Mercurial > hg > early-roguelike
view urogue/fight.c @ 310:827441d05b3e
Advanced Rogue family: fix some potential buffer overflows.
Some code for determining the score file location assumed that PATH_MAX
would be less than 1024, which cannot be guaranteed.
Advanced Rogue 5 and 7, and XRogue, have had the buffers for the file
name enlarged. UltraRogue never called the functions, so the code has
been deleted instead.
author | John "Elwin" Edwards |
---|---|
date | Mon, 03 May 2021 19:05:37 -0400 |
parents | e52a8a7ad4c5 |
children |
line wrap: on
line source
/* fight.c - All the fighting gets done here UltraRogue: The Ultimate Adventure in the Dungeons of Doom Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong All rights reserved. Based on "Advanced Rogue" Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka 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 <stdlib.h> #include <string.h> #include <ctype.h> #include "rogue.h" /* * This are the beginning experience levels for all players all further * experience levels are computed by multiplying by 2 */ static long e_levels[10] = { 143L, /* Fighter */ 182L, /* Paladin */ 169L, /* Ranger */ 127L, /* Cleric */ 154L, /* Druid */ 185L, /* Magician */ 169L, /* Illusionist */ 112L, /* Thief */ 126L, /* Assasin */ 319L /* Ninja */ }; static struct matrix att_mat[11] = { /* Base, Max_lvl, Factor, Offset, Range */ { 10, 17, 2, 1, 2 }, /* fi */ { 10, 17, 2, 1, 2 }, /* pa */ { 10, 17, 2, 1, 2 }, /* ra */ { 10, 19, 2, 1, 3 }, /* cl */ { 10, 19, 2, 1, 3 }, /* dr */ { 9, 21, 2, 1, 5 }, /* mu */ { 9, 21, 2, 1, 5 }, /* il */ { 10, 21, 2, 1, 4 }, /* th */ { 10, 21, 2, 1, 4 }, /* as */ { 10, 21, 2, 1, 4 }, /* nj */ { 7, 25, 1, 0, 2 } /* mn */ }; void do_fight(coord dir, int tothedeath) { int x,y; x = dir.x; y = dir.y; if (!tothedeath && pstats.s_hpt < max_stats.s_hpt / 3) { msg("That's not wise."); after = fighting = FALSE; return; } if (isalpha(CCHAR(winat(hero.y + y, hero.x + x)))) { after = fighting = TRUE; do_move(y, x); } else { if (fighting == FALSE) msg("Nothing there."); after = fighting = FALSE; } return; } /* fight() The player attacks the monster. */ int fight(coord *mp, struct object *weap, int thrown) { struct thing *tp; struct linked_list *item; int did_hit = TRUE; char *mname; /* Find the monster we want to fight */ if ((item = find_mons(mp->y, mp->x)) == NULL) { debug("Fight what @ %d,%d", mp->y, mp->x); return 0; } tp = THINGPTR(item); mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name; /* Since we are fighting, things are not quiet so no healing takes place */ player.t_rest_hpt = player.t_rest_pow = 0; tp->t_rest_hpt = tp->t_rest_pow = 0; /* Let him know it was really a mimic (if it was one). */ if (off(player, ISBLIND)) { if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise)) { msg("Wait! That's a %s!", mname); turn_off(*tp, ISDISGUISE); did_hit = thrown; } if (on(*tp, CANSURPRISE)) { turn_off(*tp, CANSURPRISE); if ((player.t_ctype == C_RANGER && rnd(6) != 0) || (player.t_ctype == C_NINJA && rnd(pstats.s_lvl / 2) != 0)) msg("You notice a %s trying to hide!", mname); else { msg("Wait! There's a %s!", mname); did_hit = thrown; } } } /* Protection from Normal Missiles */ if (thrown && on(*tp, HASMSHIELD)) { msg("The %s slows as it approaches %s.", weaps[weap->o_which].w_name, mname); did_hit = FALSE; } if (did_hit) { did_hit = FALSE; if (!can_blink(tp) && (off(*tp, MAGICHIT) || (weap != NULL && (weap->o_hplus > 0 || weap->o_dplus > 0))) && (off(*tp, BMAGICHIT) || (weap != NULL && (weap->o_hplus > 2 || weap->o_dplus > 2))) && roll_em(&player, tp, weap, thrown, cur_weapon)) { did_hit = TRUE; tp->t_wasshot = TRUE; if (thrown) { if (weap != NULL && weap->o_type == WEAPON && weap->o_which == GRENADE) { hearmsg("BOOOM!"); aggravate(); } thunk(weap, mname); } else hit(mname); /* hitting a friendly monster is curtains */ if (on(*tp, ISFRIENDLY)) { turn_off(*tp, ISFRIENDLY); turn_on(*tp, ISMEAN); } /* Charmed monsters become uncharmed */ if (on(*tp, ISCHARMED)) { turn_off(*tp, ISCHARMED); turn_on(*tp, ISMEAN); } /* * If the player hit a rust monster, he better have a * + weapon */ if (on(*tp, CANRUST)) { if (!thrown && (weap != NULL) && (weap->o_flags & ISMETAL) && !(weap->o_flags & ISPROT) && !(weap->o_flags & ISSILVER) && (weap->o_hplus < 1) && (weap->o_dplus < 1)) { if (rnd(100) < 50) weap->o_hplus--; else weap->o_dplus--; msg("Your %s weakens!", weaps[weap->o_which].w_name); } else if (!thrown && weap != NULL && (weap->o_flags & ISMETAL)) msg("The rust vanishes from your %s!", weaps[weap->o_which].w_name); } /* flammable monsters die from burning weapons */ if (thrown && on(*tp, CANBBURN) && (weap->o_flags & CANBURN) && !save_throw(VS_WAND, tp)) { msg("The %s vanishes in a ball of flame.", monsters[tp->t_index].m_name); tp->t_stats.s_hpt = 0; } /* spores explode and infest hero */ if (on(*tp, CANSPORE)) { msg("The %s explodes in a cloud of dust.", monsters[tp->t_index].m_name); if (is_wearing(R_HEALTH) || player.t_ctype == C_PALADIN || (player.t_ctype == C_NINJA && pstats.s_lvl > 6) || (thrown && rnd(50) > 0) || rnd(20) > 0) { msg("The dust makes it hard to breath."); } else { msg("You have contracted a parasitic infestation!"); infest_dam++; turn_on(player, HASINFEST); } tp->t_stats.s_hpt = 0; } /* fireproof monsters laugh at you when burning weapon hits */ if (thrown && on(*tp, NOFIRE) && (weap->o_flags & CANBURN)) msg("The %s laughs as the %s bounces.", monsters[tp->t_index].m_name, weaps[weap->o_which].w_name); /* sharp weapons have no effect on NOSHARP monsters */ if (on(*tp, NOSHARP) && (weap != NULL) && (weap->o_flags & ISSHARP)) { msg("The %s has no effect on the %s!", weaps[weap->o_which].w_name, monsters[tp->t_index].m_name); fighting = FALSE; } /* metal weapons pass through NOMETAL monsters */ if (on(*tp, NOMETAL) && (weap != NULL) && (weap->o_flags & ISMETAL)) { msg("The %s passes through the %s!", weaps[weap->o_which].w_name, monsters[tp->t_index].m_name); fighting = FALSE; } /* * If the player hit something that shrieks, wake the * dungeon */ if (on(*tp, CANSHRIEK)) { turn_off(*tp, CANSHRIEK); if (on(player, CANHEAR)) { msg("You are stunned by the %s's shriek.", mname); no_command += 4 + rnd(8); } else if (off(player, ISDEAF)) msg("The %s emits a piercing shriek.", mname); else msg("The %s seems to be trying to make some noise.", mname); aggravate(); if (rnd(wizard ? 3 : 39) == 0 && cur_armor != NULL && cur_armor->o_which == CRYSTAL_ARMOR) { struct linked_list *itm; struct object *obj; for (itm = pack; itm != NULL; itm = next(itm)) { obj = OBJPTR(itm); if (obj == cur_armor) break; } if (itm == NULL) { debug("Can't find crystalline armor being worn."); } else { msg("Your armor shatters from the shriek."); cur_armor = NULL; del_pack(itm); } } } /* * If the player hit something that can surprise, it * can't now */ if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE); /* * If the player hit something that can summon, it * will try to */ summon_help(tp, NOFORCE); /* Can the player confuse? */ if (on(player, CANHUH) && !thrown) { seemsg("Your hands stop glowing red!"); seemsg("The %s appears confused.", mname); turn_on(*tp, ISHUH); turn_off(player, CANHUH); } /* Merchants just disappear if hit */ /* * increases prices and curses objects from now on * though */ if (on(*tp, CANSELL)) { msg("The %s disappears with his wares with a BOOM and a flash.", mname); killed(NULL, item, NOMESSAGE, NOPOINTS); aggravate(); luck++; } else if (tp->t_stats.s_hpt <= 0) killed(&player, item, MESSAGE, POINTS); /* * If the monster is fairly intelligent and about to * die, it may turn tail and run. */ else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt / 10)) && (rnd(25) < tp->t_stats.s_intel)) { turn_on(*tp, ISFLEE); /* If monster was suffocating, stop it */ if (on(*tp, DIDSUFFOCATE)) { turn_off(*tp, DIDSUFFOCATE); extinguish_fuse(FUSE_SUFFOCATE); } /* If monster held us, stop it */ if (on(*tp, DIDHOLD) && (--hold_count == 0)) turn_off(player, ISHELD); turn_off(*tp, DIDHOLD); if (on(*tp, CANTELEPORT)) { int rm; /* * Erase the monster from the old * position */ if (isalpha(mvwinch(cw, tp->t_pos.y, tp->t_pos.x))) mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Get a new position */ do { rm = rnd_room(); rnd_pos(&rooms[rm], &tp->t_pos); } while (winat(tp->t_pos.y, tp->t_pos.x) != FLOOR); /* Put it there */ mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, tp->t_type); tp->t_oldch = CCHAR( mvwinch(cw, tp->t_pos.y, tp->t_pos.x) ); seemsg("The %s seems to have disappeared!", mname); } } } else if (thrown) bounce(weap, mname); else miss(mname); } if (curr_mons) chase_it(mp,&player); /* after so that backstabbing can happen */ count = 0; return(did_hit); } /* attack() The monster attacks the player */ int attack(struct thing *mp, struct object *weapon, int thrown) { char *mname; int did_hit = FALSE; /* If the monster is in a wall, it cannot attack */ if (on(*mp, ISINWALL)) return (FALSE); /* If two monsters start to gang up on our hero, stop fight mode */ if (fighting) { if (beast == NULL) beast = mp; else if (beast != mp) fighting = FALSE; } /* Since this is an attack, stop running and any healing that was going on at the time. */ running = FALSE; player.t_rest_hpt = player.t_rest_pow = 0; mp->t_rest_hpt = mp->t_rest_pow = 0; if (on(*mp, ISDISGUISE) && off(player, ISBLIND)) turn_off(*mp, ISDISGUISE); mname = on(player, ISBLIND) ? "the monster" : monsters[mp->t_index].m_name; if (roll_em(mp, &player, weapon, thrown, wield_weap(weapon, mp)) && (!thrown || off(player, HASMSHIELD))) { did_hit = TRUE; m_thunk(weapon, mname); if (pstats.s_hpt <= 0) { death(mp->t_index); /* Bye bye life ... */ return TRUE; } /* surprising monsters appear after they shoot at you */ if (thrown && on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE); else if (!thrown) { /* If a vampire hits, it may take half your hit points */ if ( on(*mp, CANSUCK) && !save(VS_MAGIC) ) { if (pstats.s_hpt == 1) { death(mp->t_index); return TRUE; } else { pstats.s_hpt /= 2; msg("You feel your life force being drawn from you."); } } /* strong monsters can shatter or gong crystalline armor */ if (cur_armor != NULL && cur_armor->o_which == CRYSTAL_ARMOR) { if (rnd(mp->t_stats.s_str + (cur_armor->o_ac / 2)) > 20) { struct linked_list *item; struct object *obj; for (item = pack; item != NULL; item = next(item)) { obj = OBJPTR(item); if (obj == cur_armor) break; } if (item == NULL) { debug("Can't find crystalline armor being worn."); } else { msg("Your armor is shattered by the blow."); cur_armor = NULL; del_pack(item); } } else if (rnd(mp->t_stats.s_str) > 15) { msg("Your armor rings from the blow."); aggravate(); } } /* Stinking monsters reduce the player's strength */ if (on(*mp, CANSTINK)) { turn_off(*mp, CANSTINK); if (player.t_ctype != C_PALADIN && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12) && !save(VS_POISON)) { if (on(player, CANSCENT)) { msg("You pass out from the stench of the %s.", mname); no_command += 4 + rnd(8); } else if (off(player, ISUNSMELL)) msg("The stench of the %s sickens you.", mname); if (on(player, HASSTINK)) lengthen_fuse(FUSE_UNSTINK, STINKTIME); else { turn_on(player, HASSTINK); light_fuse(FUSE_UNSTINK, 0, STINKTIME, AFTER); } } } /* chilling monster reduces strength permanently */ if (on(*mp, CANCHILL) && (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR)) { msg("You cringe at the %s's chilling touch.", mname); if (!is_wearing(R_SUSABILITY)) { chg_str(-1, FALSE, TRUE); if (lost_str == 0) light_fuse(FUSE_RES_STRENGTH, 0, CHILLTIME, AFTER); else lengthen_fuse(FUSE_RES_STRENGTH, CHILLTIME); } } /* itching monsters reduce dexterity (temporarily) */ if (on(*mp, CANITCH) && player.t_ctype != C_PALADIN && !(player.t_ctype == C_NINJA && pstats.s_lvl > 12) && !save(VS_POISON)) { msg("The claws of the %s scratch you!", mname); if (is_wearing(R_SUSABILITY)) msg("The scratch has no effect."); else { msg("You feel a burning itch."); turn_on(player, HASITCH); chg_dext(-1, FALSE, TRUE); light_fuse(FUSE_UNITCH, 0, roll(4, 6), AFTER); } } /* a hugging monster may SQUEEEEEEEZE */ if (on(*mp, CANHUG) && (cur_armor == NULL || cur_armor->o_which != CRYSTAL_ARMOR)) { if (roll(1, 20) >= 18 || roll(1, 20) >= 18) { msg("The %s squeezes you against itself.", mname); if ((pstats.s_hpt -= roll(2, 8)) <= 0) { death(mp->t_index); return TRUE; } } } /* a trampling monster may step on the player */ if (on(*mp, CANTRAMPLE)) { if (roll(1, 20) >= 16 || roll(1, 20) >= 16) { msg("The %s steps on you.", mname); if ((pstats.s_hpt -= roll(3, mp->t_stats.s_lvl)) <= 0) { death(mp->t_index); return TRUE; } } } /* a disease-carrying monster may transmit the disease */ if (on(*mp, CANDISEASE) && (rnd(pstats.s_const) < mp->t_stats.s_lvl) && off(player, HASDISEASE)) { if (is_wearing(R_HEALTH) || (player.t_ctype == C_PALADIN) || (player.t_ctype == C_NINJA && pstats.s_lvl > 6)) msg("The wound heals quickly."); else { turn_on(player, HASDISEASE); light_fuse(FUSE_CURE_DISEASE,0,roll(4,4) * SICKTIME, AFTER); msg("You have contracted a disease!"); } } /* a rust monster will weaken your armor */ if (on(*mp, CANRUST)) { if (cur_armor != NULL && cur_armor->o_which != SOFT_LEATHER && cur_armor->o_which != HEAVY_LEATHER && cur_armor->o_which != CUIRBOLILLI && cur_armor->o_which != PADDED_ARMOR && cur_armor->o_which != CRYSTAL_ARMOR && cur_armor->o_which != MITHRIL && !(cur_armor->o_flags & ISPROT) && cur_armor->o_ac < pstats.s_arm + 1) { msg("Your armor weakens!"); cur_armor->o_ac++; } else if (cur_armor != NULL && (cur_armor->o_flags & ISPROT) && cur_armor->o_which != SOFT_LEATHER && cur_armor->o_which != HEAVY_LEATHER && cur_armor->o_which != CUIRBOLILLI && cur_armor->o_which != PADDED_ARMOR && cur_armor->o_which != CRYSTAL_ARMOR && cur_armor->o_which != MITHRIL) msg("The rust vanishes instantly!"); } /* If a surprising monster hit you, you can see it now */ if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE); /* an infesting monster will give you a parasite or rot */ if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl) { if (is_wearing(R_HEALTH) || (player.t_ctype == C_PALADIN) || (player.t_ctype == C_NINJA && pstats.s_lvl > 6)) msg("The wound quickly heals."); else { turn_off(*mp, CANINFEST); msg("You have contracted a parasitic infestation!"); infest_dam++; turn_on(player, HASINFEST); } } /* Some monsters have poisonous bites */ if (on(*mp, CANPOISON) && !save(VS_POISON)) { if (is_wearing(R_SUSABILITY) || (player.t_ctype == C_PALADIN) || (player.t_ctype == C_NINJA && pstats.s_lvl > 12)) msg("The sting has no effect on you!"); else { chg_str(-1, FALSE, FALSE); msg("You feel a sting in your arm and now feel weaker."); } } /* a hideous monster may cause fear by touching */ if (on(*mp, TOUCHFEAR)) { turn_off(*mp, TOUCHFEAR); if (!save(VS_WAND)&&!(on(player,ISFLEE)&&(player.t_chasee==mp))) { if (off(player, SUPERHERO) && (player.t_ctype != C_PALADIN)) { turn_on(player, ISFLEE); player.t_ischasing = FALSE; player.t_chasee = mp; msg("The %s's touch terrifies you.", mname); } else msg("The %s's touch feels cold and clammy.", mname); } } /* some monsters will suffocate our hero */ if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) && (find_slot(FUSE_SUFFOCATE, FUSE) == NULL)) { turn_on(*mp, DIDSUFFOCATE); msg("The %s is beginning to suffocate you.", mname); light_fuse(FUSE_SUFFOCATE, 0, roll(4, 2), AFTER); } /* don't look now, you will get turned to stone */ if (on(*mp, TOUCHSTONE)) { turn_off(*mp, TOUCHSTONE); if (on(player, CANINWALL)) msg("The %s's touch has no effect.", mname); else { if (!save(VS_PETRIFICATION) && rnd(100) < 3) { msg("Your body begins to solidify."); msg("You are turned to stone !!! --More--"); wait_for(' '); death(D_PETRIFY); return TRUE; } else