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