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