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