Mercurial > hg > early-roguelike
diff urogue/fight.c @ 256:c495a4f288c6
Import UltraRogue from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 31 Jan 2017 19:56:04 -0500 |
parents | |
children | 317166b49d8a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/urogue/fight.c Tue Jan 31 19:56:04 2017 -0500 @@ -0,0 +1,2175 @@ +/* + 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 */ +