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