view arogue5/util.c @ 116:97f8fdf9595c

Makefiles: don't set defaults for CFLAGS. CFLAGS is now empty by default. If its value must be set, it should be done in the command line for make.
author John "Elwin" Edwards
date Sat, 29 Mar 2014 09:45:33 -0700
parents c49f7927b0fa
children 56e748983fa8
line wrap: on
line source

/*
 * all sorts of miscellaneous routines
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
 * All rights reserved.
 *
 * Based on "Rogue: Exploring the Dungeons of Doom"
 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
 * All rights reserved.
 *
 * See the file LICENSE.TXT for full copyright and licensing information.
 */

#include "curses.h"
#include "rogue.h"
#include <ctype.h>
#include <string.h>

/*
 * aggravate:
 *	aggravate all the monsters on this level
 */

aggravate()
{
    register struct linked_list *mi;

    for (mi = mlist; mi != NULL; mi = next(mi))
	runto(THINGPTR(mi), &hero);
}

/*
 * cansee:
 *	returns true if the hero can see a certain coordinate.
 */

cansee(y, x)
register int y, x;
{
    register struct room *rer;
    register int radius;
    coord tp;

    if (on(player, ISBLIND))
	return FALSE;

    tp.y = y;
    tp.x = x;
    rer = roomin(&tp);

    /* How far can we see? */
    if (levtype == OUTSIDE) {
	if (daytime) radius = 36;
	else if (lit_room(rer)) radius = 9;
	else radius = 3;
    }
    else radius = 3;

    /*
     * We can only see if the hero in the same room as
     * the coordinate and the room is lit or if it is close.
     */
    return ((rer != NULL && 
	     levtype != OUTSIDE &&
	     (levtype != MAZELEV ||	/* Maze level needs direct line */
	      maze_view(tp.y, tp.x)) &&
	     rer == roomin(&hero) &&
	     lit_room(rer)) ||
	    DISTANCE(y, x, hero.y, hero.x) < radius);
}

/*
 * check_level:
 *	Check to see if the guy has gone up a level.
 *
 *	Return points needed to obtain next level.
 *
 * These are the beginning experience levels for all players.
 * All further experience levels are computed by muliplying by 2
 * up through MAXDOUBLE.
 */
#define MAXDOUBLE 14	/* Maximum number of times score is doubled */
static struct {
    long base;	/* What it starts out at for doubling */
    long cap;	/* The maximum before doubling stops */
} e_levels[4] = {
	/* You must change MAXDOUBLE if you change the cap figure */
	{ 90L,	1474560L },	/* Fighter */
	{ 130L,	2129920L }, 	/* Magician */
	{ 110L, 1802240L },	/* cleric */
	{ 75L,	1228800L }	/* Thief */
};

long
check_level(get_spells)
bool get_spells;
{
    register int i, j, add = 0;
    register unsigned long exp;
    long retval;	/* Return value */
    int nsides = 0;

    /* See if we are past the doubling stage */
    exp = e_levels[player.t_ctype].cap;
    if (pstats.s_exp >= exp) {
	i = pstats.s_exp/exp;	/* First get amount above doubling area */
	retval = exp + i * exp; /* Compute next higher boundary */
	i += MAXDOUBLE;	/* Add in the previous doubled levels */
    }
    else {
	i = 0;
	exp = e_levels[player.t_ctype].base;
	while (exp <= pstats.s_exp) {
	    i++;
	    exp <<= 1;
	}
	retval = exp;
    }
    if (++i > pstats.s_lvl) {
	switch (player.t_ctype) {
	    case C_FIGHTER:	nsides = 10;
	    when C_MAGICIAN:	nsides = 4;
	    when C_CLERIC:	nsides = 8;
	    when C_THIEF:	nsides = 6;
	}

	/* Take care of multi-level jumps */
	for (j=0; j < (i-pstats.s_lvl); j++)
	    add += max(1, roll(1,nsides) + const_bonus());
	max_stats.s_hpt += add;
	if ((pstats.s_hpt += add) > max_stats.s_hpt)
	    pstats.s_hpt = max_stats.s_hpt;
	sprintf(outstring,"Welcome, %s, to level %d",
	    cnames[player.t_ctype][min(i-1, 10)], i);
	msg(outstring);
	if (get_spells) {
	    pray_time = 0;	/* A new round of prayers */
	    spell_power = 0; /* A new round of spells */
	}
    }
    pstats.s_lvl = i;
    return(retval);
}

/*
 * Used to modify the playes strength
 * it keeps track of the highest it has been, just in case
 */

chg_str(amt)
register int amt;
{
    register int ring_str;		/* ring strengths */
    register struct stats *ptr;		/* for speed */

    ptr = &pstats;
    ring_str = ring_value(R_ADDSTR);
    ptr->s_str -= ring_str;
    ptr->s_str += amt;
    if (ptr->s_str > 25)
	ptr->s_str = 25;
    if (ptr->s_str > max_stats.s_str)
	max_stats.s_str = ptr->s_str;
    ptr->s_str += ring_str;
    if (ptr->s_str <= 0)
	death(D_STRENGTH);
    updpack(TRUE);
}

/*
 * this routine computes the players current AC without dex bonus's
 */
int 
ac_compute()
{
    register int ac;

    ac  = cur_armor != NULL ? cur_armor->o_ac : pstats.s_arm;
    ac -= ring_value(R_PROTECT);
    if (cur_misc[WEAR_BRACERS] != NULL)
	ac -= cur_misc[WEAR_BRACERS]->o_ac;
    if (cur_misc[WEAR_CLOAK] != NULL)
	ac -= cur_misc[WEAR_CLOAK]->o_ac;

    /* If player has the cloak, must be wearing it */
    if (cur_relic[EMORI_CLOAK]) ac -= 5;

    if (ac > 10)
	ac = 10;
    return(ac);
}

/*
 * this routine computes the players current strength
 */
str_compute()
{
    if (cur_misc[WEAR_GAUNTLET] != NULL		&&
	cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) {
	if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
	    return (3);
	else
	    return (18);
    }
    else
	    return (pstats.s_str);
}

/*
 * this routine computes the players current dexterity
 */
dex_compute()
{
    if (cur_misc[WEAR_GAUNTLET] != NULL		&&
	cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) {
	if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
	    return (3);
	else
	    return (18);
    }
    else
	    return (pstats.s_dext);
}
    

/*
 * diag_ok:
 *	Check to see if the move is legal if it is diagonal
 */

diag_ok(sp, ep, flgptr)
register coord *sp, *ep;
struct thing *flgptr;
{
    register int numpaths = 0;

    /* Horizontal and vertical moves are always ok */
    if (ep->x == sp->x || ep->y == sp->y)
	return TRUE;

    /* Diagonal moves are not allowed if there is a horizontal or
     * vertical path to the destination
     */
    if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++;
    if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++;
    return(numpaths != 1);
}

/*
 * eat:
 *	He wants to eat something, so let him try
 */

eat()
{
    register struct linked_list *item;

    if ((item = get_item(pack, "eat", FOOD)) == NULL)
	return;
    if ((OBJPTR(item))->o_which == 1)
	msg("My, that was a yummy %s", fruit);
    else {
	if (rnd(100) > 70) {
	    msg("Yuk, this food tastes awful");

	    /* Do a check for overflow before increasing experience */
	    if (pstats.s_exp + 1L > pstats.s_exp) pstats.s_exp++;
	    check_level(TRUE);
	}
	else
	    msg("Yum, that tasted good");
    }
    if ((food_left += HUNGERTIME + rnd(400) - 200) > STOMACHSIZE)
	food_left = STOMACHSIZE;
    del_pack(item);
    hungry_state = F_OKAY;
    updpack(TRUE);
}

/*
 * pick a random position around the give (y, x) coordinates
 */
coord *
fallpos(pos, be_clear, range)
register coord *pos;
bool be_clear;
int range;
{
	register int tried, i, j;
	register char ch;
	static coord ret;
	static short masks[] = {
		0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 };

/*
 * Pick a spot at random centered on the position given by 'pos' and
 * up to 'range' squares away from 'pos'
 *
 * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE
 * inorder to be considered valid
 *
 *
 * Generate a number from 0 to 8, representing the position to pick.
 * Note that this DOES include the positon 'pos' itself
 *
 * If this position is not valid, mark it as 'tried', and pick another.
 * Whenever a position is picked that has been tried before,
 * sequentially find the next untried position. This eliminates costly
 * random number generation
 */

	tried = 0;
	while( tried != 0x1ff ) {
		i = rnd(9);
		while( tried & masks[i] )
			i = (i + 1) % 9;

		tried |= masks[i];

		for( j = 1; j <= range; j++ ) {
			ret.x = pos->x + j*grid[i].x;
			ret.y = pos->y + j*grid[i].y;

			if (ret.x == hero.x && ret.y == hero.y)
				continue; /* skip the hero */

			if (ret.x < 0 || ret.x > COLS - 1 ||
			    ret.y < 1 || ret.y > LINES - 3)
				continue; /* off the screen? */

			ch = CCHAR( winat(ret.y, ret.x) );

			/*
			 * Check to make certain the spot is valid
			 */
			switch( ch ) {
			case FLOOR:
			case PASSAGE:
				return( &ret );
			case GOLD:
			case SCROLL:
			case POTION:
			case STICK:
			case RING:
			case WEAPON:
			case ARMOR:
			case MM:
			case FOOD:
				if(!be_clear && levtype != POSTLEV)
					return( &ret );
			default:
				break;
			}
		}
	}
	return( NULL );
}


/*
 * find_mons:
 *	Find the monster from his corrdinates
 */

struct linked_list *
find_mons(y, x)
register int y;
register int x;
{
    register struct linked_list *item;
    register struct thing *th;

    for (item = mlist; item != NULL; item = next(item))
    {
	th = THINGPTR(item);
	if (th->t_pos.y == y && th->t_pos.x == x)
	    return item;
    }
    return NULL;
}

/*
 * find_obj:
 *	find the unclaimed object at y, x
 */

struct linked_list *
find_obj(y, x)
register int y;
register int x;
{
    register struct linked_list *obj;
    register struct object *op;

    for (obj = lvl_obj; obj != NULL; obj = next(obj))
    {
	op = OBJPTR(obj);
	if (op->o_pos.y == y && op->o_pos.x == x)
		return obj;
    }
    return NULL;
}


/*
 * set up the direction co_ordinate for use in varios "prefix" commands
 */
get_dir()
{
    register char *prompt;
    register bool gotit;

    prompt = terse ? "Direction?" :  "Which direction? ";
    msg(prompt);
    do
    {
	gotit = TRUE;
	switch (readchar())
	{
	    case 'h': case'H': delta.y =  0; delta.x = -1;
	    when 'j': case'J': delta.y =  1; delta.x =  0;
	    when 'k': case'K': delta.y = -1; delta.x =  0;
	    when 'l': case'L': delta.y =  0; delta.x =  1;
	    when 'y': case'Y': delta.y = -1; delta.x = -1;
	    when 'u': case'U': delta.y = -1; delta.x =  1;
	    when 'b': case'B': delta.y =  1; delta.x = -1;
	    when 'n': case'N': delta.y =  1; delta.x =  1;
	    when ESCAPE: return FALSE;