Mercurial > hg > early-roguelike
view arogue5/util.c @ 245:e7aab31362af
Rogue V[345], Super-Rogue: Fix violet fungi/venus flytraps.
Violet fungi (renamed venus flytraps in Rogue V5) do an increasing
amount of damage each time they hit.  If they miss, you still suffer
the same number of HP.  This worked by keeping a counter and printing
new damage strings into monsters[5].m_stats.s_dmg, which is the
"prototype" of that particular monster.
Each individual monster has its own damage string.  Apparently these
were once char *, pointing to the same string as the prototype.  When
the s_dmg member was changed to be an internal char array, changing the
prototype's damage string no longer had any effect on actual monsters.
As a result, flytraps did no damage on a hit, or only one point in V5.
The mechanism for doing damage on a miss continued to work.
This has been fixed by overwriting the individual monster's damage
string instead of the prototype's.  It is now no longer necessary to
reset the damage string when the flytrap is killed.  The method for
resetting it when the hero teleports away had to be modified.  Comments
referencing the long-unused xstr have been removed.
| author | John "Elwin" Edwards | 
|---|---|
| date | Sun, 01 May 2016 19:39:56 -0400 | 
| parents | 56e748983fa8 | 
| children | d71e5e1f49cf | 
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 */ void aggravate(void) { 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. */ bool cansee(int y, int 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(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 */ void chg_str(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(void) { 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 */ int str_compute(void) { 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 */ int dex_compute(void) { 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 */ bool diag_ok(coord *sp, coord *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 */ void eat(void) { 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(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(int y, 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(int y, 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 */ bool get_dir(void) { 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;
