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