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