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