/* weapons.c - Functions for dealing with problems brought about by weapons XRogue: Expeditions into the Dungeons of Doom Copyright (C) 1991 Robert Pietkivitch All rights reserved. Based on "Advanced Rogue" Copyright (C) 1984, 1985 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. */ #include #include #include #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) != ' ') { if (obj->o_type == MISSILE) nofont(cw); mvwaddch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type); newfont(cw); 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 = NULL; 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]; strcpy(weap->o_damage,iwp->w_dam); strcpy(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 = 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)) { for(;;) { msg(terse ? "Really throw? (y or n): " : "Do you really want to throw %s? (y or n): ", inv_name(obj, TRUE)); mpos = 0; ch = wgetch(cw); if (ch == 'n' || ch == ESC) { 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); } else o_discard(item); 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/2]; 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) { switch (rnd(3)) { case 0: msg("Only fighter types can wield the two-handed sword."); when 1: msg("Your hand does not fit the two-handed sword."); otherwise: msg("You can not wield the two-handed sword."); } return; } if (player.t_ctype != C_FIGHTER && player.t_ctype != C_ASSASSIN && player.t_ctype != C_THIEF && player.t_ctype != C_MONK && obj->o_type == WEAPON && obj->o_which == BASWORD) { switch (rnd(3)) { case 0: msg("Only thief types can wield the bastard sword."); when 1: msg("Your hand does not fit the bastard sword."); otherwise: msg("You can not wield the bastard sword."); } return; } if (terse) { addmsg("W"); } else { addmsg("You are now w"); } msg("ielding %s", inv_name(obj, TRUE)); cur_weapon = obj; }