]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - phantasia/misc.c
Fix arguments to *printw().
[bsdgames-darwin.git] / phantasia / misc.c
1 /* $NetBSD: misc.c,v 1.7 2000/04/27 00:30:53 jdc Exp $ */
2
3 /*
4 * misc.c Phantasia miscellaneous support routines
5 */
6
7 #include "include.h"
8
9
10 void
11 movelevel()
12 {
13 const 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 const 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 const char *label; /* pointer to place name */
71 static const char *const 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 }
358 break;
359 }
360 break;
361
362 case 'S': /* sell gems */
363 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ",
364 (double) N_GEMVALUE, Player.p_gems);
365 numitems = floor(infloat());
366
367 if (numitems > Player.p_gems || numitems < 0)
368 ++cheat;
369 else {
370 cheat = 0;
371 Player.p_gems -= numitems;
372 Player.p_gold += numitems * N_GEMVALUE;
373 }
374 }
375
376 if (cheat == 1)
377 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n");
378 else
379 if (cheat == 2) {
380 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n");
381 printw("a %.0f level magic user, and you made %s mad!\n",
382 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her");
383 altercoordinates(0.0, 0.0, A_FAR);
384 Player.p_energy /= 2.0;
385 ++Player.p_sin;
386 more(23);
387 return;
388 } else
389 if (dishonest) {
390 mvaddstr(17, 0, "The merchant stole your money!");
391 refresh();
392 altercoordinates(Player.p_x - Player.p_x / 10.0,
393 Player.p_y - Player.p_y / 10.0, A_SPECIFIC);
394 sleep(2);
395 return;
396 }
397 }
398 }
399
400 void
401 displaystats()
402 {
403 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE));
404 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n",
405 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield,
406 Player.p_mana, Users);
407 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n",
408 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might,
409 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player));
410 }
411
412 void
413 allstatslist()
414 {
415 static const char *const flags[] = /* to print value of some bools */
416 {
417 "False",
418 " True"
419 };
420
421 mvprintw(8, 0, "Type: %s\n", descrtype(&Player, FALSE));
422
423 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience);
424 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains);
425 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl);
426 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin);
427 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison);
428 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems);
429 mvprintw(16, 0, "Age : %9ld", Player.p_age);
430 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater);
431 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets);
432 mvprintw(12, 40, "Charms : %9d", Player.p_charms);
433 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns);
434 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield);
435 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword);
436 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver);
437
438 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s",
439 flags[(int)Player.p_blessing],
440 flags[Player.p_ring.ring_type != R_NONE],
441 flags[(int)Player.p_virgin],
442 flags[(int)Player.p_palantir]);
443 }
444
445 const char *
446 descrtype(playerp, shortflag)
447 struct player *playerp;
448 bool shortflag;
449 {
450 int type; /* for caluculating result subscript */
451 static const char *const results[] =/* description table */
452 {
453 " Magic User", " MU",
454 " Fighter", " F ",
455 " Elf", " E ",
456 " Dwarf", " D ",
457 " Halfling", " H ",
458 " Experimento", " EX",
459 " Super", " S ",
460 " King", " K ",
461 " Council of Wise", " CW",
462 " Ex-Valar", " EV",
463 " Valar", " V ",
464 " ? ", " ? "
465 };
466
467 type = playerp->p_type;
468
469 switch (playerp->p_specialtype) {
470 case SC_NONE:
471 type = playerp->p_type;
472 break;
473
474 case SC_KING:
475 type = 7;
476 break;
477
478 case SC_COUNCIL:
479 type = 8;
480 break;
481
482 case SC_EXVALAR:
483 type = 9;
484 break;
485
486 case SC_VALAR:
487 type = 10;
488 break;
489 }
490
491 type *= 2; /* calculate offset */
492
493 if (type > 20)
494 /* error */
495 type = 22;
496
497 if (shortflag)
498 /* use short descriptions */
499 ++type;
500
501 if (playerp->p_crowns > 0) {
502 strcpy(Databuf, results[type]);
503 Databuf[0] = '*';
504 return (Databuf);
505 } else
506 return (results[type]);
507 }
508
509 long
510 findname(name, playerp)
511 const char *name;
512 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()
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(playerp, loc)
553 struct player *playerp;
554 long loc;
555 {
556 playerp->p_name[0] = CH_MARKDELETE;
557 playerp->p_status = S_NOTUSED;
558 writerecord(playerp, loc);
559 }
560
561 void
562 leavegame()
563 {
564
565 if (Player.p_level < 1.0)
566 /* delete character */
567 freerecord(&Player, Fileloc);
568 else {
569 Player.p_status = S_OFF;
570 writerecord(&Player, Fileloc);
571 }
572
573 cleanup(TRUE);
574 /* NOTREACHED */
575 }
576
577 void
578 death(how)
579 const char *how;
580 {
581 FILE *fp; /* for updating various files */
582 int ch; /* input */
583 static const char *const deathmesg[] =
584 /* add more messages here, if desired */
585 {
586 "You have been wounded beyond repair. ",
587 "You have been disemboweled. ",
588 "You've been mashed, mauled, and spit upon. (You're dead.)\n",
589 "You died! ",
590 "You're a complete failure -- you've died!!\n",
591 "You have been dealt a fatal blow! "
592 };
593
594 clear();
595
596 if (strcmp(how, "Stupidity") != 0) {
597 if (Player.p_level > 9999.0)
598 /* old age */
599 addstr("Characters must be retired upon reaching level 10000. Sorry.");
600 else
601 if (Player.p_lives > 0)
602 /* extra lives */
603 {
604 addstr("You should be more cautious. You've been killed.\n");
605 printw("You only have %d more chance(s).\n", --Player.p_lives);
606 more(3);
607 Player.p_energy = Player.p_maxenergy;
608 return;
609 } else
610 if (Player.p_specialtype == SC_VALAR) {
611 addstr("You had your chances, but Valar aren't totally\n");
612 addstr("immortal. You are now left to wither and die . . .\n");
613 more(3);
614 Player.p_brains = Player.p_level / 25.0;
615 Player.p_energy = Player.p_maxenergy /= 5.0;
616 Player.p_quksilver = Player.p_sword = 0.0;
617 Player.p_specialtype = SC_COUNCIL;
618 return;
619 } else
620 if (Player.p_ring.ring_inuse &&
621 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG))
622 /* good ring in use - saved
623 * from death */
624 {
625 mvaddstr(4, 0, "Your ring saved you from death!\n");
626 refresh();
627 Player.p_ring.ring_type = R_NONE;
628 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0;
629 if (Player.p_crowns > 0)
630 --Player.p_crowns;
631 return;
632 } else
633 if (Player.p_ring.ring_type == R_BAD
634 || Player.p_ring.ring_type == R_SPOILED)
635 /* bad ring in
636 * possession; name
637 * idiot after player */
638 {
639 mvaddstr(4, 0,
640 "Your ring has taken control of you and turned you into a monster!\n");
641 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
642 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
643 strcpy(Curmonster.m_name, Player.p_name);
644 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, SEEK_SET);
645 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
646 fflush(Monstfp);
647 }
648 }
649 enterscore(); /* update score board */
650
651 /* put info in last dead file */
652 fp = fopen(_PATH_LASTDEAD, "w");
653 fprintf(fp, "%s (%s, run by %s, level %.0f, killed by %s)",
654 Player.p_name, descrtype(&Player, TRUE),
655 Player.p_login, Player.p_level, how);
656 fclose(fp);
657
658 /* let other players know */
659 fp = fopen(_PATH_MESS, "w");
660 fprintf(fp, "%s was killed by %s.", Player.p_name, how);
661 fclose(fp);
662
663 freerecord(&Player, Fileloc);
664
665 clear();
666 move(10, 0);
667 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]);
668 addstr("Care to give it another try ? ");
669 ch = getanswer("NY", FALSE);
670
671 if (ch == 'Y') {
672 cleanup(FALSE);
673 execl(_PATH_GAMEPROG, "phantasia", "-s",
674 (Wizard ? "-S" : (char *) NULL), 0);
675 exit(0);
676 /* NOTREACHED */
677 }
678 cleanup(TRUE);
679 /* NOTREACHED */
680 }
681
682 void
683 writerecord(playerp, place)
684 struct player *playerp;
685 long place;
686 {
687 fseek(Playersfp, place, SEEK_SET);
688 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
689 fflush(Playersfp);
690 }
691
692 double
693 explevel(experience)
694 double experience;
695 {
696 if (experience < 1.1e7)
697 return (floor(pow((experience / 1000.0), 0.4875)));
698 else
699 return (floor(pow((experience / 1250.0), 0.4865)));
700 }
701
702 void
703 truncstring(string)
704 char *string;
705 {
706 int length; /* length of string */
707
708 length = strlen(string);
709 while (string[--length] == ' ')
710 string[length] = '\0';
711 }
712
713 void
714 altercoordinates(xnew, ynew, operation)
715 double xnew;
716 double ynew;
717 int operation;
718 {
719 switch (operation) {
720 case A_FORCED: /* move with no checks */
721 break;
722
723 case A_NEAR: /* pick random coordinates near */
724 xnew = Player.p_x + ROLL(1.0, 5.0);
725 ynew = Player.p_y - ROLL(1.0, 5.0);
726 /* fall through for check */
727
728 case A_SPECIFIC: /* just move player */
729 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND)
730 /*
731 * cannot move back from point of no return
732 * pick the largest coordinate to remain unchanged
733 */
734 {
735 if (fabs(xnew) > fabs(ynew))
736 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND);
737 else
738 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND);
739 }
740 break;
741
742 case A_FAR: /* pick random coordinates far */
743 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle);
744 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle);
745 break;
746 }
747
748 /* now set location flags and adjust coordinates */
749 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew));
750
751 /* set up flags based upon location */
752 Throne = Marsh = Beyond = FALSE;
753
754 if (Player.p_x == 0.0 && Player.p_y == 0.0)
755 Throne = TRUE;
756 else
757 if (Circle < 35 && Circle >= 20)
758 Marsh = TRUE;
759 else
760 if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND)
761 Beyond = TRUE;
762
763 Changed = TRUE;
764 }
765
766 void
767 readrecord(playerp, loc)
768 struct player *playerp;
769 long loc;
770 {
771 fseek(Playersfp, loc, SEEK_SET);
772 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
773 }
774
775 void
776 adjuststats()
777 {
778 double dtemp; /* for temporary calculations */
779
780 if (explevel(Player.p_experience) > Player.p_level)
781 /* move one or more levels */
782 {
783 movelevel();
784 if (Player.p_level > 5.0)
785 Timeout = TRUE;
786 }
787 if (Player.p_specialtype == SC_VALAR)
788 /* valar */
789 Circle = Player.p_level / 5.0;
790
791 /* calculate effective quickness */
792 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote
793 - Player.p_level;;
794 dtemp = MAX(0.0, dtemp);/* gold slows player down */
795 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp;
796
797 /* calculate effective strength */
798 if (Player.p_poison > 0.0)
799 /* poison makes player weaker */
800 {
801 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0;
802 dtemp = MAX(0.1, dtemp);
803 } else
804 dtemp = 1.0;
805 Player.p_might = dtemp * Player.p_strength + Player.p_sword;
806
807 /* insure that important things are within limits */
808 Player.p_quksilver = MIN(99.0, Player.p_quksilver);
809 Player.p_mana = MIN(Player.p_mana,
810 Player.p_level * Statptr->c_maxmana + 1000.0);
811 Player.p_brains = MIN(Player.p_brains,
812 Player.p_level * Statptr->c_maxbrains + 200.0);
813 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0);
814
815 /*
816 * some implementations have problems with floating point compare
817 * we work around it with this stuff
818 */
819 Player.p_gold = floor(Player.p_gold) + 0.1;
820 Player.p_gems = floor(Player.p_gems) + 0.1;
821 Player.p_mana = floor(Player.p_mana) + 0.1;
822
823 if (Player.p_ring.ring_type != R_NONE)
824 /* do ring things */
825 {
826 /* rest to max */
827 Player.p_energy = Player.p_maxenergy + Player.p_shield;
828
829 if (Player.p_ring.ring_duration <= 0)
830 /* clean up expired rings */
831 switch (Player.p_ring.ring_type) {
832 case R_BAD: /* ring drives player crazy */
833 Player.p_ring.ring_type = R_SPOILED;
834 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0);
835 break;
836
837 case R_NAZREG: /* ring disappears */
838 Player.p_ring.ring_type = R_NONE;
839 break;
840
841 case R_SPOILED: /* ring kills player */
842 death("A cursed ring");
843 break;
844
845 case R_DLREG: /* this ring doesn't expire */
846 Player.p_ring.ring_duration = 0;
847 break;
848 }
849 }
850 if (Player.p_age / N_AGE > Player.p_degenerated)
851 /* age player slightly */
852 {
853 ++Player.p_degenerated;
854 if (Player.p_quickness > 23.0)
855 Player.p_quickness *= 0.99;
856 Player.p_strength *= 0.97;
857 Player.p_brains *= 0.95;
858 Player.p_magiclvl *= 0.97;
859 Player.p_maxenergy *= 0.95;
860 Player.p_quksilver *= 0.95;
861 Player.p_sword *= 0.93;
862 Player.p_shield *= 0.93;
863 }
864 }
865
866 void
867 initplayer(playerp)
868 struct player *playerp;
869 {
870 playerp->p_experience =
871 playerp->p_level =
872 playerp->p_strength =
873 playerp->p_sword =
874 playerp->p_might =
875 playerp->p_energy =
876 playerp->p_maxenergy =
877 playerp->p_shield =
878 playerp->p_quickness =
879 playerp->p_quksilver =
880 playerp->p_speed =
881 playerp->p_magiclvl =
882 playerp->p_mana =
883 playerp->p_brains =
884 playerp->p_poison =
885 playerp->p_gems =
886 playerp->p_sin =
887 playerp->p_1scratch =
888 playerp->p_2scratch = 0.0;
889
890 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */
891
892 playerp->p_x = ROLL(-125.0, 251.0);
893 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */
894
895 /* clear ring */
896 playerp->p_ring.ring_type = R_NONE;
897 playerp->p_ring.ring_duration = 0;
898 playerp->p_ring.ring_inuse = FALSE;
899
900 playerp->p_age = 0L;
901
902 playerp->p_degenerated = 1; /* don't degenerate initially */
903
904 playerp->p_type = C_FIGHTER; /* default */
905 playerp->p_specialtype = SC_NONE;
906 playerp->p_lives =
907 playerp->p_crowns =
908 playerp->p_charms =
909 playerp->p_amulets =
910 playerp->p_holywater =
911 playerp->p_lastused = 0;
912 playerp->p_status = S_NOTUSED;
913 playerp->p_tampered = T_OFF;
914 playerp->p_istat = I_OFF;
915
916 playerp->p_palantir =
917 playerp->p_blessing =
918 playerp->p_virgin =
919 playerp->p_blindness = FALSE;
920
921 playerp->p_name[0] =
922 playerp->p_password[0] =
923 playerp->p_login[0] = '\0';
924 }
925
926 void
927 readmessage()
928 {
929 move(3, 0);
930 clrtoeol();
931 fseek(Messagefp, 0L, SEEK_SET);
932 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL)
933 addstr(Databuf);
934 }
935
936 void
937 error(whichfile)
938 const char *whichfile;
939 {
940 int (*funcp) __P((const char *,...));
941
942 if (Windows) {
943 funcp = printw;
944 clear();
945 } else
946 funcp = printf;
947
948 (*funcp) ("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno);
949 (*funcp) ("Please run 'setup' to determine the problem.\n");
950 cleanup(TRUE);
951 /* NOTREACHED */
952 }
953
954 double
955 distance(x1, x2, y1, y2)
956 double x1, x2, y1, y2;
957 {
958 double deltax, deltay;
959
960 deltax = x1 - x2;
961 deltay = y1 - y2;
962 return (sqrt(deltax * deltax + deltay * deltay));
963 }
964
965 void
966 ill_sig(whichsig)
967 int whichsig;
968 {
969 clear();
970 if (!(whichsig == SIGINT || whichsig == SIGQUIT))
971 printw("Error: caught signal # %d.\n", whichsig);
972 cleanup(TRUE);
973 /* NOTREACHED */
974 }
975
976 const char *
977 descrstatus(playerp)
978 struct player *playerp;
979 {
980 switch (playerp->p_status) {
981 case S_PLAYING:
982 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield))
983 return ("Low Energy");
984 else
985 if (playerp->p_blindness)
986 return ("Blind");
987 else
988 return ("In game");
989
990 case S_CLOAKED:
991 return ("Cloaked");
992
993 case S_INBATTLE:
994 return ("In Battle");
995
996 case S_MONSTER:
997 return ("Encounter");
998
999 case S_TRADING:
1000 return ("Trading");
1001
1002 case S_OFF:
1003 return ("Off");
1004
1005 case S_HUNGUP:
1006 return ("Hung up");
1007
1008 default:
1009 return ("");
1010 }
1011 }
1012
1013 double
1014 drandom()
1015 {
1016 if (sizeof(int) != 2)
1017 /* use only low bits */
1018 return ((double) (random() & 0x7fff) / 32768.0);
1019 else
1020 return ((double) random() / 32768.0);
1021 }
1022
1023 void
1024 collecttaxes(gold, gems)
1025 double gold;
1026 double gems;
1027 {
1028 FILE *fp; /* to update Goldfile */
1029 double dtemp; /* for temporary calculations */
1030 double taxes; /* tax liability */
1031
1032 /* add to cache */
1033 Player.p_gold += gold;
1034 Player.p_gems += gems;
1035
1036 /* calculate tax liability */
1037 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold);
1038
1039 if (Player.p_gold < taxes)
1040 /* not enough gold to pay taxes, must convert some gems to
1041 * gold */
1042 {
1043 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to
1044 * convert */
1045
1046 if (Player.p_gems >= dtemp)
1047 /* player has enough to convert */
1048 {
1049 Player.p_gems -= dtemp;
1050 Player.p_gold += dtemp * N_GEMVALUE;
1051 } else
1052 /* take everything; this should never happen */
1053 {
1054 Player.p_gold += Player.p_gems * N_GEMVALUE;
1055 Player.p_gems = 0.0;
1056 taxes = Player.p_gold;
1057 }
1058 }
1059 Player.p_gold -= taxes;
1060
1061 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
1062 /* update taxes */
1063 {
1064 dtemp = 0.0;
1065 fread((char *) &dtemp, sizeof(double), 1, fp);
1066 dtemp += floor(taxes);
1067 fseek(fp, 0L, SEEK_SET);
1068 fwrite((char *) &dtemp, sizeof(double), 1, fp);
1069 fclose(fp);
1070 }
1071 }