]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - phantasia/misc.c
Rework to use curses.h only on the target, not on the host.
[bsdgames-darwin.git] / phantasia / misc.c
1 /* $NetBSD: misc.c,v 1.11 2004/04/07 17:46:47 ross Exp $ */
2
3 /*
4 * misc.c Phantasia miscellaneous support routines
5 */
6
7 #include "include.h"
8 #include <curses.h>
9
10
11 void
12 movelevel()
13 {
14 const struct charstats *statptr; /* for pointing into Stattable */
15 double new; /* new level */
16 double inc; /* increment between new and old levels */
17
18 Changed = TRUE;
19
20 if (Player.p_type == C_EXPER)
21 /* roll a type to use for increment */
22 statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)];
23 else
24 statptr = Statptr;
25
26 new = explevel(Player.p_experience);
27 inc = new - Player.p_level;
28 Player.p_level = new;
29
30 /* add increments to statistics */
31 Player.p_strength += statptr->c_strength.increase * inc;
32 Player.p_mana += statptr->c_mana.increase * inc;
33 Player.p_brains += statptr->c_brains.increase * inc;
34 Player.p_magiclvl += statptr->c_magiclvl.increase * inc;
35 Player.p_maxenergy += statptr->c_energy.increase * inc;
36
37 /* rest to maximum upon reaching new level */
38 Player.p_energy = Player.p_maxenergy + Player.p_shield;
39
40 if (Player.p_crowns > 0 && Player.p_level >= 1000.0)
41 /* no longer able to be king -- turn crowns into cash */
42 {
43 Player.p_gold += ((double) Player.p_crowns) * 5000.0;
44 Player.p_crowns = 0;
45 }
46 if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL)
47 /* make a member of the council */
48 {
49 mvaddstr(6, 0, "You have made it to the Council of the Wise.\n");
50 addstr("Good Luck on your search for the Holy Grail.\n");
51
52 Player.p_specialtype = SC_COUNCIL;
53
54 /* no rings for council and above */
55 Player.p_ring.ring_type = R_NONE;
56 Player.p_ring.ring_duration = 0;
57
58 Player.p_lives = 3; /* three extra lives */
59 }
60 if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR)
61 death("Old age");
62 }
63
64 const char *
65 descrlocation(playerp, shortflag)
66 struct player *playerp;
67 bool shortflag;
68 {
69 double circle; /* corresponding circle for coordinates */
70 int quadrant; /* quandrant of grid */
71 const char *label; /* pointer to place name */
72 static const char *const nametable[4][4] = /* names of places */
73 {
74 {"Anorien", "Ithilien", "Rohan", "Lorien"},
75 {"Gondor", "Mordor", "Dunland", "Rovanion"},
76 {"South Gondor", "Khand", "Eriador", "The Iron Hills"},
77 {"Far Harad", "Near Harad", "The Northern Waste", "Rhun"}
78 };
79
80 if (playerp->p_specialtype == SC_VALAR)
81 return (" is in Valhala");
82 else
83 if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) {
84 if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND)
85 label = "The Point of No Return";
86 else
87 label = "The Ashen Mountains";
88 } else
89 if (circle >= 55)
90 label = "Morannon";
91 else
92 if (circle >= 35)
93 label = "Kennaquahair";
94 else
95 if (circle >= 20)
96 label = "The Dead Marshes";
97 else
98 if (circle >= 9)
99 label = "The Outer Waste";
100 else
101 if (circle >= 5)
102 label = "The Moors Adventurous";
103 else {
104 if (playerp->p_x == 0.0 && playerp->p_y == 0.0)
105 label = "The Lord's Chamber";
106 else {
107 /* this
108 *
109 * expr
110 * essi
111 * on
112 * is
113 * spli
114 * t
115 * to
116 * prev
117 * ent
118 * comp
119 * iler
120 *
121 * loop
122 *
123 * with
124 *
125 * some
126 *
127 * comp
128 * iler
129 * s */
130 quadrant = ((playerp->p_x > 0.0) ? 1 : 0);
131 quadrant += ((playerp->p_y >= 0.0) ? 2 : 0);
132 label = nametable[((int) circle) - 1][quadrant];
133 }
134 }
135
136 if (shortflag)
137 sprintf(Databuf, "%.29s", label);
138 else
139 sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y);
140
141 return (Databuf);
142 }
143
144 void
145 tradingpost()
146 {
147 double numitems; /* number of items to purchase */
148 double cost; /* cost of purchase */
149 double blessingcost; /* cost of blessing */
150 int ch; /* input */
151 int size; /* size of the trading post */
152 int loop; /* loop counter */
153 int cheat = 0; /* number of times player has tried to cheat */
154 bool dishonest = FALSE; /* set when merchant is dishonest */
155
156 Player.p_status = S_TRADING;
157 writerecord(&Player, Fileloc);
158
159 clear();
160 addstr("You are at a trading post. All purchases must be made with gold.");
161
162 size = sqrt(fabs(Player.p_x / 100)) + 1;
163 size = MIN(7, size);
164
165 /* set up cost of blessing */
166 blessingcost = 1000.0 * (Player.p_level + 5.0);
167
168 /* print Menu */
169 move(7, 0);
170 for (loop = 0; loop < size; ++loop)
171 /* print Menu */
172 {
173 if (loop == 6)
174 cost = blessingcost;
175 else
176 cost = Menu[loop].cost;
177 printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost);
178 }
179
180 mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? ");
181
182 for (;;) {
183 adjuststats(); /* truncate any bad values */
184
185 /* print some important statistics */
186 mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n",
187 Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms);
188 printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n",
189 Player.p_shield, Player.p_sword, Player.p_quksilver,
190 (Player.p_blessing ? " True" : "False"));
191 printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana);
192
193 move(5, 36);
194 ch = getanswer("LPS", FALSE);
195 move(15, 0);
196 clrtobot();
197 switch (ch) {
198 case 'L': /* leave */
199 case '\n':
200 altercoordinates(0.0, 0.0, A_NEAR);
201 return;
202
203 case 'P': /* make purchase */
204 mvaddstr(15, 0, "What what would you like to buy ? ");
205 ch = getanswer(" 1234567", FALSE);
206 move(15, 0);
207 clrtoeol();
208
209 if (ch - '0' > size)
210 addstr("Sorry, this merchant doesn't have that.");
211 else
212 switch (ch) {
213 case '1':
214 printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ",
215 Menu[0].cost, floor(Player.p_gold / Menu[0].cost));
216 cost = (numitems = floor(infloat())) * Menu[0].cost;
217
218 if (cost > Player.p_gold || numitems < 0)
219 ++cheat;
220 else {
221 cheat = 0;
222 Player.p_gold -= cost;
223 if (drandom() < 0.02)
224 dishonest = TRUE;
225 else
226 Player.p_mana += numitems;
227 }
228 break;
229
230 case '2':
231 printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ",
232 Menu[1].cost, floor(Player.p_gold / Menu[1].cost));
233 cost = (numitems = floor(infloat())) * Menu[1].cost;
234
235 if (numitems == 0.0)
236 break;
237 else
238 if (cost > Player.p_gold || numitems < 0)
239 ++cheat;
240 else
241 if (numitems < Player.p_shield)
242 NOBETTER();
243 else {
244 cheat = 0;
245 Player.p_gold -= cost;
246 if (drandom() < 0.02)
247 dishonest = TRUE;
248 else
249 Player.p_shield = numitems;
250 }
251 break;
252
253 case '3':
254 printw("A book costs %.0f gp. How many do you want (%.0f max) ? ",
255 Menu[2].cost, floor(Player.p_gold / Menu[2].cost));
256 cost = (numitems = floor(infloat())) * Menu[2].cost;
257
258 if (cost > Player.p_gold || numitems < 0)
259 ++cheat;
260 else {
261 cheat = 0;
262 Player.p_gold -= cost;
263 if (drandom() < 0.02)
264 dishonest = TRUE;
265 else
266 if (drandom() * numitems > Player.p_level / 10.0
267 && numitems != 1) {
268 printw("\nYou blew your mind!\n");
269 Player.p_brains /= 5;
270 } else {
271 Player.p_brains += floor(numitems) * ROLL(20, 8);
272 }
273 }
274 break;
275
276 case '4':
277 printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ",
278 Menu[3].cost, floor(Player.p_gold / Menu[3].cost));
279 cost = (numitems = floor(infloat())) * Menu[3].cost;
280
281 if (numitems == 0.0)
282 break;
283 else
284 if (cost > Player.p_gold || numitems < 0)
285 ++cheat;
286 else
287 if (numitems < Player.p_sword)
288 NOBETTER();
289 else {
290 cheat = 0;
291 Player.p_gold -= cost;
292 if (drandom() < 0.02)
293 dishonest = TRUE;
294 else
295 Player.p_sword = numitems;
296 }
297 break;
298
299 case '5':
300 printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ",
301 Menu[4].cost, floor(Player.p_gold / Menu[4].cost));
302 cost = (numitems = floor(infloat())) * Menu[4].cost;
303
304 if (cost > Player.p_gold || numitems < 0)
305 ++cheat;
306 else {
307 cheat = 0;
308 Player.p_gold -= cost;
309 if (drandom() < 0.02)
310 dishonest = TRUE;
311 else
312 Player.p_charms += numitems;
313 }
314 break;
315
316 case '6':
317 printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ",
318 Menu[5].cost, floor(Player.p_gold / Menu[5].cost));
319 cost = (numitems = floor(infloat())) * Menu[5].cost;
320
321 if (numitems == 0.0)
322 break;
323 else
324 if (cost > Player.p_gold || numitems < 0)
325 ++cheat;
326 else
327 if (numitems < Player.p_quksilver)
328 NOBETTER();
329 else {
330 cheat = 0;
331 Player.p_gold -= cost;
332 if (drandom() < 0.02)
333 dishonest = TRUE;
334 else
335 Player.p_quksilver = numitems;
336 }
337 break;
338
339 case '7':
340 if (Player.p_blessing) {
341 addstr("You already have a blessing.");
342 break;
343 }
344 printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost);
345 ch = getanswer("NY", FALSE);
346
347 if (ch == 'Y') {
348 if (Player.p_gold < blessingcost)
349 ++cheat;
350 else {
351 cheat = 0;
352 Player.p_gold -= blessingcost;
353 if (drandom() < 0.02)
354 dishonest = TRUE;
355 else
356 Player.p_blessing = TRUE;
357 }
358 }
359 break;
360 }
361 break;
362
363 case 'S': /* sell gems */
364 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ",
365 (double) N_GEMVALUE, Player.p_gems);
366 numitems = floor(infloat());
367
368 if (numitems > Player.p_gems || numitems < 0)
369 ++cheat;
370 else {
371 cheat = 0;
372 Player.p_gems -= numitems;
373 Player.p_gold += numitems * N_GEMVALUE;
374 }
375 }
376
377 if (cheat == 1)
378 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n");
379 else
380 if (cheat == 2) {
381 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n");
382 printw("a %.0f level magic user, and you made %s mad!\n",
383 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her");
384 altercoordinates(0.0, 0.0, A_FAR);
385 Player.p_energy /= 2.0;
386 ++Player.p_sin;
387 more(23);
388 return;
389 } else
390 if (dishonest) {
391 mvaddstr(17, 0, "The merchant stole your money!");
392 refresh();
393 altercoordinates(Player.p_x - Player.p_x / 10.0,
394 Player.p_y - Player.p_y / 10.0, A_SPECIFIC);
395 sleep(2);
396 return;
397 }
398 }
399 }
400
401 void
402 displaystats()
403 {
404 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE));
405 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n",
406 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield,
407 Player.p_mana, Users);
408 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n",
409 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might,
410 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player));
411 }
412
413 void
414 allstatslist()
415 {
416 static const char *const flags[] = /* to print value of some bools */
417 {
418 "False",
419 " True"
420 };
421
422 mvprintw(8, 0, "Type: %s\n", descrtype(&Player, FALSE));
423
424 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience);
425 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains);
426 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl);
427 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin);
428 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison);
429 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems);
430 mvprintw(16, 0, "Age : %9ld", Player.p_age);
431 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater);
432 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets);
433 mvprintw(12, 40, "Charms : %9d", Player.p_charms);
434 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns);
435 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield);
436 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword);
437 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver);
438
439 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s",
440 flags[(int)Player.p_blessing],
441 flags[Player.p_ring.ring_type != R_NONE],
442 flags[(int)Player.p_virgin],
443 flags[(int)Player.p_palantir]);
444 }
445
446 const char *
447 descrtype(playerp, shortflag)
448 struct player *playerp;
449 bool shortflag;
450 {
451 int type; /* for caluculating result subscript */
452 static const char *const results[] =/* description table */
453 {
454 " Magic User", " MU",
455 " Fighter", " F ",
456 " Elf", " E ",
457 " Dwarf", " D ",
458 " Halfling", " H ",
459 " Experimento", " EX",
460 " Super", " S ",
461 " King", " K ",
462 " Council of Wise", " CW",
463 " Ex-Valar", " EV",
464 " Valar", " V ",
465 " ? ", " ? "
466 };
467
468 type = playerp->p_type;
469
470 switch (playerp->p_specialtype) {
471 case SC_NONE:
472 type = playerp->p_type;
473 break;
474
475 case SC_KING:
476 type = 7;
477 break;
478
479 case SC_COUNCIL:
480 type = 8;
481 break;
482
483 case SC_EXVALAR:
484 type = 9;
485 break;
486
487 case SC_VALAR:
488 type = 10;
489 break;
490 }
491
492 type *= 2; /* calculate offset */
493
494 if (type > 20)
495 /* error */
496 type = 22;
497
498 if (shortflag)
499 /* use short descriptions */
500 ++type;
501
502 if (playerp->p_crowns > 0) {
503 strcpy(Databuf, results[type]);
504 Databuf[0] = '*';
505 return (Databuf);
506 } else
507 return (results[type]);
508 }
509
510 long
511 findname(name, playerp)
512 const char *name;
513 struct player *playerp;
514 {
515 long loc = 0; /* location in the file */
516
517 fseek(Playersfp, 0L, SEEK_SET);
518 while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
519 if (strcmp(playerp->p_name, name) == 0) {
520 if (playerp->p_status != S_NOTUSED || Wizard)
521 /* found it */
522 return (loc);
523 }
524 loc += SZ_PLAYERSTRUCT;
525 }
526
527 return (-1);
528 }
529
530 long
531 allocrecord()
532 {
533 long loc = 0L; /* location in file */
534
535 fseek(Playersfp, 0L, SEEK_SET);
536 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
537 if (Other.p_status == S_NOTUSED)
538 /* found an empty record */
539 return (loc);
540 else
541 loc += SZ_PLAYERSTRUCT;
542 }
543
544 /* make a new record */
545 initplayer(&Other);
546 Player.p_status = S_OFF;
547 writerecord(&Other, loc);
548
549 return (loc);
550 }
551
552 void
553 freerecord(playerp, loc)
554 struct player *playerp;
555 long loc;
556 {
557 playerp->p_name[0] = CH_MARKDELETE;
558 playerp->p_status = S_NOTUSED;
559 writerecord(playerp, loc);
560 }
561
562 void
563 leavegame()
564 {
565
566 if (Player.p_level < 1.0)
567 /* delete character */
568 freerecord(&Player, Fileloc);
569 else {
570 Player.p_status = S_OFF;
571 writerecord(&Player, Fileloc);
572 }
573
574 cleanup(TRUE);
575 /* NOTREACHED */
576 }
577
578 void
579 death(how)
580 const char *how;
581 {
582 FILE *fp; /* for updating various files */
583 int ch; /* input */
584 static const char *const deathmesg[] =
585 /* add more messages here, if desired */
586 {
587 "You have been wounded beyond repair. ",
588 "You have been disemboweled. ",
589 "You've been mashed, mauled, and spit upon. (You're dead.)\n",
590 "You died! ",
591 "You're a complete failure -- you've died!!\n",
592 "You have been dealt a fatal blow! "
593 };
594
595 clear();
596
597 if (strcmp(how, "Stupidity") != 0) {
598 if (Player.p_level > 9999.0)
599 /* old age */
600 addstr("Characters must be retired upon reaching level 10000. Sorry.");
601 else
602 if (Player.p_lives > 0)
603 /* extra lives */
604 {
605 addstr("You should be more cautious. You've been killed.\n");
606 printw("You only have %d more chance(s).\n", --Player.p_lives);
607 more(3);
608 Player.p_energy = Player.p_maxenergy;
609 return;
610 } else
611 if (Player.p_specialtype == SC_VALAR) {
612 addstr("You had your chances, but Valar aren't totally\n");
613 addstr("immortal. You are now left to wither and die . . .\n");
614 more(3);
615 Player.p_brains = Player.p_level / 25.0;
616 Player.p_energy = Player.p_maxenergy /= 5.0;
617 Player.p_quksilver = Player.p_sword = 0.0;
618 Player.p_specialtype = SC_COUNCIL;
619 return;
620 } else
621 if (Player.p_ring.ring_inuse &&
622 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG))
623 /* good ring in use - saved
624 * from death */
625 {
626 mvaddstr(4, 0, "Your ring saved you from death!\n");
627 refresh();
628 Player.p_ring.ring_type = R_NONE;
629 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0;
630 if (Player.p_crowns > 0)
631 --Player.p_crowns;
632 return;
633 } else
634 if (Player.p_ring.ring_type == R_BAD
635 || Player.p_ring.ring_type == R_SPOILED)
636 /* bad ring in
637 * possession; name
638 * idiot after player */
639 {
640 mvaddstr(4, 0,
641 "Your ring has taken control of you and turned you into a monster!\n");
642 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
643 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
644 strcpy(Curmonster.m_name, Player.p_name);
645 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
646 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
647 fflush(Monstfp);
648 }
649 }
650 enterscore(); /* update score board */
651
652 /* put info in last dead file */
653 fp = fopen(_PATH_LASTDEAD, "w");
654 fprintf(fp, "%s (%s, run by %s, level %.0f, killed by %s)",
655 Player.p_name, descrtype(&Player, TRUE),
656 Player.p_login, Player.p_level, how);
657 fclose(fp);
658
659 /* let other players know */
660 fp = fopen(_PATH_MESS, "w");
661 fprintf(fp, "%s was killed by %s.", Player.p_name, how);
662 fclose(fp);
663
664 freerecord(&Player, Fileloc);
665
666 clear();
667 move(10, 0);
668 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]);
669 addstr("Care to give it another try ? ");
670 ch = getanswer("NY", FALSE);
671
672 if (ch == 'Y') {
673 cleanup(FALSE);
674 execl(_PATH_GAMEPROG, "phantasia", "-s",
675 (Wizard ? "-S" : (char *) NULL), 0);
676 exit(0);
677 /* NOTREACHED */
678 }
679 cleanup(TRUE);
680 /* NOTREACHED */
681 }
682
683 void
684 writerecord(playerp, place)
685 struct player *playerp;
686 long place;
687 {
688 fseek(Playersfp, place, SEEK_SET);
689 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
690 fflush(Playersfp);
691 }
692
693 double
694 explevel(experience)
695 double experience;
696 {
697 if (experience < 1.1e7)
698 return (floor(pow((experience / 1000.0), 0.4875)));
699 else
700 return (floor(pow((experience / 1250.0), 0.4865)));
701 }
702
703 void
704 truncstring(string)
705 char *string;
706 {
707 int length; /* length of string */
708
709 length = strlen(string);
710 while (string[--length] == ' ')
711 string[length] = '\0';
712 }
713
714 void
715 altercoordinates(xnew, ynew, operation)
716 double xnew;
717 double ynew;
718 int operation;
719 {
720 switch (operation) {
721 case A_FORCED: /* move with no checks */
722 break;
723
724 case A_NEAR: /* pick random coordinates near */
725 xnew = Player.p_x + ROLL(1.0, 5.0);
726 ynew = Player.p_y - ROLL(1.0, 5.0);
727 /* fall through for check */
728
729 case A_SPECIFIC: /* just move player */
730 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND)
731 /*
732 * cannot move back from point of no return
733 * pick the largest coordinate to remain unchanged
734 */
735 {
736 if (fabs(xnew) > fabs(ynew))
737 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND);
738 else
739 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND);
740 }
741 break;
742
743 case A_FAR: /* pick random coordinates far */
744 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle);
745 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle);
746 break;
747 }
748
749 /* now set location flags and adjust coordinates */
750 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew));
751
752 /* set up flags based upon location */
753 Throne = Marsh = Beyond = FALSE;
754
755 if (Player.p_x == 0.0 && Player.p_y == 0.0)
756 Throne = TRUE;
757 else
758 if (Circle < 35 && Circle >= 20)
759 Marsh = TRUE;
760 else
761 if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND)
762 Beyond = TRUE;
763
764 Changed = TRUE;
765 }
766
767 void
768 readrecord(playerp, loc)
769 struct player *playerp;
770 long loc;
771 {
772 fseek(Playersfp, loc, SEEK_SET);
773 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
774 }
775
776 void
777 adjuststats()
778 {
779 double dtemp; /* for temporary calculations */
780
781 if (explevel(Player.p_experience) > Player.p_level)
782 /* move one or more levels */
783 {
784 movelevel();
785 if (Player.p_level > 5.0)
786 Timeout = TRUE;
787 }
788 if (Player.p_specialtype == SC_VALAR)
789 /* valar */
790 Circle = Player.p_level / 5.0;
791
792 /* calculate effective quickness */
793 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote
794 - Player.p_level;
795 dtemp = MAX(0.0, dtemp);/* gold slows player down */
796 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp;
797
798 /* calculate effective strength */
799 if (Player.p_poison > 0.0)
800 /* poison makes player weaker */
801 {
802 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0;
803 dtemp = MAX(0.1, dtemp);
804 } else
805 dtemp = 1.0;
806 Player.p_might = dtemp * Player.p_strength + Player.p_sword;
807
808 /* insure that important things are within limits */
809 Player.p_quksilver = MIN(99.0, Player.p_quksilver);
810 Player.p_mana = MIN(Player.p_mana,
811 Player.p_level * Statptr->c_maxmana + 1000.0);
812 Player.p_brains = MIN(Player.p_brains,
813 Player.p_level * Statptr->c_maxbrains + 200.0);
814 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0);
815
816 /*
817 * some implementations have problems with floating point compare
818 * we work around it with this stuff
819 */
820 Player.p_gold = floor(Player.p_gold) + 0.1;
821 Player.p_gems = floor(Player.p_gems) + 0.1;
822 Player.p_mana = floor(Player.p_mana) + 0.1;
823
824 if (Player.p_ring.ring_type != R_NONE)
825 /* do ring things */
826 {
827 /* rest to max */
828 Player.p_energy = Player.p_maxenergy + Player.p_shield;
829
830 if (Player.p_ring.ring_duration <= 0)
831 /* clean up expired rings */
832 switch (Player.p_ring.ring_type) {
833 case R_BAD: /* ring drives player crazy */
834 Player.p_ring.ring_type = R_SPOILED;
835 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0);
836 break;
837
838 case R_NAZREG: /* ring disappears */
839 Player.p_ring.ring_type = R_NONE;
840 break;
841
842 case R_SPOILED: /* ring kills player */
843 death("A cursed ring");
844 break;
845
846 case R_DLREG: /* this ring doesn't expire */
847 Player.p_ring.ring_duration = 0;
848 break;
849 }
850 }
851 if (Player.p_age / N_AGE > Player.p_degenerated)
852 /* age player slightly */
853 {
854 ++Player.p_degenerated;
855 if (Player.p_quickness > 23.0)
856 Player.p_quickness *= 0.99;
857 Player.p_strength *= 0.97;
858 Player.p_brains *= 0.95;
859 Player.p_magiclvl *= 0.97;
860 Player.p_maxenergy *= 0.95;
861 Player.p_quksilver *= 0.95;
862 Player.p_sword *= 0.93;
863 Player.p_shield *= 0.93;
864 }
865 }
866
867 void
868 initplayer(playerp)
869 struct player *playerp;
870 {
871 playerp->p_experience =
872 playerp->p_level =
873 playerp->p_strength =
874 playerp->p_sword =
875 playerp->p_might =
876 playerp->p_energy =
877 playerp->p_maxenergy =
878 playerp->p_shield =
879 playerp->p_quickness =
880 playerp->p_quksilver =
881 playerp->p_speed =
882 playerp->p_magiclvl =
883 playerp->p_mana =
884 playerp->p_brains =
885 playerp->p_poison =
886 playerp->p_gems =
887 playerp->p_sin =
888 playerp->p_1scratch =
889 playerp->p_2scratch = 0.0;
890
891 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */
892
893 playerp->p_x = ROLL(-125.0, 251.0);
894 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */
895
896 /* clear ring */
897 playerp->p_ring.ring_type = R_NONE;
898 playerp->p_ring.ring_duration = 0;
899 playerp->p_ring.ring_inuse = FALSE;
900
901 playerp->p_age = 0L;
902
903 playerp->p_degenerated = 1; /* don't degenerate initially */
904
905 playerp->p_type = C_FIGHTER; /* default */
906 playerp->p_specialtype = SC_NONE;
907 playerp->p_lives =
908 playerp->p_crowns =
909 playerp->p_charms =
910 playerp->p_amulets =
911 playerp->p_holywater =
912 playerp->p_lastused = 0;
913 playerp->p_status = S_NOTUSED;
914 playerp->p_tampered = T_OFF;
915 playerp->p_istat = I_OFF;
916
917 playerp->p_palantir =
918 playerp->p_blessing =
919 playerp->p_virgin =
920 playerp->p_blindness = FALSE;
921
922 playerp->p_name[0] =
923 playerp->p_password[0] =
924 playerp->p_login[0] = '\0';
925 }
926
927 void
928 readmessage()
929 {
930 move(3, 0);
931 clrtoeol();
932 fseek(Messagefp, 0L, SEEK_SET);
933 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL)
934 addstr(Databuf);
935 }
936
937 void
938 error(whichfile)
939 const char *whichfile;
940 {
941 int (*funcp)(const char *,...);
942
943 if (Windows) {
944 funcp = printw;
945 clear();
946 } else
947 funcp = printf;
948
949 (*funcp) ("An unrecoverable error has occurred reading %s. (%s)\n", whichfile, strerror(errno));
950 (*funcp) ("Please run 'setup' to determine the problem.\n");
951 cleanup(TRUE);
952 /* NOTREACHED */
953 }
954
955 double
956 distance(x1, x2, y1, y2)
957 double x1, x2, y1, y2;
958 {
959 double deltax, deltay;
960
961 deltax = x1 - x2;
962 deltay = y1 - y2;
963 return (sqrt(deltax * deltax + deltay * deltay));
964 }
965
966 void
967 ill_sig(whichsig)
968 int whichsig;
969 {
970 clear();
971 if (!(whichsig == SIGINT || whichsig == SIGQUIT))
972 printw("Error: caught signal # %d.\n", whichsig);
973 cleanup(TRUE);
974 /* NOTREACHED */
975 }
976
977 const char *
978 descrstatus(playerp)
979 struct player *playerp;
980 {
981 switch (playerp->p_status) {
982 case S_PLAYING:
983 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield))
984 return ("Low Energy");
985 else
986 if (playerp->p_blindness)
987 return ("Blind");
988 else
989 return ("In game");
990
991 case S_CLOAKED:
992 return ("Cloaked");
993
994 case S_INBATTLE:
995 return ("In Battle");
996
997 case S_MONSTER:
998 return ("Encounter");
999
1000 case S_TRADING:
1001 return ("Trading");
1002
1003 case S_OFF:
1004 return ("Off");
1005
1006 case S_HUNGUP:
1007 return ("Hung up");
1008
1009 default:
1010 return ("");
1011 }
1012 }
1013
1014 double
1015 drandom()
1016 {
1017 if (sizeof(int) != 2)
1018 /* use only low bits */
1019 return ((double) (random() & 0x7fff) / 32768.0);
1020 else
1021 return ((double) random() / 32768.0);
1022 }
1023
1024 void
1025 collecttaxes(gold, gems)
1026 double gold;
1027 double gems;
1028 {
1029 FILE *fp; /* to update Goldfile */
1030 double dtemp; /* for temporary calculations */
1031 double taxes; /* tax liability */
1032
1033 /* add to cache */
1034 Player.p_gold += gold;
1035 Player.p_gems += gems;
1036
1037 /* calculate tax liability */
1038 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold);
1039
1040 if (Player.p_gold < taxes)
1041 /* not enough gold to pay taxes, must convert some gems to
1042 * gold */
1043 {
1044 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to
1045 * convert */
1046
1047 if (Player.p_gems >= dtemp)
1048 /* player has enough to convert */
1049 {
1050 Player.p_gems -= dtemp;
1051 Player.p_gold += dtemp * N_GEMVALUE;
1052 } else
1053 /* take everything; this should never happen */
1054 {
1055 Player.p_gold += Player.p_gems * N_GEMVALUE;
1056 Player.p_gems = 0.0;
1057 taxes = Player.p_gold;
1058 }
1059 }
1060 Player.p_gold -= taxes;
1061
1062 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
1063 /* update taxes */
1064 {
1065 dtemp = 0.0;
1066 fread((char *) &dtemp, sizeof(double), 1, fp);
1067 dtemp += floor(taxes);
1068 fseek(fp, 0L, SEEK_SET);
1069 fwrite((char *) &dtemp, sizeof(double), 1, fp);
1070 fclose(fp);
1071 }
1072 }