Expand PMF_FN_* macros.
[netbsd-mini2440.git] / games / phantasia / misc.c
blob049e73b395fd23a788f167720c3a8124b6a0ddc7
1 /* $NetBSD: misc.c,v 1.18 2009/08/12 08:21:41 dholland Exp $ */
3 /*
4 * misc.c Phantasia miscellaneous support routines
5 */
7 #include <errno.h>
8 #include <math.h>
9 #include <setjmp.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
16 #include "macros.h"
17 #include "phantdefs.h"
18 #include "phantstruct.h"
19 #include "phantglobs.h"
20 #include "pathnames.h"
22 #undef bool
23 #include <curses.h>
26 static double explevel(double);
28 static void
29 movelevel(void)
31 const struct charstats *statptr; /* for pointing into Stattable */
32 double new; /* new level */
33 double inc; /* increment between new and old levels */
35 Changed = TRUE;
37 if (Player.p_type == C_EXPER)
38 /* roll a type to use for increment */
39 statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)];
40 else
41 statptr = Statptr;
43 new = explevel(Player.p_experience);
44 inc = new - Player.p_level;
45 Player.p_level = new;
47 /* add increments to statistics */
48 Player.p_strength += statptr->c_strength.increase * inc;
49 Player.p_mana += statptr->c_mana.increase * inc;
50 Player.p_brains += statptr->c_brains.increase * inc;
51 Player.p_magiclvl += statptr->c_magiclvl.increase * inc;
52 Player.p_maxenergy += statptr->c_energy.increase * inc;
54 /* rest to maximum upon reaching new level */
55 Player.p_energy = Player.p_maxenergy + Player.p_shield;
57 if (Player.p_crowns > 0 && Player.p_level >= 1000.0)
58 /* no longer able to be king -- turn crowns into cash */
60 Player.p_gold += ((double) Player.p_crowns) * 5000.0;
61 Player.p_crowns = 0;
63 if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL)
64 /* make a member of the council */
66 mvaddstr(6, 0, "You have made it to the Council of the Wise.\n");
67 addstr("Good Luck on your search for the Holy Grail.\n");
69 Player.p_specialtype = SC_COUNCIL;
71 /* no rings for council and above */
72 Player.p_ring.ring_type = R_NONE;
73 Player.p_ring.ring_duration = 0;
75 Player.p_lives = 3; /* three extra lives */
77 if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR)
78 death("Old age");
81 const char *
82 descrlocation(struct player *playerp, phbool shortflag)
84 double circle; /* corresponding circle for coordinates */
85 int quadrant; /* quandrant of grid */
86 const char *label; /* pointer to place name */
87 static const char *const nametable[4][4] = /* names of places */
89 {"Anorien", "Ithilien", "Rohan", "Lorien"},
90 {"Gondor", "Mordor", "Dunland", "Rovanion"},
91 {"South Gondor", "Khand", "Eriador", "The Iron Hills"},
92 {"Far Harad", "Near Harad", "The Northern Waste", "Rhun"}
95 if (playerp->p_specialtype == SC_VALAR)
96 return (" is in Valhala");
97 else
98 if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0) {
99 if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND)
100 label = "The Point of No Return";
101 else
102 label = "The Ashen Mountains";
103 } else
104 if (circle >= 55)
105 label = "Morannon";
106 else
107 if (circle >= 35)
108 label = "Kennaquahair";
109 else
110 if (circle >= 20)
111 label = "The Dead Marshes";
112 else
113 if (circle >= 9)
114 label = "The Outer Waste";
115 else
116 if (circle >= 5)
117 label = "The Moors Adventurous";
118 else {
119 if (playerp->p_x == 0.0 && playerp->p_y == 0.0)
120 label = "The Lord's Chamber";
121 else {
122 /* this
124 * expr
125 * essi
126 * on
127 * is
128 * spli
130 * to
131 * prev
132 * ent
133 * comp
134 * iler
136 * loop
138 * with
140 * some
142 * comp
143 * iler
144 * s */
145 quadrant = ((playerp->p_x > 0.0) ? 1 : 0);
146 quadrant += ((playerp->p_y >= 0.0) ? 2 : 0);
147 label = nametable[((int) circle) - 1][quadrant];
151 if (shortflag)
152 snprintf(Databuf, SZ_DATABUF, "%.29s", label);
153 else
154 snprintf(Databuf, SZ_DATABUF,
155 " is in %s (%.0f,%.0f)",
156 label, playerp->p_x, playerp->p_y);
158 return (Databuf);
161 void
162 tradingpost(void)
164 double numitems; /* number of items to purchase */
165 double cost; /* cost of purchase */
166 double blessingcost; /* cost of blessing */
167 int ch; /* input */
168 int size; /* size of the trading post */
169 int loop; /* loop counter */
170 int cheat = 0; /* number of times player has tried to cheat */
171 bool dishonest = FALSE; /* set when merchant is dishonest */
173 Player.p_status = S_TRADING;
174 writerecord(&Player, Fileloc);
176 clear();
177 addstr("You are at a trading post. All purchases must be made with gold.");
179 size = sqrt(fabs(Player.p_x / 100)) + 1;
180 size = MIN(7, size);
182 /* set up cost of blessing */
183 blessingcost = 1000.0 * (Player.p_level + 5.0);
185 /* print Menu */
186 move(7, 0);
187 for (loop = 0; loop < size; ++loop)
188 /* print Menu */
190 if (loop == 6)
191 cost = blessingcost;
192 else
193 cost = Menu[loop].cost;
194 printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost);
197 mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? ");
199 for (;;) {
200 adjuststats(); /* truncate any bad values */
202 /* print some important statistics */
203 mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n",
204 Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms);
205 printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n",
206 Player.p_shield, Player.p_sword, Player.p_quksilver,
207 (Player.p_blessing ? " True" : "False"));
208 printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana);
210 move(5, 36);
211 ch = getanswer("LPS", FALSE);
212 move(15, 0);
213 clrtobot();
214 switch (ch) {
215 case 'L': /* leave */
216 case '\n':
217 altercoordinates(0.0, 0.0, A_NEAR);
218 return;
220 case 'P': /* make purchase */
221 mvaddstr(15, 0, "What what would you like to buy ? ");
222 ch = getanswer(" 1234567", FALSE);
223 move(15, 0);
224 clrtoeol();
226 if (ch - '0' > size)
227 addstr("Sorry, this merchant doesn't have that.");
228 else
229 switch (ch) {
230 case '1':
231 printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ",
232 Menu[0].cost, floor(Player.p_gold / Menu[0].cost));
233 cost = (numitems = floor(infloat())) * Menu[0].cost;
235 if (cost > Player.p_gold || numitems < 0)
236 ++cheat;
237 else {
238 cheat = 0;
239 Player.p_gold -= cost;
240 if (drandom() < 0.02)
241 dishonest = TRUE;
242 else
243 Player.p_mana += numitems;
245 break;
247 case '2':
248 printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ",
249 Menu[1].cost, floor(Player.p_gold / Menu[1].cost));
250 cost = (numitems = floor(infloat())) * Menu[1].cost;
252 if (numitems == 0.0)
253 break;
254 else
255 if (cost > Player.p_gold || numitems < 0)
256 ++cheat;
257 else
258 if (numitems < Player.p_shield)
259 NOBETTER();
260 else {
261 cheat = 0;
262 Player.p_gold -= cost;
263 if (drandom() < 0.02)
264 dishonest = TRUE;
265 else
266 Player.p_shield = numitems;
268 break;
270 case '3':
271 printw("A book costs %.0f gp. How many do you want (%.0f max) ? ",
272 Menu[2].cost, floor(Player.p_gold / Menu[2].cost));
273 cost = (numitems = floor(infloat())) * Menu[2].cost;
275 if (cost > Player.p_gold || numitems < 0)
276 ++cheat;
277 else {
278 cheat = 0;
279 Player.p_gold -= cost;
280 if (drandom() < 0.02)
281 dishonest = TRUE;
282 else
283 if (drandom() * numitems > Player.p_level / 10.0
284 && numitems != 1) {
285 printw("\nYou blew your mind!\n");
286 Player.p_brains /= 5;
287 } else {
288 Player.p_brains += floor(numitems) * ROLL(20, 8);
291 break;
293 case '4':
294 printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ",
295 Menu[3].cost, floor(Player.p_gold / Menu[3].cost));
296 cost = (numitems = floor(infloat())) * Menu[3].cost;
298 if (numitems == 0.0)
299 break;
300 else
301 if (cost > Player.p_gold || numitems < 0)
302 ++cheat;
303 else
304 if (numitems < Player.p_sword)
305 NOBETTER();
306 else {
307 cheat = 0;
308 Player.p_gold -= cost;
309 if (drandom() < 0.02)
310 dishonest = TRUE;
311 else
312 Player.p_sword = numitems;
314 break;
316 case '5':
317 printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ",
318 Menu[4].cost, floor(Player.p_gold / Menu[4].cost));
319 cost = (numitems = floor(infloat())) * Menu[4].cost;
321 if (cost > Player.p_gold || numitems < 0)
322 ++cheat;
323 else {
324 cheat = 0;
325 Player.p_gold -= cost;
326 if (drandom() < 0.02)
327 dishonest = TRUE;
328 else
329 Player.p_charms += numitems;
331 break;
333 case '6':
334 printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ",
335 Menu[5].cost, floor(Player.p_gold / Menu[5].cost));
336 cost = (numitems = floor(infloat())) * Menu[5].cost;
338 if (numitems == 0.0)
339 break;
340 else
341 if (cost > Player.p_gold || numitems < 0)
342 ++cheat;
343 else
344 if (numitems < Player.p_quksilver)
345 NOBETTER();
346 else {
347 cheat = 0;
348 Player.p_gold -= cost;
349 if (drandom() < 0.02)
350 dishonest = TRUE;
351 else
352 Player.p_quksilver = numitems;
354 break;
356 case '7':
357 if (Player.p_blessing) {
358 addstr("You already have a blessing.");
359 break;
361 printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost);
362 ch = getanswer("NY", FALSE);
364 if (ch == 'Y') {
365 if (Player.p_gold < blessingcost)
366 ++cheat;
367 else {
368 cheat = 0;
369 Player.p_gold -= blessingcost;
370 if (drandom() < 0.02)
371 dishonest = TRUE;
372 else
373 Player.p_blessing = TRUE;
376 break;
378 break;
380 case 'S': /* sell gems */
381 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ",
382 (double) N_GEMVALUE, Player.p_gems);
383 numitems = floor(infloat());
385 if (numitems > Player.p_gems || numitems < 0)
386 ++cheat;
387 else {
388 cheat = 0;
389 Player.p_gems -= numitems;
390 Player.p_gold += numitems * N_GEMVALUE;
394 if (cheat == 1)
395 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n");
396 else
397 if (cheat == 2) {
398 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n");
399 printw("a %.0f level magic user, and you made %s mad!\n",
400 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her");
401 altercoordinates(0.0, 0.0, A_FAR);
402 Player.p_energy /= 2.0;
403 ++Player.p_sin;
404 more(23);
405 return;
406 } else
407 if (dishonest) {
408 mvaddstr(17, 0, "The merchant stole your money!");
409 refresh();
410 altercoordinates(Player.p_x - Player.p_x / 10.0,
411 Player.p_y - Player.p_y / 10.0, A_SPECIFIC);
412 sleep(2);
413 return;
418 void
419 displaystats(void)
421 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE));
422 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n",
423 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield,
424 Player.p_mana, Users);
425 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n",
426 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might,
427 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player));
430 void
431 allstatslist(void)
433 static const char *const flags[] = /* to print value of some bools */
435 "False",
436 " True"
439 mvprintw(8, 0, "Type: %s\n", descrtype(&Player, FALSE));
441 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience);
442 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains);
443 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl);
444 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin);
445 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison);
446 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems);
447 mvprintw(16, 0, "Age : %9ld", Player.p_age);
448 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater);
449 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets);
450 mvprintw(12, 40, "Charms : %9d", Player.p_charms);
451 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns);
452 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield);
453 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword);
454 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver);
456 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s",
457 flags[(int)Player.p_blessing],
458 flags[Player.p_ring.ring_type != R_NONE],
459 flags[(int)Player.p_virgin],
460 flags[(int)Player.p_palantir]);
463 const char *
464 descrtype(struct player *playerp, phbool shortflag)
466 int type; /* for caluculating result subscript */
467 static const char *const results[] =/* description table */
469 " Magic User", " MU",
470 " Fighter", " F ",
471 " Elf", " E ",
472 " Dwarf", " D ",
473 " Halfling", " H ",
474 " Experimento", " EX",
475 " Super", " S ",
476 " King", " K ",
477 " Council of Wise", " CW",
478 " Ex-Valar", " EV",
479 " Valar", " V ",
480 " ? ", " ? "
483 type = playerp->p_type;
485 switch (playerp->p_specialtype) {
486 case SC_NONE:
487 type = playerp->p_type;
488 break;
490 case SC_KING:
491 type = 7;
492 break;
494 case SC_COUNCIL:
495 type = 8;
496 break;
498 case SC_EXVALAR:
499 type = 9;
500 break;
502 case SC_VALAR:
503 type = 10;
504 break;
507 type *= 2; /* calculate offset */
509 if (type > 20)
510 /* error */
511 type = 22;
513 if (shortflag)
514 /* use short descriptions */
515 ++type;
517 if (playerp->p_crowns > 0) {
518 strcpy(Databuf, results[type]);
519 Databuf[0] = '*';
520 return (Databuf);
521 } else
522 return (results[type]);
525 long
526 findname(const char *name, struct player *playerp)
528 long loc = 0; /* location in the file */
530 fseek(Playersfp, 0L, SEEK_SET);
531 while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
532 if (strcmp(playerp->p_name, name) == 0) {
533 if (playerp->p_status != S_NOTUSED || Wizard)
534 /* found it */
535 return (loc);
537 loc += SZ_PLAYERSTRUCT;
540 return (-1);
543 long
544 allocrecord(void)
546 long loc = 0L; /* location in file */
548 fseek(Playersfp, 0L, SEEK_SET);
549 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1) {
550 if (Other.p_status == S_NOTUSED)
551 /* found an empty record */
552 return (loc);
553 else
554 loc += SZ_PLAYERSTRUCT;
557 /* make a new record */
558 initplayer(&Other);
559 Player.p_status = S_OFF;
560 writerecord(&Other, loc);
562 return (loc);
565 void
566 freerecord(struct player *playerp, long loc)
568 playerp->p_name[0] = CH_MARKDELETE;
569 playerp->p_status = S_NOTUSED;
570 writerecord(playerp, loc);
573 void
574 leavegame(void)
577 if (Player.p_level < 1.0)
578 /* delete character */
579 freerecord(&Player, Fileloc);
580 else {
581 Player.p_status = S_OFF;
582 writerecord(&Player, Fileloc);
585 cleanup(TRUE);
586 /* NOTREACHED */
589 void
590 death(const char *how)
592 FILE *fp; /* for updating various files */
593 int ch; /* input */
594 static const char *const deathmesg[] =
595 /* add more messages here, if desired */
597 "You have been wounded beyond repair. ",
598 "You have been disemboweled. ",
599 "You've been mashed, mauled, and spit upon. (You're dead.)\n",
600 "You died! ",
601 "You're a complete failure -- you've died!!\n",
602 "You have been dealt a fatal blow! "
605 clear();
607 if (strcmp(how, "Stupidity") != 0) {
608 if (Player.p_level > 9999.0)
609 /* old age */
610 addstr("Characters must be retired upon reaching level 10000. Sorry.");
611 else
612 if (Player.p_lives > 0)
613 /* extra lives */
615 addstr("You should be more cautious. You've been killed.\n");
616 printw("You only have %d more chance(s).\n", --Player.p_lives);
617 more(3);
618 Player.p_energy = Player.p_maxenergy;
619 return;
620 } else
621 if (Player.p_specialtype == SC_VALAR) {
622 addstr("You had your chances, but Valar aren't totally\n");
623 addstr("immortal. You are now left to wither and die . . .\n");
624 more(3);
625 Player.p_brains = Player.p_level / 25.0;
626 Player.p_energy = Player.p_maxenergy /= 5.0;
627 Player.p_quksilver = Player.p_sword = 0.0;
628 Player.p_specialtype = SC_COUNCIL;
629 return;
630 } else
631 if (Player.p_ring.ring_inuse &&
632 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG))
633 /* good ring in use - saved
634 * from death */
636 mvaddstr(4, 0, "Your ring saved you from death!\n");
637 refresh();
638 Player.p_ring.ring_type = R_NONE;
639 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0;
640 if (Player.p_crowns > 0)
641 --Player.p_crowns;
642 return;
643 } else
644 if (Player.p_ring.ring_type == R_BAD
645 || Player.p_ring.ring_type == R_SPOILED)
646 /* bad ring in
647 * possession; name
648 * idiot after player */
650 mvaddstr(4, 0,
651 "Your ring has taken control of you and turned you into a monster!\n");
652 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
653 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
654 strcpy(Curmonster.m_name, Player.p_name);
655 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
656 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
657 fflush(Monstfp);
660 enterscore(); /* update score board */
662 /* put info in last dead file */
663 fp = fopen(_PATH_LASTDEAD, "w");
664 fprintf(fp, "%s (%s, run by %s, level %.0f, killed by %s)",
665 Player.p_name, descrtype(&Player, TRUE),
666 Player.p_login, Player.p_level, how);
667 fclose(fp);
669 /* let other players know */
670 fp = fopen(_PATH_MESS, "w");
671 fprintf(fp, "%s was killed by %s.", Player.p_name, how);
672 fclose(fp);
674 freerecord(&Player, Fileloc);
676 clear();
677 move(10, 0);
678 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]);
679 addstr("Care to give it another try ? ");
680 ch = getanswer("NY", FALSE);
682 if (ch == 'Y') {
683 cleanup(FALSE);
684 execl(_PATH_GAMEPROG, "phantasia", "-s",
685 (Wizard ? "-S" : (char *) NULL), (char *) NULL);
686 exit(0);
687 /* NOTREACHED */
689 cleanup(TRUE);
690 /* NOTREACHED */
693 void
694 writerecord(struct player *playerp, long place)
696 fseek(Playersfp, place, SEEK_SET);
697 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
698 fflush(Playersfp);
701 static double
702 explevel(double experience)
704 if (experience < 1.1e7)
705 return (floor(pow((experience / 1000.0), 0.4875)));
706 else
707 return (floor(pow((experience / 1250.0), 0.4865)));
710 void
711 truncstring(char *string)
713 int length; /* length of string */
715 length = strlen(string);
716 while (string[--length] == ' ')
717 string[length] = '\0';
720 void
721 altercoordinates(double xnew, double ynew, int operation)
723 switch (operation) {
724 case A_FORCED: /* move with no checks */
725 break;
727 case A_NEAR: /* pick random coordinates near */
728 xnew = Player.p_x + ROLL(1.0, 5.0);
729 ynew = Player.p_y - ROLL(1.0, 5.0);
730 /* fall through for check */
732 case A_SPECIFIC: /* just move player */
733 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND)
735 * cannot move back from point of no return
736 * pick the largest coordinate to remain unchanged
739 if (fabs(xnew) > fabs(ynew))
740 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND);
741 else
742 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND);
744 break;
746 case A_FAR: /* pick random coordinates far */
747 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle);
748 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle);
749 break;
752 /* now set location flags and adjust coordinates */
753 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew));
755 /* set up flags based upon location */
756 Throne = Marsh = Beyond = FALSE;
758 if (Player.p_x == 0.0 && Player.p_y == 0.0)
759 Throne = TRUE;
760 else
761 if (Circle < 35 && Circle >= 20)
762 Marsh = TRUE;
763 else
764 if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND)
765 Beyond = TRUE;
767 Changed = TRUE;
770 void
771 readrecord(struct player *playerp, long loc)
773 fseek(Playersfp, loc, SEEK_SET);
774 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
777 void
778 adjuststats(void)
780 double dtemp; /* for temporary calculations */
782 if (explevel(Player.p_experience) > Player.p_level)
783 /* move one or more levels */
785 movelevel();
786 if (Player.p_level > 5.0)
787 Timeout = TRUE;
789 if (Player.p_specialtype == SC_VALAR)
790 /* valar */
791 Circle = Player.p_level / 5.0;
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;
799 /* calculate effective strength */
800 if (Player.p_poison > 0.0)
801 /* poison makes player weaker */
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;
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);
818 * some implementations have problems with floating point compare
819 * we work around it with this stuff
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;
825 if (Player.p_ring.ring_type != R_NONE)
826 /* do ring things */
828 /* rest to max */
829 Player.p_energy = Player.p_maxenergy + Player.p_shield;
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;
839 case R_NAZREG: /* ring disappears */
840 Player.p_ring.ring_type = R_NONE;
841 break;
843 case R_SPOILED: /* ring kills player */
844 death("A cursed ring");
845 break;
847 case R_DLREG: /* this ring doesn't expire */
848 Player.p_ring.ring_duration = 0;
849 break;
852 if (Player.p_age / N_AGE > Player.p_degenerated)
853 /* age player slightly */
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;
868 void
869 initplayer(struct player *playerp)
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;
891 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */
893 playerp->p_x = ROLL(-125.0, 251.0);
894 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */
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;
901 playerp->p_age = 0L;
903 playerp->p_degenerated = 1; /* don't degenerate initially */
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;
917 playerp->p_palantir =
918 playerp->p_blessing =
919 playerp->p_virgin =
920 playerp->p_blindness = FALSE;
922 playerp->p_name[0] =
923 playerp->p_password[0] =
924 playerp->p_login[0] = '\0';
927 void
928 readmessage(void)
930 move(3, 0);
931 clrtoeol();
932 fseek(Messagefp, 0L, SEEK_SET);
933 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL)
934 addstr(Databuf);
937 void
938 error(const char *whichfile)
940 int (*funcp)(const char *,...);
942 if (Windows) {
943 funcp = printw;
944 clear();
945 } else
946 funcp = printf;
948 (*funcp) ("An unrecoverable error has occurred reading %s. (%s)\n", whichfile, strerror(errno));
949 (*funcp) ("Please run 'setup' to determine the problem.\n");
950 cleanup(TRUE);
951 /* NOTREACHED */
954 double
955 distance(double x_1, double x_2, double y_1, double y_2)
957 double deltax, deltay;
959 deltax = x_1 - x_2;
960 deltay = y_1 - y_2;
961 return (sqrt(deltax * deltax + deltay * deltay));
964 void
965 ill_sig(int whichsig)
967 clear();
968 if (!(whichsig == SIGINT || whichsig == SIGQUIT))
969 printw("Error: caught signal # %d.\n", whichsig);
970 cleanup(TRUE);
971 /* NOTREACHED */
974 const char *
975 descrstatus(struct player *playerp)
977 switch (playerp->p_status) {
978 case S_PLAYING:
979 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield))
980 return ("Low Energy");
981 else
982 if (playerp->p_blindness)
983 return ("Blind");
984 else
985 return ("In game");
987 case S_CLOAKED:
988 return ("Cloaked");
990 case S_INBATTLE:
991 return ("In Battle");
993 case S_MONSTER:
994 return ("Encounter");
996 case S_TRADING:
997 return ("Trading");
999 case S_OFF:
1000 return ("Off");
1002 case S_HUNGUP:
1003 return ("Hung up");
1005 default:
1006 return ("");
1010 double
1011 drandom(void)
1013 if (sizeof(int) != 2)
1014 /* use only low bits */
1015 return ((double) (random() & 0x7fff) / 32768.0);
1016 else
1017 return ((double) random() / 32768.0);
1020 void
1021 collecttaxes(double gold, double gems)
1023 FILE *fp; /* to update Goldfile */
1024 double dtemp; /* for temporary calculations */
1025 double taxes; /* tax liability */
1027 /* add to cache */
1028 Player.p_gold += gold;
1029 Player.p_gems += gems;
1031 /* calculate tax liability */
1032 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold);
1034 if (Player.p_gold < taxes)
1035 /* not enough gold to pay taxes, must convert some gems to
1036 * gold */
1038 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to
1039 * convert */
1041 if (Player.p_gems >= dtemp)
1042 /* player has enough to convert */
1044 Player.p_gems -= dtemp;
1045 Player.p_gold += dtemp * N_GEMVALUE;
1046 } else
1047 /* take everything; this should never happen */
1049 Player.p_gold += Player.p_gems * N_GEMVALUE;
1050 Player.p_gems = 0.0;
1051 taxes = Player.p_gold;
1054 Player.p_gold -= taxes;
1056 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
1057 /* update taxes */
1059 dtemp = 0.0;
1060 fread((char *) &dtemp, sizeof(double), 1, fp);
1061 dtemp += floor(taxes);
1062 fseek(fp, 0L, SEEK_SET);
1063 fwrite((char *) &dtemp, sizeof(double), 1, fp);
1064 fclose(fp);