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 */
+