/*
* 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;
}