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