diff urogue/weapons.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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/urogue/weapons.c	Tue Jan 31 19:56:04 2017 -0500
@@ -0,0 +1,556 @@
+/*
+    weapons.c - Functions for dealing with problems brought about by weapons
+         
+    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 <ctype.h>
+#include <string.h>
+#include "rogue.h"
+
+/*
+    missile()
+        Fire a missile in a given direction
+*/
+
+void
+missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
+{
+    struct object   *obj;
+    struct linked_list  *nitem;
+
+    if (item == NULL)   /* Get which thing we are hurling */
+        return;
+
+    obj = OBJPTR(item);
+
+    if (!dropcheck(obj) || is_current(obj))
+        return;
+
+    /*
+     * Get rid of the thing. If it is a non-multiple item object, or if
+     * it is the last thing, just drop it. Otherwise, create a new item
+     * with a count of one.
+    */
+
+    if (obj->o_count < 2)
+    {
+        if (tp->t_pack == pack)
+            rem_pack(obj);
+        else
+            detach(tp->t_pack, item);
+    }
+    else
+    {
+        obj->o_count--;
+        nitem = (struct linked_list *) new_item(sizeof *obj);
+        obj = OBJPTR(nitem);
+        *obj = *(OBJPTR(item));
+        obj->o_count = 1;
+        item = nitem;
+    }
+
+    switch (obj->o_type)
+    {
+        case ARTIFACT:
+            has_artifact &= ~(1 << obj->o_which);
+            break;
+
+        case SCROLL:
+            if (obj->o_which == S_SCARE && obj->o_flags & ISBLESSED)
+                obj->o_flags &= ~ISBLESSED;
+            else
+                obj->o_flags |= ISCURSED;
+    }
+
+    updpack();
+    obj->o_pos = do_motion(obj->o_type, ydelta, xdelta, tp);
+
+    /*
+     * AHA! Here it has hit something. If it is a wall or a door, or if
+     * it misses (combat) the monster, put it on the floor
+     */
+
+    if (!hit_monster(obj->o_pos.y, obj->o_pos.x, obj, tp))
+    {
+        if (obj->o_type == WEAPON && obj->o_which == GRENADE)
+        {
+            hearmsg("BOOOM!");
+            aggravate();
+
+            if (ntraps + 1 < 2 * MAXTRAPS &&
+                fallpos(obj->o_pos, &traps[ntraps].tr_pos))
+            {
+                mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
+                    TRAPDOOR);
+                traps[ntraps].tr_type = TRAPDOOR;
+                traps[ntraps].tr_flags = ISFOUND;
+                traps[ntraps].tr_show = TRAPDOOR;
+                ntraps++;
+                light(&hero);
+            }
+            discard(item);
+        }
+        else if (obj->o_flags & ISLOST)
+        {
+            if (obj->o_type == WEAPON)
+                addmsg("The %s", weaps[obj->o_which].w_name);
+            else
+                addmsg(inv_name(obj, LOWERCASE));
+
+            msg(" vanishes in a puff of greasy smoke.");
+            discard(item);
+        }
+        else
+        {
+            fall(&player, item, TRUE, TRUE);
+
+            if (obj->o_flags & CANRETURN)
+                msg("You have %s.", inv_name(obj, LOWERCASE));
+        }
+    }
+    else if (obj->o_flags & ISOWNED)
+    {
+        add_pack(item, NOMESSAGE);
+        msg("You have %s.", inv_name(obj, LOWERCASE));
+    }
+
+    mvwaddch(cw, hero.y, hero.x, PLAYER);
+}
+
+/*
+    do_motion()
+        do the actual motion on the screen done by an object
+        traveling across the room
+*/
+
+coord
+do_motion(int ob, int ydelta, int xdelta, struct thing *tp)
+{
+    coord pos;
+    /* Come fly with us ... */
+
+    pos = tp->t_pos;
+
+    for (;;)
+    {
+        int ch;
+
+        /* Erase the old one */
+
+        if (!ce(pos, tp->t_pos) &&
+            cansee(pos.y, pos.x) &&
+            mvwinch(cw, pos.y, pos.x) != ' ')
+        {
+            mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
+        }
+
+        /* Get the new position */
+
+        pos.y += ydelta;
+        pos.x += xdelta;
+
+        if (shoot_ok(ch = winat(pos.y, pos.x)) &&
+            ch != DOOR && !ce(pos, hero))
+        {
+            /* It hasn't hit anything yet, so display it if it alright. */
+
+            if (cansee(pos.y, pos.x) &&
+                mvwinch(cw, pos.y, pos.x) != ' ')
+            {
+                mvwaddch(cw, pos.y, pos.x, ob);
+                wrefresh(cw);
+            }
+			
+            continue;
+
+        }
+        break;
+    }
+
+    return(pos);
+}
+
+/*
+    fall()
+        Drop an item someplace around here.
+*/
+
+void
+fall(struct thing *tp, struct linked_list *item, int pr, int player_owned)
+{
+    struct object *obj;
+    struct room   *rp;
+    coord   fpos;
+
+    obj = OBJPTR(item);
+    rp = roomin(tp->t_pos);
+
+    if (player_owned && obj->o_flags & CANRETURN)
+    {
+        add_pack(item, NOMESSAGE);
+        msg("You have %s.", inv_name(obj, LOWERCASE));
+        return;
+    }
+    else if (fallpos(obj->o_pos, &fpos))
+    {
+        if (obj->o_flags & CANBURN && obj->o_type == WEAPON
+            && obj->o_which == MOLOTOV
+            && ntraps + 1 < 2 * MAXTRAPS)
+        {
+            mvaddch(fpos.y, fpos.x, FIRETRAP);
+            traps[ntraps].tr_type  = FIRETRAP;
+            traps[ntraps].tr_flags = ISFOUND;
+            traps[ntraps].tr_show  = FIRETRAP;
+            traps[ntraps].tr_pos   = fpos;
+            ntraps++;
+
+            if (rp != NULL)
+                rp->r_flags &= ~ISDARK;
+        }
+        else
+        {
+            obj->o_pos = fpos;
+            add_obj(item, fpos.y, fpos.x);
+        }
+
+        if (rp != NULL &&
+            (!(rp->r_flags & ISDARK) ||
+             (rp->r_flags & HASFIRE)))
+        {
+            light(&hero);
+            mvwaddch(cw, hero.y, hero.x, PLAYER);
+        }
+        return;
+    }
+
+    /* get here only if there isn't a place to put it */
+	
+    if (pr)
+    {
+        if (cansee(obj->o_pos.y, obj->o_pos.x))
+        {
+            if (obj->o_type == WEAPON)
+                addmsg("The %s", weaps[obj->o_which].w_name);
+            else
+                addmsg(inv_name(obj, LOWERCASE));
+
+            msg(" vanishes as it hits the ground.");
+        }
+    }
+    discard(item);
+}
+
+/*
+    init_weapon()
+        Set up the initial goodies for a weapon
+*/
+
+void
+init_weapon(struct object *weap, int type)
+{
+    struct init_weps *iwp = &weaps[type];
+
+    weap->o_damage  = iwp->w_dam;
+    weap->o_hurldmg = iwp->w_hrl;
+    weap->o_launch  = iwp->w_launch;
+    weap->o_flags   = iwp->w_flags;
+    weap->o_weight  = iwp->w_wght;
+
+    if (weap->o_flags & ISMANY)
+    {
+        weap->o_count = rnd(8) + 8; 
+        weap->o_group = ++group;
+    }
+    else
+        weap->o_count = 1;
+}
+
+/*
+    hit_monster()
+        does the missile hit the target?
+*/
+
+int
+hit_monster(int y, int x, struct object *weapon, struct thing *thrower)
+{
+    struct linked_list *mon;
+    coord target;
+
+    target.y = y;
+    target.x = x;
+
+    if (thrower == &player)
+        return(fight(&target, weapon, THROWN));
+
+    if (ce(target, hero))
+    {
+        if (good_monster(*thrower))
+        {
+            if (on(*thrower, ISFAMILIAR))
+                msg("Please get out of the way, Master!  I nearly hit you.");
+            else
+                msg("Get out of the way %s!", whoami);
+
+            return(FALSE);
+        }
+
+        return(attack(thrower, weapon, THROWN));
+    }
+
+    if ((mon = find_mons(y, x)) != NULL)
+        return(mon_mon_attack(thrower, mon, weapon, THROWN));
+    else
+        return(FALSE);
+}
+
+
+/*
+    num()
+        Figure out the plus number for armor/weapons
+*/
+
+char *
+num(int n1, int n2, char *buf)
+{
+    if (buf == NULL)
+        return("UltraRogue Error #104");
+
+    if (n1 == 0 && n2 == 0)
+    {
+        strcpy(buf,"+0");
+        return(buf);
+    }
+
+    if (n2 == 0)
+        sprintf(buf, "%s%d", n1 < 0 ? "" : "+", n1);
+    else
+        sprintf(buf, "%s%d, %s%d", n1 < 0 ? "" : "+",
+            n1, n2 < 0 ? "" : "+", n2);
+
+    return(buf);
+}
+
+/*
+    wield()
+        Pull out a certain weapon
+*/
+
+void
+wield(void)
+{
+    struct linked_list *item;
+    struct object *obj, *oweapon;
+
+    oweapon = cur_weapon;
+
+    if (!dropcheck(cur_weapon))
+    {
+        cur_weapon = oweapon;
+        return;
+    }
+
+    cur_weapon = oweapon;
+
+    if ((item = get_item("wield", WEAPON)) == NULL)
+    {
+        after = FALSE;
+        return;
+    }
+
+    obj = OBJPTR(item);
+
+    if (is_current(obj))
+    {
+        after = FALSE;
+        return;
+    }
+
+    wield_ok(&player, obj, TRUE);
+
+    msg("You are now wielding %s.", inv_name(obj, LOWERCASE));
+
+    cur_weapon = obj;
+}
+
+/*
+    fallpos()
+        pick a random position around the given (y, x) coordinates
+*/
+
+int
+fallpos(coord pos, coord *newpos) /*ARGSUSED*/
+{
+    int   y, x, cnt;
+	coord places[9];
+
+    cnt = 0;
+
+    /* look for all the places that qualify */
+
+    for (y = pos.y - 1; y <= pos.y + 1; y++)
+	{
+        for (x = pos.x - 1; x <= pos.x + 1; x++)
+        {
+            switch(CCHAR(mvwinch(stdscr,y,x)))
+            {
+                case GOLD:
+                case POTION:
+                case SCROLL:
+                case FOOD:
+                case WEAPON:
+                case ARMOR:
+                case RING:
+                case STICK:
+                case FLOOR:
+                case PASSAGE:
+                case ARTIFACT:
+                    places[cnt].y = y;
+                    places[cnt].x = x;
+                    cnt++;
+            }
+        }
+    }
+	
+	/* now, pick one of the places, if there are any */
+
+    if (cnt > 0) 
+	{
+        int which = rnd(cnt);
+
+        newpos->y = places[which].y;
+        newpos->x = places[which].x;
+
+        debug("Dropping object at %d, %d", newpos->y, newpos->x);
+    }
+	
+    return(cnt);
+}
+
+/*
+    wield_ok()
+        enforce player class weapons restrictions
+*/
+
+int
+wield_ok(struct thing *wieldee, struct object *obj, int print_message)
+{
+    int ret_val = TRUE;
+    int class_type = wieldee->t_ctype;
+
+    if (obj->o_type != WEAPON)
+    {
+        ret_val = FALSE;
+        return(ret_val);
+    }
+    else
+        switch (class_type)
+        {
+            case C_MAGICIAN: /* need one hand free */
+            case C_ILLUSION:
+                if (obj->o_flags & ISTWOH)
+                    ret_val = FALSE;
+                break;
+
+            case C_THIEF:    /* need portable weapon  */
+            case C_ASSASIN:
+            case C_NINJA:
+                if (obj->o_flags & ISTWOH)
+                    ret_val = FALSE;
+                break;
+
+            case C_CLERIC:   /* No sharp weapons */
+                if (obj->o_flags & ISSHARP)
+                    ret_val = FALSE;
+                break;
+
+            case C_DRUID:    /* No non-silver metal weapons */
+                if (obj->o_flags & ISMETAL && !(obj->o_flags & ISSILVER))
+                    ret_val = FALSE;
+                break;
+
+            case C_PALADIN:  /* must wield sharp stuff */
+                if ((obj->o_flags & ISSHARP) == FALSE)
+                    ret_val = FALSE;
+                break;
+
+            case C_FIGHTER:  /* wield anything */
+            case C_RANGER:
+            case C_MONSTER:
+                break;
+
+            default:  /* Unknown class */
+                debug("Unknown class %d.", class_type);
+                break;
+        }
+
+    if (itemweight(obj) > 18 * pstats.s_str)
+    {
+        if (wieldee == &player && print_message == TRUE)
+            msg("That is too heavy for you to swing effectively!");
+
+        ret_val = FALSE;
+        return(ret_val);
+    }
+
+    if (ret_val == FALSE && print_message == MESSAGE)
+        switch (class_type)
+        {
+            case C_MAGICIAN:
+            case C_ILLUSION:
+                msg("You'll find it hard to cast spells while wielding that!");
+                break;
+
+            case C_THIEF:
+            case C_ASSASIN:
+            case C_NINJA:
+                msg("Don't expect to backstab anyone while wielding that!");
+                break;
+
+            case C_CLERIC:
+            case C_DRUID:
+            case C_PALADIN:
+                msg("Your god strongly disapproves of your wielding that!");
+                break;
+
+            case C_FIGHTER:
+            case C_RANGER:
+            case C_MONSTER:
+                break;
+        }
+
+    return(ret_val);
+}
+
+/*
+    shoot_ok()
+        returns true if it is ok for type to shoot over ch
+*/
+
+int
+shoot_ok(int ch)
+{
+    switch(ch)
+    {
+        case ' ':
+        case '|':
+        case '-':
+        case SECRETDOOR:
+            return(FALSE);
+
+        default:
+            return(!isalpha(ch));
+    }
+}