view arogue7/weapons.c @ 291:5b6855d5d089

Fix a portability issue with md_hasclreol(). Some games' implementation of md_hasclreol() poked around in ncurses internals, which does not work for some ncurses build configuration. Most games did not actually call md_hasclreol(), so it was removed. There is a standard terminfo function which can retrieve the value of the clr_eol capability, so this was used for rogue5.
author John "Elwin" Edwards
date Wed, 27 Dec 2017 10:26:06 -0500
parents f9ef86cf22b2
children 28e22fb35989
line wrap: on
line source

/*
 * weapons.c - Functions for dealing with problems brought about by weapons
 *
 * Advanced Rogue
 * Copyright (C) 1984, 1985, 1986 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.
 */

/*
 * Functions for dealing with problems brought about by weapons
 *
 */

#include "curses.h"
#include <ctype.h>
#include <string.h>
#include "rogue.h"

void
boomerang(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
{
	register struct object *obj;
	struct thing midpoint;
	coord oldpos;

	obj = OBJPTR(item);
	oldpos = obj->o_pos;

	/*
	 * make it appear to fly at the target
	 */
	do_motion(obj, ydelta, xdelta, tp);
	hit_monster(unc(obj->o_pos), obj, tp);

	/*
	 * Now let's make it fly back to the wielder.  We need to
	 * use midpoint to fool do_motion into thinking the action
	 * starts there.  Do_motion only looks at the t_pos field.
	 */
	midpoint.t_pos = obj->o_pos;	/* Simulate a new start position */
	do_motion(obj, -ydelta, -xdelta, &midpoint);

	obj->o_pos = oldpos;
}

/*
 * do the actual motion on the screen done by an object traveling
 * across the room.  Note that we should not look at any field in
 * tp other than t_pos unless we change boomerang().
 */
void
do_motion(struct object *obj, int ydelta, int xdelta, struct thing *tp)
{

	/*
	* Come fly with us ...
	*/
	obj->o_pos = tp->t_pos;
	for (; ;) {
		register int ch;
		/*
		* Erase the old one
		*/
		if (!ce(obj->o_pos, tp->t_pos) &&
		    cansee(unc(obj->o_pos)) &&
		    mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') {
			mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, show(obj->o_pos.y, obj->o_pos.x));
		}
		/*
		* Get the new position
		*/
		obj->o_pos.y += ydelta;
		obj->o_pos.x += xdelta;
		if (shoot_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR && !ce(obj->o_pos, hero)) {
			/*
			* It hasn't hit anything yet, so display it
			* If it alright.
			*/
			if (cansee(unc(obj->o_pos)) &&
			    mvwinch(cw, obj->o_pos.y, obj->o_pos.x) != ' ') {
				mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type);
				draw(cw);
			}
			continue;
		}

		/*
		 * Did we stop because of a monster or the hero?  If we did 
		 * not, we want to move our position back one because we could
		 * not actually make it this far.
		 */
		if (!isalpha(ch) && 
		    !(obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)) {
		        obj->o_pos.y -= ydelta;
		        obj->o_pos.x -= xdelta;
		}

		break;
	}
}


/*
 * fall:
 *	Drop an item someplace around here.
 */

void
fall(struct linked_list *item, bool pr)
{
	register struct object *obj;
	register struct room *rp;
	register int i;
	struct object *tobj;
	struct linked_list *titem;
	coord *fpos;

	obj = OBJPTR(item);
	/*
	 * try to drop the item, look up to 3 squares away for now
	 */
	for (i=1; i<4; i++) {
	    if ((fpos = fallpos(&obj->o_pos, FALSE, i)) != NULL)
		break;
	}

	if (fpos != NULL) {
		if (obj->o_group) { /* try to add groups together */
		    for(titem=lvl_obj; titem!=NULL; titem=next(titem)) {
			tobj = OBJPTR(titem);
			if (tobj->o_group == obj->o_group	&&
			    tobj->o_pos.y == fpos->y		&&
			    tobj->o_pos.x == fpos->x) {
				tobj->o_count += obj->o_count;
				o_discard(item);
				return;
			}
		    }
		}
		mvaddch(fpos->y, fpos->x, obj->o_type);
		obj->o_pos = *fpos;
		if ((rp = roomin(&hero)) != NULL &&
		    lit_room(rp)) {
			light(&hero);
			mvwaddch(cw, hero.y, hero.x, PLAYER);
		}
		attach(lvl_obj, item);
		return;
	}
	if (pr) {
	    msg("The %s vanishes as it hits the ground.",
		weaps[obj->o_which].w_name);		
	}
	o_discard(item);
}


/*
 * Does the missile hit the monster
 */

bool
hit_monster(int y, int x, struct object *obj, struct thing *tp)
{
	static coord mp;

	mp.y = y;
	mp.x = x;
	if (tp == &player) {
		/* Make sure there is a monster where it landed */
		if (!isalpha(mvwinch(mw, y, x))) {
			return(FALSE);
		}

		/* Player hits monster */
		return(fight(&mp, obj, TRUE));
	} else {
		if (!ce(mp, hero)) {
		    /* Monster hits monster */
		    return(skirmish(tp, &mp, obj, TRUE));
		}

		/* Monster hits player */
		return(attack(tp, obj, TRUE));
	}
}

/*
 * init_weapon:
 *	Set up the initial goodies for a weapon
 */

void
init_weapon(struct object *weap, char type)
{
	register struct init_weps *iwp;

	iwp = &weaps[type];
	strncpy(weap->o_damage, iwp->w_dam, sizeof(weap->o_damage));
	strncpy(weap->o_hurldmg, iwp->w_hrl, sizeof(weap->o_hurldmg));
	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 = newgrp();
	} else {
		weap->o_count = 1;
	}
}

/*
 * missile:
 *	Fire a missile in a given direction
 */

void
missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
{
	register struct object *obj;
	register struct linked_list *nitem;
	char ch;

	/*
	* Get which thing we are hurling
	*/
	if (item == NULL) {
		return;
	}
	obj = OBJPTR(item);
	if (obj->o_type == RELIC && obj->o_which == AXE_AKLAD) {
	    boomerang(ydelta, xdelta, item, tp);
	    return;
	}

	if (!dropcheck(obj)) return;	/* Can we get rid of it? */

	if(!(obj->o_flags & ISMISL)) {
	    while (TRUE) {
		msg(terse ? "Really throw? (y or n): "
			  : "Do you really want to throw %s? (y or n): ",
				inv_name(obj, TRUE));
		mpos = 0;
		ch = readchar();
		if (ch == 'n' || ch == ESCAPE) {
		    after = FALSE;
		    return;
		}
		if (ch == 'y')
		    break;
	    }
	}
	/*
	 * 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) {
		detach(tp->t_pack, item);
		if (tp->t_pack == pack) {
			inpack--;
		}
	} 
	else {
		obj->o_count--;
		nitem = (struct linked_list *) new_item(sizeof *obj);
		obj = OBJPTR(nitem);
		*obj = *(OBJPTR(item));
		obj->o_count = 1;
		item = nitem;
	}
	updpack(FALSE, tp);
	do_motion(obj, 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(unc(obj->o_pos), obj, tp)) {
		fall(item, TRUE);
	}
	mvwaddch(cw, hero.y, hero.x, PLAYER);
}

/*
 * num:
 *	Figure out the plus number for armor/weapons
 */

char *
num(int n1, int n2)
{
	static char numbuf[LINELEN];

	if (n1 == 0 && n2 == 0) {
		return "+0";
	}
	if (n2 == 0) {
		sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1);
	} else {
		sprintf(numbuf, "%s%d, %s%d", n1 < 0 ? "" : "+", n1, n2 < 0 ? "" : "+", n2);
	}
	return(numbuf);
}

/*
 * wield:
 *	Pull out a certain weapon
 */

void
wield(void)
{
	register struct linked_list *item;
	register struct object *obj, *oweapon;

	/*
	 * It takes 2 movement periods to unwield a weapon and 2 movement
	 * periods to wield a weapon.
	 */
	if (player.t_action != C_WIELD) {
	    player.t_action = C_WIELD;
	    player.t_using = NULL;	/* Make sure this is NULL! */
	    if (cur_weapon != NULL) {
		player.t_no_move = 2 * movement(&player);
		return;
	    }
	}

	if ((oweapon = cur_weapon) != NULL) {
	    /* At this point we have waited at least 2 units */
	    if (!dropcheck(cur_weapon)) {
		    cur_weapon = oweapon;
		    player.t_action = A_NIL;
		    return;
	    }
	    if (terse)
		addmsg("Was ");
	    else
		addmsg("You were ");
	    msg("wielding %s", inv_name(oweapon, TRUE));
	}

	/* We we have something picked out? */
	if (player.t_using == NULL) {
	    /* Now, what does he want to wield? */
	    if ((item = get_item(pack, "wield", WIELDABLE, FALSE, FALSE)) == NULL) {
		    player.t_action = A_NIL;
		    after = FALSE;
		    return;
	    }
	    player.t_using = item;
	    player.t_no_move = 2 * movement(&player);
	    return;
	}

	/* We have waited our time, let's wield the weapon */
	item = player.t_using;
	player.t_using = NULL;
	player.t_action = A_NIL;

	obj = OBJPTR(item);

	if (is_current(obj)) {
		msg("Item in use.");
		after = FALSE;
		return;
	}
	if (player.t_ctype != C_FIGHTER && 
	    player.t_ctype != C_RANGER  &&
	    player.t_ctype != C_PALADIN &&
	    obj->o_type == WEAPON	&&
	   (obj->o_which == TWOSWORD  ||
	    (obj->o_which == BASWORD &&
	     player.t_ctype != C_ASSASIN))) {
		msg("Only fighter types can wield a %s", 
		    weaps[obj->o_which].w_name);
		return;
	}
	if (terse) {
		addmsg("W");
	} else {
		addmsg("You are now w");
	}
	msg("ielding %s", inv_name(obj, TRUE));
	cur_weapon = obj;
}