1 /*
2 * misc.c Phantasia miscellaneous support routines
3 */
4
5 #include "include.h"
6
7
8 /************************************************************************
9 /
10 / FUNCTION NAME: movelevel()
11 /
12 / FUNCTION: move player to new level
13 /
14 / AUTHOR: E. A. Estes, 12/4/85
15 /
16 / ARGUMENTS: none
17 /
18 / RETURN VALUE: none
19 /
20 / MODULES CALLED: death(), floor(), wmove(), drandom(), waddstr(), explevel()
21 /
22 / GLOBAL INPUTS: Player, *stdscr, *Statptr, Stattable[]
23 /
24 / GLOBAL OUTPUTS: Player, Changed
25 /
26 / DESCRIPTION:
27 / Use lookup table to increment important statistics when
28 / progressing to new experience level.
29 / Players are rested to maximum as a bonus for making a new
30 / level.
31 / Check for council of wise, and being too big to be king.
32 /
33 /************************************************************************/
34
movelevel()35 movelevel()
36 {
37 register struct charstats *statptr; /* for pointing into Stattable */
38 double new; /* new level */
39 double inc; /* increment between new and old levels */
40
41 Changed = TRUE;
42
43 if (Player.p_type == C_EXPER)
44 /* roll a type to use for increment */
45 statptr = &Stattable[(int) ROLL(C_MAGIC, C_HALFLING - C_MAGIC + 1)];
46 else
47 statptr = Statptr;
48
49 new = explevel(Player.p_experience);
50 inc = new - Player.p_level;
51 Player.p_level = new;
52
53 /* add increments to statistics */
54 Player.p_strength += statptr->c_strength.increase * inc;
55 Player.p_mana += statptr->c_mana.increase * inc;
56 Player.p_brains += statptr->c_brains.increase * inc;
57 Player.p_magiclvl += statptr->c_magiclvl.increase * inc;
58 Player.p_maxenergy += statptr->c_energy.increase * inc;
59
60 /* rest to maximum upon reaching new level */
61 Player.p_energy = Player.p_maxenergy + Player.p_shield;
62
63 if (Player.p_crowns > 0 && Player.p_level >= 1000.0)
64 /* no longer able to be king -- turn crowns into cash */
65 {
66 Player.p_gold += ((double) Player.p_crowns) * 5000.0;
67 Player.p_crowns = 0;
68 }
69
70 if (Player.p_level >= 3000.0 && Player.p_specialtype < SC_COUNCIL)
71 /* make a member of the council */
72 {
73 mvaddstr(6, 0, "You have made it to the Council of the Wise.\n");
74 addstr("Good Luck on your search for the Holy Grail.\n");
75
76 Player.p_specialtype = SC_COUNCIL;
77
78 /* no rings for council and above */
79 Player.p_ring.ring_type = R_NONE;
80 Player.p_ring.ring_duration = 0;
81
82 Player.p_lives = 3; /* three extra lives */
83 }
84
85 if (Player.p_level > 9999.0 && Player.p_specialtype != SC_VALAR)
86 death("Old age");
87 }
88 /**/
89 /************************************************************************
90 /
91 / FUNCTION NAME: descrlocation()
92 /
93 / FUNCTION: return a formatted description of location
94 /
95 / AUTHOR: E. A. Estes, 12/4/85
96 /
97 / ARGUMENTS:
98 / struct player playerp - pointer to player structure
99 / bool shortflag - set if short form is desired
100 /
101 / RETURN VALUE: pointer to string containing result
102 /
103 / MODULES CALLED: fabs(), floor(), sprintf(), distance()
104 /
105 / GLOBAL INPUTS: Databuf[]
106 /
107 / GLOBAL OUTPUTS: none
108 /
109 / DESCRIPTION:
110 / Look at coordinates and return an appropriately formatted
111 / string.
112 /
113 /************************************************************************/
114
115 char *
descrlocation(playerp,shortflag)116 descrlocation(playerp, shortflag)
117 struct player *playerp;
118 bool shortflag;
119 {
120 double circle; /* corresponding circle for coordinates */
121 register int quadrant; /* quandrant of grid */
122 register char *label; /* pointer to place name */
123 static char *nametable[4][4] = /* names of places */
124 {
125 "Anorien", "Ithilien", "Rohan", "Lorien",
126 "Gondor", "Mordor", "Dunland", "Rovanion",
127 "South Gondor", "Khand", "Eriador", "The Iron Hills",
128 "Far Harad", "Near Harad", "The Northern Waste", "Rhun"
129 };
130
131 if (playerp->p_specialtype == SC_VALAR)
132 return(" is in Valhala");
133 else if ((circle = CIRCLE(playerp->p_x, playerp->p_y)) >= 1000.0)
134 {
135 if (MAX(fabs(playerp->p_x), fabs(playerp->p_y)) > D_BEYOND)
136 label = "The Point of No Return";
137 else
138 label = "The Ashen Mountains";
139 }
140 else if (circle >= 55)
141 label = "Morannon";
142 else if (circle >= 35)
143 label = "Kennaquahair";
144 else if (circle >= 20)
145 label = "The Dead Marshes";
146 else if (circle >= 9)
147 label = "The Outer Waste";
148 else if (circle >= 5)
149 label = "The Moors Adventurous";
150 else
151 {
152 if (playerp->p_x == 0.0 && playerp->p_y == 0.0)
153 label = "The Lord's Chamber";
154 else
155 {
156 /* this expression is split to prevent compiler loop with some compilers */
157 quadrant = ((playerp->p_x > 0.0) ? 1 : 0);
158 quadrant += ((playerp->p_y >= 0.0) ? 2 : 0);
159 label = nametable[((int) circle) - 1][quadrant];
160 }
161 }
162
163 if (shortflag)
164 sprintf(Databuf, "%.29s", label);
165 else
166 sprintf(Databuf, " is in %s (%.0f,%.0f)", label, playerp->p_x, playerp->p_y);
167
168 return(Databuf);
169 }
170 /**/
171 /************************************************************************
172 /
173 / FUNCTION NAME: tradingpost()
174 /
175 / FUNCTION: do trading post stuff
176 /
177 / AUTHOR: E. A. Estes, 12/4/85
178 /
179 / ARGUMENTS: none
180 /
181 / RETURN VALUE: none
182 /
183 / MODULES CALLED: writerecord(), adjuststats(), fabs(), more(), sqrt(),
184 / sleep(), floor(), wmove(), drandom(), wclear(), printw(),
185 / altercoordinates(), infloat(), waddstr(), wrefresh(), mvprintw(), getanswer(),
186 / wclrtoeol(), wclrtobot()
187 /
188 / GLOBAL INPUTS: Menu[], Circle, Player, *stdscr, Fileloc, Nobetter[]
189 /
190 / GLOBAL OUTPUTS: Player
191 /
192 / DESCRIPTION:
193 / Different trading posts have different items.
194 / Merchants cannot be cheated, but they can be dishonest
195 / themselves.
196 /
197 / Shields, swords, and quicksilver are not cumulative. This is
198 / one major area of complaint, but there are two reasons for this:
199 / 1) It becomes MUCH too easy to make very large versions
200 / of these items.
201 / 2) In the real world, one cannot simply weld two swords
202 / together to make a bigger one.
203 /
204 / At one time, it was possible to sell old weapons at half the purchase
205 / price. This resulted in huge amounts of gold floating around,
206 / and the game lost much of its challenge.
207 /
208 / Also, purchasing gems defeats the whole purpose of gold. Gold
209 / is small change for lower level players. They really shouldn't
210 / be able to accumulate more than enough gold for a small sword or
211 / a few books. Higher level players shouldn't even bother to pick
212 / up gold, except maybe to buy mana once in a while.
213 /
214 /************************************************************************/
215
tradingpost()216 tradingpost()
217 {
218 double numitems; /* number of items to purchase */
219 double cost; /* cost of purchase */
220 double blessingcost; /* cost of blessing */
221 int ch; /* input */
222 register int size; /* size of the trading post */
223 register int loop; /* loop counter */
224 int cheat = 0; /* number of times player has tried to cheat */
225 bool dishonest = FALSE;/* set when merchant is dishonest */
226
227 Player.p_status = S_TRADING;
228 writerecord(&Player, Fileloc);
229
230 clear();
231 addstr("You are at a trading post. All purchases must be made with gold.");
232
233 size = sqrt(fabs(Player.p_x / 100)) + 1;
234 size = MIN(7, size);
235
236 /* set up cost of blessing */
237 blessingcost = 1000.0 * (Player.p_level + 5.0);
238
239 /* print Menu */
240 move(7, 0);
241 for (loop = 0; loop < size; ++loop)
242 /* print Menu */
243 {
244 if (loop == 6)
245 cost = blessingcost;
246 else
247 cost = Menu[loop].cost;
248 printw("(%d) %-12s: %6.0f\n", loop + 1, Menu[loop].item, cost);
249 }
250
251 mvprintw(5, 0, "L:Leave P:Purchase S:Sell Gems ? ");
252
253 for (;;)
254 {
255 adjuststats(); /* truncate any bad values */
256
257 /* print some important statistics */
258 mvprintw(1, 0, "Gold: %9.0f Gems: %9.0f Level: %6.0f Charms: %6d\n",
259 Player.p_gold, Player.p_gems, Player.p_level, Player.p_charms);
260 printw("Shield: %9.0f Sword: %9.0f Quicksilver:%3.0f Blessed: %s\n",
261 Player.p_shield, Player.p_sword, Player.p_quksilver,
262 (Player.p_blessing ? " True" : "False"));
263 printw("Brains: %9.0f Mana: %9.0f", Player.p_brains, Player.p_mana);
264
265 move(5, 36);
266 ch = getanswer("LPS", FALSE);
267 move(15, 0);
268 clrtobot();
269 switch(ch)
270 {
271 case 'L': /* leave */
272 case '\n':
273 altercoordinates(0.0, 0.0, A_NEAR);
274 return;
275
276 case 'P': /* make purchase */
277 mvaddstr(15, 0, "What what would you like to buy ? ");
278 ch = getanswer(" 1234567", FALSE);
279 move(15, 0);
280 clrtoeol();
281
282 if (ch - '0' > size)
283 addstr("Sorry, this merchant doesn't have that.");
284 else
285 switch (ch)
286 {
287 case '1':
288 printw("Mana is one per %.0f gold piece. How many do you want (%.0f max) ? ",
289 Menu[0].cost, floor(Player.p_gold / Menu[0].cost));
290 cost = (numitems = floor(infloat())) * Menu[0].cost;
291
292 if (cost > Player.p_gold || numitems < 0)
293 ++cheat;
294 else
295 {
296 cheat = 0;
297 Player.p_gold -= cost;
298 if (drandom() < 0.02)
299 dishonest = TRUE;
300 else
301 Player.p_mana += numitems;
302 }
303 break;
304
305 case '2':
306 printw("Shields are %.0f per +1. How many do you want (%.0f max) ? ",
307 Menu[1].cost, floor(Player.p_gold / Menu[1].cost));
308 cost = (numitems = floor(infloat())) * Menu[1].cost;
309
310 if (numitems == 0.0)
311 break;
312 else if (cost > Player.p_gold || numitems < 0)
313 ++cheat;
314 else if (numitems < Player.p_shield)
315 NOBETTER();
316 else
317 {
318 cheat = 0;
319 Player.p_gold -= cost;
320 if (drandom() < 0.02)
321 dishonest = TRUE;
322 else
323 Player.p_shield = numitems;
324 }
325 break;
326
327 case '3':
328 printw("A book costs %.0f gp. How many do you want (%.0f max) ? ",
329 Menu[2].cost, floor(Player.p_gold / Menu[2].cost));
330 cost = (numitems = floor(infloat())) * Menu[2].cost;
331
332 if (cost > Player.p_gold || numitems < 0)
333 ++cheat;
334 else
335 {
336 cheat = 0;
337 Player.p_gold -= cost;
338 if (drandom() < 0.02)
339 dishonest = TRUE;
340 else if (drandom() * numitems > Player.p_level / 10.0
341 && numitems != 1)
342 {
343 printw("\nYou blew your mind!\n");
344 Player.p_brains /= 5;
345 }
346 else
347 {
348 Player.p_brains += floor(numitems) * ROLL(20, 8);
349 }
350 }
351 break;
352
353 case '4':
354 printw("Swords are %.0f gp per +1. How many + do you want (%.0f max) ? ",
355 Menu[3].cost, floor(Player.p_gold / Menu[3].cost));
356 cost = (numitems = floor(infloat())) * Menu[3].cost;
357
358 if (numitems == 0.0)
359 break;
360 else if (cost > Player.p_gold || numitems < 0)
361 ++cheat;
362 else if (numitems < Player.p_sword)
363 NOBETTER();
364 else
365 {
366 cheat = 0;
367 Player.p_gold -= cost;
368 if (drandom() < 0.02)
369 dishonest = TRUE;
370 else
371 Player.p_sword = numitems;
372 }
373 break;
374
375 case '5':
376 printw("A charm costs %.0f gp. How many do you want (%.0f max) ? ",
377 Menu[4].cost, floor(Player.p_gold / Menu[4].cost));
378 cost = (numitems = floor(infloat())) * Menu[4].cost;
379
380 if (cost > Player.p_gold || numitems < 0)
381 ++cheat;
382 else
383 {
384 cheat = 0;
385 Player.p_gold -= cost;
386 if (drandom() < 0.02)
387 dishonest = TRUE;
388 else
389 Player.p_charms += numitems;
390 }
391 break;
392
393 case '6':
394 printw("Quicksilver is %.0f gp per +1. How many + do you want (%.0f max) ? ",
395 Menu[5].cost, floor(Player.p_gold / Menu[5].cost));
396 cost = (numitems = floor(infloat())) * Menu[5].cost;
397
398 if (numitems == 0.0)
399 break;
400 else if (cost > Player.p_gold || numitems < 0)
401 ++cheat;
402 else if (numitems < Player.p_quksilver)
403 NOBETTER();
404 else
405 {
406 cheat = 0;
407 Player.p_gold -= cost;
408 if (drandom() < 0.02)
409 dishonest = TRUE;
410 else
411 Player.p_quksilver = numitems;
412 }
413 break;
414
415 case '7':
416 if (Player.p_blessing)
417 {
418 addstr("You already have a blessing.");
419 break;
420 }
421
422 printw("A blessing requires a %.0f gp donation. Still want one ? ", blessingcost);
423 ch = getanswer("NY", FALSE);
424
425 if (ch == 'Y')
426 if (Player.p_gold < blessingcost)
427 ++cheat;
428 else
429 {
430 cheat = 0;
431 Player.p_gold -= blessingcost;
432 if (drandom() < 0.02)
433 dishonest = TRUE;
434 else
435 Player.p_blessing = TRUE;
436 }
437 break;
438 }
439 break;
440
441 case 'S': /* sell gems */
442 mvprintw(15, 0, "A gem is worth %.0f gp. How many do you want to sell (%.0f max) ? ",
443 (double) N_GEMVALUE, Player.p_gems);
444 numitems = floor(infloat());
445
446 if (numitems > Player.p_gems || numitems < 0)
447 ++cheat;
448 else
449 {
450 cheat = 0;
451 Player.p_gems -= numitems;
452 Player.p_gold += numitems * N_GEMVALUE;
453 }
454 }
455
456 if (cheat == 1)
457 mvaddstr(17, 0, "Come on, merchants aren't stupid. Stop cheating.\n");
458 else if (cheat == 2)
459 {
460 mvaddstr(17, 0, "You had your chance. This merchant happens to be\n");
461 printw("a %.0f level magic user, and you made %s mad!\n",
462 ROLL(Circle * 20.0, 40.0), (drandom() < 0.5) ? "him" : "her");
463 altercoordinates(0.0, 0.0, A_FAR);
464 Player.p_energy /= 2.0;
465 ++Player.p_sin;
466 more(23);
467 return;
468 }
469 else if (dishonest)
470 {
471 mvaddstr(17, 0, "The merchant stole your money!");
472 refresh();
473 altercoordinates(Player.p_x - Player.p_x / 10.0,
474 Player.p_y - Player.p_y / 10.0, A_SPECIFIC);
475 sleep(2);
476 return;
477 }
478 }
479 }
480 /**/
481 /************************************************************************
482 /
483 / FUNCTION NAME: displaystats()
484 /
485 / FUNCTION: print out important player statistics
486 /
487 / AUTHOR: E. A. Estes, 12/4/85
488 /
489 / ARGUMENTS: none
490 /
491 / RETURN VALUE: none
492 /
493 / MODULES CALLED: descrstatus(), descrlocation(), mvprintw()
494 /
495 / GLOBAL INPUTS: Users, Player
496 /
497 / GLOBAL OUTPUTS: none
498 /
499 / DESCRIPTION:
500 / Important player statistics are printed on the screen.
501 /
502 /************************************************************************/
503
displaystats()504 displaystats()
505 {
506 mvprintw(0, 0, "%s%s\n", Player.p_name, descrlocation(&Player, FALSE));
507 mvprintw(1, 0, "Level :%7.0f Energy :%9.0f(%9.0f) Mana :%9.0f Users:%3d\n",
508 Player.p_level, Player.p_energy, Player.p_maxenergy + Player.p_shield,
509 Player.p_mana, Users);
510 mvprintw(2, 0, "Quick :%3.0f(%3.0f) Strength:%9.0f(%9.0f) Gold :%9.0f %s\n",
511 Player.p_speed, Player.p_quickness + Player.p_quksilver, Player.p_might,
512 Player.p_strength + Player.p_sword, Player.p_gold, descrstatus(&Player));
513 }
514 /**/
515 /************************************************************************
516 /
517 / FUNCTION NAME: allstatslist()
518 /
519 / FUNCTION: show player items
520 /
521 / AUTHOR: E. A. Estes, 12/4/85
522 /
523 / ARGUMENTS: none
524 /
525 / RETURN VALUE: none
526 /
527 / MODULES CALLED: mvprintw(), descrtype()
528 /
529 / GLOBAL INPUTS: Player
530 /
531 / GLOBAL OUTPUTS: none
532 /
533 / DESCRIPTION:
534 / Print out some player statistics of lesser importance.
535 /
536 /************************************************************************/
537
allstatslist()538 allstatslist()
539 {
540 static char *flags[] = /* to print value of some bools */
541 {
542 "False",
543 " True"
544 };
545
546 mvprintw( 8, 0, "Type: %s\n", descrtype(&Player, FALSE));
547
548 mvprintw(10, 0, "Experience: %9.0f", Player.p_experience);
549 mvprintw(11, 0, "Brains : %9.0f", Player.p_brains);
550 mvprintw(12, 0, "Magic Lvl : %9.0f", Player.p_magiclvl);
551 mvprintw(13, 0, "Sin : %9.5f", Player.p_sin);
552 mvprintw(14, 0, "Poison : %9.5f", Player.p_poison);
553 mvprintw(15, 0, "Gems : %9.0f", Player.p_gems);
554 mvprintw(16, 0, "Age : %9d", Player.p_age);
555 mvprintw(10, 40, "Holy Water: %9d", Player.p_holywater);
556 mvprintw(11, 40, "Amulets : %9d", Player.p_amulets);
557 mvprintw(12, 40, "Charms : %9d", Player.p_charms);
558 mvprintw(13, 40, "Crowns : %9d", Player.p_crowns);
559 mvprintw(14, 40, "Shield : %9.0f", Player.p_shield);
560 mvprintw(15, 40, "Sword : %9.0f", Player.p_sword);
561 mvprintw(16, 40, "Quickslver: %9.0f", Player.p_quksilver);
562
563 mvprintw(18, 0, "Blessing: %s Ring: %s Virgin: %s Palantir: %s",
564 flags[Player.p_blessing], flags[Player.p_ring.ring_type != R_NONE],
565 flags[Player.p_virgin], flags[Player.p_palantir]);
566 }
567 /**/
568 /************************************************************************
569 /
570 / FUNCTION NAME: descrtype()
571 /
572 / FUNCTION: return a string specifying player type
573 /
574 / AUTHOR: E. A. Estes, 12/4/85
575 /
576 / ARGUMENTS:
577 / struct player playerp - pointer to structure for player
578 / bool shortflag - set if short form is desired
579 /
580 / RETURN VALUE: pointer to string describing player type
581 /
582 / MODULES CALLED: strcpy()
583 /
584 / GLOBAL INPUTS: Databuf[]
585 /
586 / GLOBAL OUTPUTS: Databuf[]
587 /
588 / DESCRIPTION:
589 / Return a string describing the player type.
590 / King, council, valar, supercedes other types.
591 / The first character of the string is '*' if the player
592 / has a crown.
593 / If 'shortflag' is TRUE, return a 3 character string.
594 /
595 /************************************************************************/
596
597 char *
descrtype(playerp,shortflag)598 descrtype(playerp, shortflag)
599 struct player *playerp;
600 bool shortflag;
601 {
602 register int type; /* for caluculating result subscript */
603 static char *results[] = /* description table */
604 {
605 " Magic User", " MU",
606 " Fighter", " F ",
607 " Elf", " E ",
608 " Dwarf", " D ",
609 " Halfling", " H ",
610 " Experimento", " EX",
611 " Super", " S ",
612 " King", " K ",
613 " Council of Wise", " CW",
614 " Ex-Valar", " EV",
615 " Valar", " V ",
616 " ? ", " ? "
617 };
618
619 type = playerp->p_type;
620
621 switch (playerp->p_specialtype)
622 {
623 case SC_NONE:
624 type = playerp->p_type;
625 break;
626
627 case SC_KING:
628 type = 7;
629 break;
630
631 case SC_COUNCIL:
632 type = 8;
633 break;
634
635 case SC_EXVALAR:
636 type = 9;
637 break;
638
639 case SC_VALAR:
640 type = 10;
641 break;
642 }
643
644 type *= 2; /* calculate offset */
645
646 if (type > 20)
647 /* error */
648 type = 22;
649
650 if (shortflag)
651 /* use short descriptions */
652 ++type;
653
654 if (playerp->p_crowns > 0)
655 {
656 strcpy(Databuf, results[type]);
657 Databuf[0] = '*';
658 return(Databuf);
659 }
660 else
661 return(results[type]);
662 }
663 /**/
664 /************************************************************************
665 /
666 / FUNCTION NAME: findname()
667 /
668 / FUNCTION: find location in player file of given name
669 /
670 / AUTHOR: E. A. Estes, 12/4/85
671 /
672 / ARGUMENTS:
673 / char *name - name of character to look for
674 / struct player *playerp - pointer of structure to fill
675 /
676 / RETURN VALUE: location of player if found, -1 otherwise
677 /
678 / MODULES CALLED: fread(), fseek(), strcmp()
679 /
680 / GLOBAL INPUTS: Wizard, *Playersfp
681 /
682 / GLOBAL OUTPUTS: none
683 /
684 / DESCRIPTION:
685 / Search the player file for the player of the given name.
686 / If player is found, fill structure with player data.
687 /
688 /************************************************************************/
689
690 long
findname(name,playerp)691 findname(name, playerp)
692 register char *name;
693 register struct player *playerp;
694 {
695 long loc = 0; /* location in the file */
696
697 fseek(Playersfp, 0L, 0);
698 while (fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
699 {
700 if (strcmp(playerp->p_name, name) == 0)
701 {
702 if (playerp->p_status != S_NOTUSED || Wizard)
703 /* found it */
704 return(loc);
705 }
706 loc += SZ_PLAYERSTRUCT;
707 }
708
709 return(-1);
710 }
711 /**/
712 /************************************************************************
713 /
714 / FUNCTION NAME: allocrecord()
715 /
716 / FUNCTION: find space in the player file for a new character
717 /
718 / AUTHOR: E. A. Estes, 12/4/85
719 /
720 / ARGUMENTS: none
721 /
722 / RETURN VALUE: location of free space in file
723 /
724 / MODULES CALLED: initplayer(), writerecord(), fread(), fseek()
725 /
726 / GLOBAL INPUTS: Other, *Playersfp
727 /
728 / GLOBAL OUTPUTS: Player
729 /
730 / DESCRIPTION:
731 / Search the player file for an unused entry. If none are found,
732 / make one at the end of the file.
733 /
734 /************************************************************************/
735
736 long
allocrecord()737 allocrecord()
738 {
739 long loc = 0L; /* location in file */
740
741 fseek(Playersfp, 0L, 0);
742 while (fread((char *) &Other, SZ_PLAYERSTRUCT, 1, Playersfp) == 1)
743 {
744 if (Other.p_status == S_NOTUSED)
745 /* found an empty record */
746 return(loc);
747 else
748 loc += SZ_PLAYERSTRUCT;
749 }
750
751 /* make a new record */
752 initplayer(&Other);
753 Player.p_status = S_OFF;
754 writerecord(&Other, loc);
755
756 return(loc);
757 }
758 /**/
759 /************************************************************************
760 /
761 / FUNCTION NAME: freerecord()
762 /
763 / FUNCTION: free up a record on the player file
764 /
765 / AUTHOR: E. A. Estes, 2/7/86
766 /
767 / ARGUMENTS:
768 / struct player playerp - pointer to structure to free
769 / long loc - location in file to free
770 /
771 / RETURN VALUE: none
772 /
773 / MODULES CALLED: writerecord()
774 /
775 / GLOBAL INPUTS: none
776 /
777 / GLOBAL OUTPUTS: none
778 /
779 / DESCRIPTION:
780 / Mark structure as not used, and update player file.
781 /
782 /************************************************************************/
783
784 freerecord(playerp, loc)
785 struct player *playerp;
786 long loc;
787 {
788 playerp->p_name[0] = CH_MARKDELETE;
789 playerp->p_status = S_NOTUSED;
790 writerecord(playerp, loc);
791 }
792 /**/
793 /************************************************************************
794 /
795 / FUNCTION NAME: leavegame()
796 /
797 / FUNCTION: leave game
798 /
799 / AUTHOR: E. A. Estes, 12/4/85
800 /
801 / ARGUMENTS: none
802 /
803 / RETURN VALUE: none
804 /
805 / MODULES CALLED: freerecord(), writerecord(), cleanup()
806 /
807 / GLOBAL INPUTS: Player, Fileloc
808 /
809 / GLOBAL OUTPUTS: Player
810 /
811 / DESCRIPTION:
812 / Mark player as inactive, and cleanup.
813 / Do not save players below level 1.
814 /
815 /************************************************************************/
816
leavegame()817 leavegame()
818 {
819
820 if (Player.p_level < 1.0)
821 /* delete character */
822 freerecord(&Player, Fileloc);
823 else
824 {
825 Player.p_status = S_OFF;
826 writerecord(&Player, Fileloc);
827 }
828
829 cleanup(TRUE);
830 /*NOTREACHED*/
831 }
832 /**/
833 /************************************************************************
834 /
835 / FUNCTION NAME: death()
836 /
837 / FUNCTION: death routine
838 /
839 / AUTHOR: E. A. Estes, 12/4/85
840 /
841 / ARGUMENTS:
842 / char *how - pointer to string describing cause of death
843 /
844 / RETURN VALUE: none
845 /
846 / MODULES CALLED: freerecord(), enterscore(), more(), exit(), fread(),
847 / fseek(), execl(), fopen(), floor(), wmove(), drandom(), wclear(), strcmp(),
848 / fwrite(), fflush(), printw(), strcpy(), fclose(), waddstr(), cleanup(),
849 / fprintf(), wrefresh(), getanswer(), descrtype()
850 /
851 / GLOBAL INPUTS: Curmonster, Wizard, Player, *stdscr, Fileloc, *Monstfp
852 /
853 / GLOBAL OUTPUTS: Player
854 /
855 / DESCRIPTION:
856 / Kill off current player.
857 / Handle rings, and multiple lives.
858 / Print an appropriate message.
859 / Update scoreboard, lastdead, and let other players know about
860 / the demise of their comrade.
861 /
862 /************************************************************************/
863
death(how)864 death(how)
865 char *how;
866 {
867 FILE *fp; /* for updating various files */
868 int ch; /* input */
869 static char *deathmesg[] =
870 /* add more messages here, if desired */
871 {
872 "You have been wounded beyond repair. ",
873 "You have been disemboweled. ",
874 "You've been mashed, mauled, and spit upon. (You're dead.)\n",
875 "You died! ",
876 "You're a complete failure -- you've died!!\n",
877 "You have been dealt a fatal blow! "
878 };
879
880 clear();
881
882 if (strcmp(how, "Stupidity") != 0)
883 {
884 if (Player.p_level > 9999.0)
885 /* old age */
886 addstr("Characters must be retired upon reaching level 10000. Sorry.");
887 else if (Player.p_lives > 0)
888 /* extra lives */
889 {
890 addstr("You should be more cautious. You've been killed.\n");
891 printw("You only have %d more chance(s).\n", --Player.p_lives);
892 more(3);
893 Player.p_energy = Player.p_maxenergy;
894 return;
895 }
896 else if (Player.p_specialtype == SC_VALAR)
897 {
898 addstr("You had your chances, but Valar aren't totally\n");
899 addstr("immortal. You are now left to wither and die . . .\n");
900 more(3);
901 Player.p_brains = Player.p_level / 25.0;
902 Player.p_energy = Player.p_maxenergy /= 5.0;
903 Player.p_quksilver = Player.p_sword = 0.0;
904 Player.p_specialtype = SC_COUNCIL;
905 return;
906 }
907 else if (Player.p_ring.ring_inuse &&
908 (Player.p_ring.ring_type == R_DLREG || Player.p_ring.ring_type == R_NAZREG))
909 /* good ring in use - saved from death */
910 {
911 mvaddstr(4, 0, "Your ring saved you from death!\n");
912 refresh();
913 Player.p_ring.ring_type = R_NONE;
914 Player.p_energy = Player.p_maxenergy / 12.0 + 1.0;
915 if (Player.p_crowns > 0)
916 --Player.p_crowns;
917 return;
918 }
919 else if (Player.p_ring.ring_type == R_BAD
920 || Player.p_ring.ring_type == R_SPOILED)
921 /* bad ring in possession; name idiot after player */
922 {
923 mvaddstr(4, 0,
924 "Your ring has taken control of you and turned you into a monster!\n");
925 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0);
926 fread((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
927 strcpy(Curmonster.m_name, Player.p_name);
928 fseek(Monstfp, 13L * SZ_MONSTERSTRUCT, 0);
929 fwrite((char *) &Curmonster, SZ_MONSTERSTRUCT, 1, Monstfp);
930 fflush(Monstfp);
931 }
932 }
933
934 enterscore(); /* update score board */
935
936 /* put info in last dead file */
937 fp = fopen(_PATH_LASTDEAD, "w");
938 fprintf(fp,"%s (%s, run by %s, level %.0f, killed by %s)",
939 Player.p_name, descrtype(&Player, TRUE),
940 Player.p_login, Player.p_level, how);
941 fclose(fp);
942
943 /* let other players know */
944 fp = fopen(_PATH_MESS, "w");
945 fprintf(fp, "%s was killed by %s.", Player.p_name, how);
946 fclose(fp);
947
948 freerecord(&Player, Fileloc);
949
950 clear();
951 move(10, 0);
952 addstr(deathmesg[(int) ROLL(0.0, (double) sizeof(deathmesg) / sizeof(char *))]);
953 addstr("Care to give it another try ? ");
954 ch = getanswer("NY", FALSE);
955
956 if (ch == 'Y')
957 {
958 cleanup(FALSE);
959 execl(_PATH_GAMEPROG, "phantasia", "-s",
960 (Wizard ? "-S": (char *) NULL), 0);
961 exit(0);
962 /*NOTREACHED*/
963 }
964
965 cleanup(TRUE);
966 /*NOTREACHED*/
967 }
968 /**/
969 /************************************************************************
970 /
971 / FUNCTION NAME: writerecord()
972 /
973 / FUNCTION: update structure in player file
974 /
975 / AUTHOR: E. A. Estes, 12/4/85
976 /
977 / ARGUMENTS:
978 / struct player *playerp - pointer to structure to write out
979 / long place - location in file to updata
980 /
981 / RETURN VALUE: none
982 /
983 / MODULES CALLED: fseek(), fwrite(), fflush()
984 /
985 / GLOBAL INPUTS: *Playersfp
986 /
987 / GLOBAL OUTPUTS: none
988 /
989 / DESCRIPTION:
990 / Update location in player file with given structure.
991 /
992 /************************************************************************/
993
writerecord(playerp,place)994 writerecord(playerp, place)
995 register struct player *playerp;
996 long place;
997 {
998 fseek(Playersfp, place, 0);
999 fwrite((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
1000 fflush(Playersfp);
1001 }
1002 /**/
1003 /************************************************************************
1004 /
1005 / FUNCTION NAME: explevel()
1006 /
1007 / FUNCTION: calculate level based upon experience
1008 /
1009 / AUTHOR: E. A. Estes, 12/4/85
1010 /
1011 / ARGUMENTS:
1012 / double experience - experience to calculate experience level from
1013 /
1014 / RETURN VALUE: experience level
1015 /
1016 / MODULES CALLED: pow(), floor()
1017 /
1018 / GLOBAL INPUTS: none
1019 /
1020 / GLOBAL OUTPUTS: none
1021 /
1022 / DESCRIPTION:
1023 / Experience level is a geometric progression. This has been finely
1024 / tuned over the years, and probably should not be changed.
1025 /
1026 /************************************************************************/
1027
1028 double
explevel(experience)1029 explevel(experience)
1030 double experience;
1031 {
1032 if (experience < 1.1e7)
1033 return(floor(pow((experience / 1000.0), 0.4875)));
1034 else
1035 return(floor(pow((experience / 1250.0), 0.4865)));
1036 }
1037 /**/
1038 /************************************************************************
1039 /
1040 / FUNCTION NAME: truncstring()
1041 /
1042 / FUNCTION: truncate trailing blanks off a string
1043 /
1044 / AUTHOR: E. A. Estes, 12/4/85
1045 /
1046 / ARGUMENTS:
1047 / char *string - pointer to null terminated string
1048 /
1049 / RETURN VALUE: none
1050 /
1051 / MODULES CALLED: strlen()
1052 /
1053 / GLOBAL INPUTS: none
1054 /
1055 / GLOBAL OUTPUTS: none
1056 /
1057 / DESCRIPTION:
1058 / Put nul characters in place of spaces at the end of the string.
1059 /
1060 /************************************************************************/
1061
truncstring(string)1062 truncstring(string)
1063 register char *string;
1064 {
1065 register int length; /* length of string */
1066
1067 length = strlen(string);
1068 while (string[--length] == ' ')
1069 string[length] = '\0';
1070 }
1071 /**/
1072 /************************************************************************
1073 /
1074 / FUNCTION NAME: altercoordinates()
1075 /
1076 / FUNCTION: Alter x, y coordinates and set/check location flags
1077 /
1078 / AUTHOR: E. A. Estes, 12/16/85
1079 /
1080 / ARGUMENTS:
1081 / double xnew, ynew - new x, y coordinates
1082 / int operation - operation to perform with coordinates
1083 /
1084 / RETURN VALUE: none
1085 /
1086 / MODULES CALLED: fabs(), floor(), drandom(), distance()
1087 /
1088 / GLOBAL INPUTS: Circle, Beyond, Player
1089 /
1090 / GLOBAL OUTPUTS: Marsh, Circle, Beyond, Throne, Player, Changed
1091 /
1092 / DESCRIPTION:
1093 / This module is called whenever the player's coordinates are altered.
1094 / If the player is beyond the point of no return, he/she is forced
1095 / to stay there.
1096 /
1097 /************************************************************************/
1098
altercoordinates(xnew,ynew,operation)1099 altercoordinates(xnew, ynew, operation)
1100 double xnew;
1101 double ynew;
1102 int operation;
1103 {
1104 switch (operation)
1105 {
1106 case A_FORCED: /* move with no checks */
1107 break;
1108
1109 case A_NEAR: /* pick random coordinates near */
1110 xnew = Player.p_x + ROLL(1.0, 5.0);
1111 ynew = Player.p_y - ROLL(1.0, 5.0);
1112 /* fall through for check */
1113
1114 case A_SPECIFIC: /* just move player */
1115 if (Beyond && fabs(xnew) < D_BEYOND && fabs(ynew) < D_BEYOND)
1116 /*
1117 * cannot move back from point of no return
1118 * pick the largest coordinate to remain unchanged
1119 */
1120 {
1121 if (fabs(xnew) > fabs(ynew))
1122 xnew = SGN(Player.p_x) * MAX(fabs(Player.p_x), D_BEYOND);
1123 else
1124 ynew = SGN(Player.p_y) * MAX(fabs(Player.p_y), D_BEYOND);
1125 }
1126 break;
1127
1128 case A_FAR: /* pick random coordinates far */
1129 xnew = Player.p_x + SGN(Player.p_x) * ROLL(50 * Circle, 250 * Circle);
1130 ynew = Player.p_y + SGN(Player.p_y) * ROLL(50 * Circle, 250 * Circle);
1131 break;
1132 }
1133
1134 /* now set location flags and adjust coordinates */
1135 Circle = CIRCLE(Player.p_x = floor(xnew), Player.p_y = floor(ynew));
1136
1137 /* set up flags based upon location */
1138 Throne = Marsh = Beyond = FALSE;
1139
1140 if (Player.p_x == 0.0 && Player.p_y == 0.0)
1141 Throne = TRUE;
1142 else if (Circle < 35 && Circle >= 20)
1143 Marsh = TRUE;
1144 else if (MAX(fabs(Player.p_x), fabs(Player.p_y)) >= D_BEYOND)
1145 Beyond = TRUE;
1146
1147 Changed = TRUE;
1148 }
1149 /**/
1150 /************************************************************************
1151 /
1152 / FUNCTION NAME: readrecord()
1153 /
1154 / FUNCTION: read a player structure from file
1155 /
1156 / AUTHOR: E. A. Estes, 12/4/85
1157 /
1158 / ARGUMENTS:
1159 / struct player *playerp - pointer to structure to fill
1160 / int loc - location of record to read
1161 /
1162 / RETURN VALUE: none
1163 /
1164 / MODULES CALLED: fread(), fseek()
1165 /
1166 / GLOBAL INPUTS: *Playersfp
1167 /
1168 / GLOBAL OUTPUTS: none
1169 /
1170 / DESCRIPTION:
1171 / Read structure information from player file.
1172 /
1173 /************************************************************************/
1174
readrecord(playerp,loc)1175 readrecord(playerp, loc)
1176 register struct player *playerp;
1177 long loc;
1178 {
1179 fseek(Playersfp, loc, 0);
1180 fread((char *) playerp, SZ_PLAYERSTRUCT, 1, Playersfp);
1181 }
1182 /**/
1183 /************************************************************************
1184 /
1185 / FUNCTION NAME: adjuststats()
1186 /
1187 / FUNCTION: adjust player statistics
1188 /
1189 / AUTHOR: E. A. Estes, 12/4/85
1190 /
1191 / ARGUMENTS: none
1192 /
1193 / RETURN VALUE: none
1194 /
1195 / MODULES CALLED: death(), floor(), drandom(), explevel(), movelevel()
1196 /
1197 / GLOBAL INPUTS: Player, *Statptr
1198 /
1199 / GLOBAL OUTPUTS: Circle, Player, Timeout
1200 /
1201 / DESCRIPTION:
1202 / Handle adjustment and maximums on various player characteristics.
1203 /
1204 /************************************************************************/
1205
adjuststats()1206 adjuststats()
1207 {
1208 double dtemp; /* for temporary calculations */
1209
1210 if (explevel(Player.p_experience) > Player.p_level)
1211 /* move one or more levels */
1212 {
1213 movelevel();
1214 if (Player.p_level > 5.0)
1215 Timeout = TRUE;
1216 }
1217
1218 if (Player.p_specialtype == SC_VALAR)
1219 /* valar */
1220 Circle = Player.p_level / 5.0;
1221
1222 /* calculate effective quickness */
1223 dtemp = ((Player.p_gold + Player.p_gems / 2.0) - 1000.0) / Statptr->c_goldtote
1224 - Player.p_level;;
1225 dtemp = MAX(0.0, dtemp); /* gold slows player down */
1226 Player.p_speed = Player.p_quickness + Player.p_quksilver - dtemp;
1227
1228 /* calculate effective strength */
1229 if (Player.p_poison > 0.0)
1230 /* poison makes player weaker */
1231 {
1232 dtemp = 1.0 - Player.p_poison * Statptr->c_weakness / 800.0;
1233 dtemp = MAX(0.1, dtemp);
1234 }
1235 else
1236 dtemp = 1.0;
1237 Player.p_might = dtemp * Player.p_strength + Player.p_sword;
1238
1239 /* insure that important things are within limits */
1240 Player.p_quksilver = MIN(99.0, Player.p_quksilver);
1241 Player.p_mana = MIN(Player.p_mana,
1242 Player.p_level * Statptr->c_maxmana + 1000.0);
1243 Player.p_brains = MIN(Player.p_brains,
1244 Player.p_level * Statptr->c_maxbrains + 200.0);
1245 Player.p_charms = MIN(Player.p_charms, Player.p_level + 10.0);
1246
1247 /*
1248 * some implementations have problems with floating point compare
1249 * we work around it with this stuff
1250 */
1251 Player.p_gold = floor(Player.p_gold) + 0.1;
1252 Player.p_gems = floor(Player.p_gems) + 0.1;
1253 Player.p_mana = floor(Player.p_mana) + 0.1;
1254
1255 if (Player.p_ring.ring_type != R_NONE)
1256 /* do ring things */
1257 {
1258 /* rest to max */
1259 Player.p_energy = Player.p_maxenergy + Player.p_shield;
1260
1261 if (Player.p_ring.ring_duration <= 0)
1262 /* clean up expired rings */
1263 switch (Player.p_ring.ring_type)
1264 {
1265 case R_BAD: /* ring drives player crazy */
1266 Player.p_ring.ring_type = R_SPOILED;
1267 Player.p_ring.ring_duration = (short) ROLL(10.0, 25.0);
1268 break;
1269
1270 case R_NAZREG: /* ring disappears */
1271 Player.p_ring.ring_type = R_NONE;
1272 break;
1273
1274 case R_SPOILED: /* ring kills player */
1275 death("A cursed ring");
1276 break;
1277
1278 case R_DLREG: /* this ring doesn't expire */
1279 Player.p_ring.ring_duration = 0;
1280 break;
1281 }
1282 }
1283
1284 if (Player.p_age / N_AGE > Player.p_degenerated)
1285 /* age player slightly */
1286 {
1287 ++Player.p_degenerated;
1288 if (Player.p_quickness > 23.0)
1289 Player.p_quickness *= 0.99;
1290 Player.p_strength *= 0.97;
1291 Player.p_brains *= 0.95;
1292 Player.p_magiclvl *= 0.97;
1293 Player.p_maxenergy *= 0.95;
1294 Player.p_quksilver *= 0.95;
1295 Player.p_sword *= 0.93;
1296 Player.p_shield *= 0.93;
1297 }
1298 }
1299 /**/
1300 /************************************************************************
1301 /
1302 / FUNCTION NAME: initplayer()
1303 /
1304 / FUNCTION: initialize a character
1305 /
1306 / AUTHOR: E. A. Estes, 12/4/85
1307 /
1308 / ARGUMENTS:
1309 / struct player *playerp - pointer to structure to init
1310 /
1311 / RETURN VALUE: none
1312 /
1313 / MODULES CALLED: floor(), drandom()
1314 /
1315 / GLOBAL INPUTS: none
1316 /
1317 / GLOBAL OUTPUTS: none
1318 /
1319 / DESCRIPTION:
1320 / Put a bunch of default values in the given structure.
1321 /
1322 /************************************************************************/
1323
initplayer(playerp)1324 initplayer(playerp)
1325 register struct player *playerp;
1326 {
1327 playerp->p_experience =
1328 playerp->p_level =
1329 playerp->p_strength =
1330 playerp->p_sword =
1331 playerp->p_might =
1332 playerp->p_energy =
1333 playerp->p_maxenergy =
1334 playerp->p_shield =
1335 playerp->p_quickness =
1336 playerp->p_quksilver =
1337 playerp->p_speed =
1338 playerp->p_magiclvl =
1339 playerp->p_mana =
1340 playerp->p_brains =
1341 playerp->p_poison =
1342 playerp->p_gems =
1343 playerp->p_sin =
1344 playerp->p_1scratch =
1345 playerp->p_2scratch = 0.0;
1346
1347 playerp->p_gold = ROLL(50.0, 75.0) + 0.1; /* give some gold */
1348
1349 playerp->p_x = ROLL(-125.0, 251.0);
1350 playerp->p_y = ROLL(-125.0, 251.0); /* give random x, y */
1351
1352 /* clear ring */
1353 playerp->p_ring.ring_type = R_NONE;
1354 playerp->p_ring.ring_duration = 0;
1355 playerp->p_ring.ring_inuse = FALSE;
1356
1357 playerp->p_age = 0L;
1358
1359 playerp->p_degenerated = 1; /* don't degenerate initially */
1360
1361 playerp->p_type = C_FIGHTER; /* default */
1362 playerp->p_specialtype = SC_NONE;
1363 playerp->p_lives =
1364 playerp->p_crowns =
1365 playerp->p_charms =
1366 playerp->p_amulets =
1367 playerp->p_holywater =
1368 playerp->p_lastused = 0;
1369 playerp->p_status = S_NOTUSED;
1370 playerp->p_tampered = T_OFF;
1371 playerp->p_istat = I_OFF;
1372
1373 playerp->p_palantir =
1374 playerp->p_blessing =
1375 playerp->p_virgin =
1376 playerp->p_blindness = FALSE;
1377
1378 playerp->p_name[0] =
1379 playerp->p_password[0] =
1380 playerp->p_login[0] = '\0';
1381 }
1382 /**/
1383 /************************************************************************
1384 /
1385 / FUNCTION NAME: readmessage()
1386 /
1387 / FUNCTION: read message from other players
1388 /
1389 / AUTHOR: E. A. Estes, 12/4/85
1390 /
1391 / ARGUMENTS: none
1392 /
1393 / RETURN VALUE: none
1394 /
1395 / MODULES CALLED: fseek(), fgets(), wmove(), waddstr(), wclrtoeol()
1396 /
1397 / GLOBAL INPUTS: *stdscr, Databuf[], *Messagefp
1398 /
1399 / GLOBAL OUTPUTS: none
1400 /
1401 / DESCRIPTION:
1402 / If there is a message from other players, print it.
1403 /
1404 /************************************************************************/
1405
readmessage()1406 readmessage()
1407 {
1408 move(3, 0);
1409 clrtoeol();
1410 fseek(Messagefp, 0L, 0);
1411 if (fgets(Databuf, SZ_DATABUF, Messagefp) != NULL)
1412 addstr(Databuf);
1413 }
1414 /**/
1415 /************************************************************************
1416 /
1417 / FUNCTION NAME: error()
1418 /
1419 / FUNCTION: process evironment error
1420 /
1421 / AUTHOR: E. A. Estes, 12/4/85
1422 /
1423 / ARGUMENTS:
1424 / char *whichfile - pointer to name of file which caused error
1425 /
1426 / RETURN VALUE: none
1427 /
1428 / MODULES CALLED: wclear(), cleanup()
1429 /
1430 / GLOBAL INPUTS: errno, *stdscr, printw(), printf(), Windows
1431 /
1432 / GLOBAL OUTPUTS: none
1433 /
1434 / DESCRIPTION:
1435 / Print message about offending file, and exit.
1436 /
1437 /************************************************************************/
1438
error(whichfile)1439 error(whichfile)
1440 char *whichfile;
1441 {
1442 int (*funcp) __P((const char *, ...));
1443
1444 if (Windows)
1445 {
1446 funcp = printw;
1447 clear();
1448 }
1449 else
1450 funcp = printf;
1451
1452 (*funcp)("An unrecoverable error has occurred reading %s. (errno = %d)\n", whichfile, errno);
1453 (*funcp)("Please run 'setup' to determine the problem.\n");
1454 cleanup(TRUE);
1455 /*NOTREACHED*/
1456 }
1457 /**/
1458 /************************************************************************
1459 /
1460 / FUNCTION NAME: distance()
1461 /
1462 / FUNCTION: calculate distance between two points
1463 /
1464 / AUTHOR: E. A. Estes, 12/4/85
1465 /
1466 / ARGUMENTS:
1467 / double x1, y1 - x, y coordinates of first point
1468 / double x2, y2 - x, y coordinates of second point
1469 /
1470 / RETURN VALUE: distance between the two points
1471 /
1472 / MODULES CALLED: sqrt()
1473 /
1474 / GLOBAL INPUTS: none
1475 /
1476 / GLOBAL OUTPUTS: none
1477 /
1478 / DESCRIPTION:
1479 / This function is provided because someone's hypot() library function
1480 / fails if x1 == x2 && y1 == y2.
1481 /
1482 /************************************************************************/
1483
1484 double
distance(x1,x2,y1,y2)1485 distance(x1, x2, y1, y2)
1486 double x1, x2, y1, y2;
1487 {
1488 double deltax, deltay;
1489
1490 deltax = x1 - x2;
1491 deltay = y1 - y2;
1492 return(sqrt(deltax * deltax + deltay * deltay));
1493 }
1494
1495 /**/
1496 /************************************************************************
1497 /
1498 / FUNCTION NAME: ill_sig()
1499 /
1500 / FUNCTION: exit upon trapping an illegal signal
1501 /
1502 / AUTHOR: E. A. Estes, 12/4/85
1503 /
1504 / ARGUMENTS:
1505 / int whichsig - signal which occured to cause jump to here
1506 /
1507 / RETURN VALUE: none
1508 /
1509 / MODULES CALLED: wclear(), printw(), cleanup()
1510 /
1511 / GLOBAL INPUTS: *stdscr
1512 /
1513 / GLOBAL OUTPUTS: none
1514 /
1515 / DESCRIPTION:
1516 / When an illegal signal is caught, print a message, and cleanup.
1517 /
1518 /************************************************************************/
1519
ill_sig(whichsig)1520 ill_sig(whichsig)
1521 int whichsig;
1522 {
1523 clear();
1524 if (!(whichsig == SIGINT || whichsig == SIGQUIT))
1525 printw("Error: caught signal # %d.\n", whichsig);
1526 cleanup(TRUE);
1527 /*NOTREACHED*/
1528 }
1529 /**/
1530 /************************************************************************
1531 /
1532 / FUNCTION NAME: descrstatus()
1533 /
1534 / FUNCTION: return a string describing the player status
1535 /
1536 / AUTHOR: E. A. Estes, 3/3/86
1537 /
1538 / ARGUMENTS:
1539 / struct player playerp - pointer to player structure to describe
1540 /
1541 / RETURN VALUE: string describing player's status
1542 /
1543 / MODULES CALLED: none
1544 /
1545 / GLOBAL INPUTS: none
1546 /
1547 / GLOBAL OUTPUTS: none
1548 /
1549 / DESCRIPTION:
1550 / Return verbal description of player status.
1551 / If player status is S_PLAYING, check for low energy and blindness.
1552 /
1553 /************************************************************************/
1554
1555 char *
descrstatus(playerp)1556 descrstatus(playerp)
1557 register struct player *playerp;
1558 {
1559 switch (playerp->p_status)
1560 {
1561 case S_PLAYING:
1562 if (playerp->p_energy < 0.2 * (playerp->p_maxenergy + playerp->p_shield))
1563 return("Low Energy");
1564 else if (playerp->p_blindness)
1565 return("Blind");
1566 else
1567 return("In game");
1568
1569 case S_CLOAKED:
1570 return("Cloaked");
1571
1572 case S_INBATTLE:
1573 return("In Battle");
1574
1575 case S_MONSTER:
1576 return("Encounter");
1577
1578 case S_TRADING:
1579 return("Trading");
1580
1581 case S_OFF:
1582 return("Off");
1583
1584 case S_HUNGUP:
1585 return("Hung up");
1586
1587 default:
1588 return("");
1589 }
1590 }
1591 /**/
1592 /************************************************************************
1593 /
1594 / FUNCTION NAME: drandom()
1595 /
1596 / FUNCTION: return a random floating point number from 0.0 < 1.0
1597 /
1598 / AUTHOR: E. A. Estes, 2/7/86
1599 /
1600 / ARGUMENTS: none
1601 /
1602 / RETURN VALUE: none
1603 /
1604 / MODULES CALLED: random()
1605 /
1606 / GLOBAL INPUTS: none
1607 /
1608 / GLOBAL OUTPUTS: none
1609 /
1610 / DESCRIPTION:
1611 / Convert random integer from library routine into a floating
1612 / point number, and divide by the largest possible random number.
1613 / We mask large integers with 32767 to handle sites that return
1614 / 31 bit random integers.
1615 /
1616 /************************************************************************/
1617
1618 double
drandom()1619 drandom()
1620 {
1621 if (sizeof(int) != 2)
1622 /* use only low bits */
1623 return((double) (random() & 0x7fff) / 32768.0);
1624 else
1625 return((double) random() / 32768.0);
1626 }
1627 /**/
1628 /************************************************************************
1629 /
1630 / FUNCTION NAME: collecttaxes()
1631 /
1632 / FUNCTION: collect taxes from current player
1633 /
1634 / AUTHOR: E. A. Estes, 2/7/86
1635 /
1636 / ARGUMENTS:
1637 / double gold - amount of gold to tax
1638 / double gems - amount of gems to tax
1639 /
1640 / RETURN VALUE: none
1641 /
1642 / MODULES CALLED: fread(), fseek(), fopen(), floor(), fwrite(), fclose()
1643 /
1644 / GLOBAL INPUTS: Player
1645 /
1646 / GLOBAL OUTPUTS: Player
1647 /
1648 / DESCRIPTION:
1649 / Pay taxes on gold and gems. If the player does not have enough
1650 / gold to pay taxes on the added gems, convert some gems to gold.
1651 / Add taxes to tax data base; add remaining gold and gems to
1652 / player's cache.
1653 /
1654 /************************************************************************/
1655
collecttaxes(gold,gems)1656 collecttaxes(gold, gems)
1657 double gold;
1658 double gems;
1659 {
1660 FILE *fp; /* to update Goldfile */
1661 double dtemp; /* for temporary calculations */
1662 double taxes; /* tax liability */
1663
1664 /* add to cache */
1665 Player.p_gold += gold;
1666 Player.p_gems += gems;
1667
1668 /* calculate tax liability */
1669 taxes = N_TAXAMOUNT / 100.0 * (N_GEMVALUE * gems + gold);
1670
1671 if (Player.p_gold < taxes)
1672 /* not enough gold to pay taxes, must convert some gems to gold */
1673 {
1674 dtemp = floor(taxes / N_GEMVALUE + 1.0); /* number of gems to convert */
1675
1676 if (Player.p_gems >= dtemp)
1677 /* player has enough to convert */
1678 {
1679 Player.p_gems -= dtemp;
1680 Player.p_gold += dtemp * N_GEMVALUE;
1681 }
1682 else
1683 /* take everything; this should never happen */
1684 {
1685 Player.p_gold += Player.p_gems * N_GEMVALUE;
1686 Player.p_gems = 0.0;
1687 taxes = Player.p_gold;
1688 }
1689 }
1690
1691 Player.p_gold -= taxes;
1692
1693 if ((fp = fopen(_PATH_GOLD, "r+")) != NULL)
1694 /* update taxes */
1695 {
1696 dtemp = 0.0;
1697 fread((char *) &dtemp, sizeof(double), 1, fp);
1698 dtemp += floor(taxes);
1699 fseek(fp, 0L, 0);
1700 fwrite((char *) &dtemp, sizeof(double), 1, fp);
1701 fclose(fp);
1702 }
1703 }
1704