1 /*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Timothy C. Stoehr. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * @(#)throw.c 8.1 (Berkeley) 5/31/93 33 * $FreeBSD: src/games/rogue/throw.c,v 1.3 1999/11/30 03:49:28 billf Exp $ 34 * $DragonFly: src/games/rogue/throw.c,v 1.3 2006/09/02 19:31:07 pavalos Exp $ 35 */ 36 37 /* 38 * throw.c 39 * 40 * This source herein may be modified and/or distributed by anybody who 41 * so desires, with the following restrictions: 42 * 1.) No portion of this notice shall be removed. 43 * 2.) Credit shall not be taken for the creation of this source. 44 * 3.) This code is not to be traded, sold, or used for personal 45 * gain or profit. 46 * 47 */ 48 49 #include "rogue.h" 50 51 extern short cur_room; 52 extern char *curse_message; 53 extern char hit_message[]; 54 55 static void flop_weapon(object *, short, short); 56 static object *get_thrown_at_monster(object *, short, short *, short *); 57 static boolean throw_at_monster(object *, object *); 58 59 void 60 throw(void) 61 { 62 short wch, d; 63 boolean first_miss = 1; 64 object *weapon; 65 short dir, row, col; 66 object *monster; 67 68 while (!is_direction(dir = rgetchar(), &d)) { 69 sound_bell(); 70 if (first_miss) { 71 message("direction? ", 0); 72 first_miss = 0; 73 } 74 } 75 check_message(); 76 if (dir == CANCEL) { 77 return; 78 } 79 if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) { 80 return; 81 } 82 check_message(); 83 84 if (!(weapon = get_letter_object(wch))) { 85 message("no such item.", 0); 86 return; 87 } 88 if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) { 89 message(curse_message, 0); 90 return; 91 } 92 row = rogue.row; col = rogue.col; 93 94 if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) { 95 unwield(rogue.weapon); 96 } else if (weapon->in_use_flags & BEING_WORN) { 97 mv_aquatars(); 98 unwear(rogue.armor); 99 print_stats(STAT_ARMOR); 100 } else if (weapon->in_use_flags & ON_EITHER_HAND) { 101 un_put_on(weapon); 102 } 103 monster = get_thrown_at_monster(weapon, d, &row, &col); 104 mvaddch(rogue.row, rogue.col, rogue.fchar); 105 refresh(); 106 107 if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))) { 108 mvaddch(row, col, get_dungeon_char(row, col)); 109 } 110 if (monster) { 111 wake_up(monster); 112 check_gold_seeker(monster); 113 114 if (!throw_at_monster(monster, weapon)) { 115 flop_weapon(weapon, row, col); 116 } 117 } else { 118 flop_weapon(weapon, row, col); 119 } 120 vanish(weapon, 1, &rogue.pack); 121 } 122 123 static boolean 124 throw_at_monster(object *monster, object *weapon) 125 { 126 short damage, hit_chance; 127 short t; 128 129 hit_chance = get_hit_chance(weapon); 130 damage = get_weapon_damage(weapon); 131 if ((weapon->which_kind == ARROW) && 132 (rogue.weapon && (rogue.weapon->which_kind == BOW))) { 133 damage += get_weapon_damage(rogue.weapon); 134 damage = ((damage * 2) / 3); 135 hit_chance += (hit_chance / 3); 136 } else if ((weapon->in_use_flags & BEING_WIELDED) && 137 ((weapon->which_kind == DAGGER) || 138 (weapon->which_kind == SHURIKEN) || 139 (weapon->which_kind == DART))) { 140 damage = ((damage * 3) / 2); 141 hit_chance += (hit_chance / 3); 142 } 143 t = weapon->quantity; 144 weapon->quantity = 1; 145 sprintf(hit_message, "the %s", name_of(weapon)); 146 weapon->quantity = t; 147 148 if (!rand_percent(hit_chance)) { 149 strcat(hit_message, "misses "); 150 return(0); 151 } 152 s_con_mon(monster); 153 strcat(hit_message, "hit "); 154 mon_damage(monster, damage); 155 return(1); 156 } 157 158 static object * 159 get_thrown_at_monster(object *obj, short dir, short *row, short *col) 160 { 161 short orow, ocol; 162 short i, ch; 163 164 orow = *row; ocol = *col; 165 166 ch = get_mask_char(obj->what_is); 167 168 for (i = 0; i < 24; i++) { 169 get_dir_rc(dir, row, col, 0); 170 if ( (((*col <= 0) || (*col >= DCOLS-1)) || 171 (dungeon[*row][*col] == NOTHING)) || 172 ((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) && 173 (!(dungeon[*row][*col] & TRAP)))) { 174 *row = orow; 175 *col = ocol; 176 return(0); 177 } 178 if ((i != 0) && rogue_can_see(orow, ocol)) { 179 mvaddch(orow, ocol, get_dungeon_char(orow, ocol)); 180 } 181 if (rogue_can_see(*row, *col)) { 182 if (!(dungeon[*row][*col] & MONSTER)) { 183 mvaddch(*row, *col, ch); 184 } 185 refresh(); 186 } 187 orow = *row; ocol = *col; 188 if (dungeon[*row][*col] & MONSTER) { 189 if (!imitating(*row, *col)) { 190 return(object_at(&level_monsters, *row, *col)); 191 } 192 } 193 if (dungeon[*row][*col] & TUNNEL) { 194 i += 2; 195 } 196 } 197 return(0); 198 } 199 200 static void 201 flop_weapon(object *weapon, short row, short col) 202 { 203 object *new_weapon, *monster; 204 short i = 0; 205 char msg[80]; 206 boolean found = 0; 207 short mch, dch; 208 unsigned short mon; 209 210 while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) { 211 rand_around(i++, &row, &col); 212 if ((row > (DROWS-2)) || (row < MIN_ROW) || 213 (col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) || 214 (dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) { 215 continue; 216 } 217 found = 1; 218 break; 219 } 220 221 if (found || (i == 0)) { 222 new_weapon = alloc_object(); 223 *new_weapon = *weapon; 224 new_weapon->in_use_flags = NOT_USED; 225 new_weapon->quantity = 1; 226 new_weapon->ichar = 'L'; 227 place_at(new_weapon, row, col); 228 if (rogue_can_see(row, col) && 229 ((row != rogue.row) || (col != rogue.col))) { 230 mon = dungeon[row][col] & MONSTER; 231 dungeon[row][col] &= (~MONSTER); 232 dch = get_dungeon_char(row, col); 233 if (mon) { 234 mch = mvinch(row, col); 235 if ((monster = object_at(&level_monsters, 236 row, col)) != NULL) { 237 monster->trail_char = dch; 238 } 239 if ((mch < 'A') || (mch > 'Z')) { 240 mvaddch(row, col, dch); 241 } 242 } else { 243 mvaddch(row, col, dch); 244 } 245 dungeon[row][col] |= mon; 246 } 247 } else { 248 short t; 249 250 t = weapon->quantity; 251 weapon->quantity = 1; 252 sprintf(msg, "the %svanishes as it hits the ground", 253 name_of(weapon)); 254 weapon->quantity = t; 255 message(msg, 0); 256 } 257 } 258 259 void 260 rand_around(short i, short *r, short *c) 261 { 262 static char pos[] = "\010\007\001\003\004\005\002\006\0"; 263 static short row, col; 264 short j; 265 266 if (i == 0) { 267 short x, y, o, t; 268 269 row = *r; 270 col = *c; 271 272 o = get_rand(1, 8); 273 274 for (j = 0; j < 5; j++) { 275 x = get_rand(0, 8); 276 y = (x + o) % 9; 277 t = pos[x]; 278 pos[x] = pos[y]; 279 pos[y] = t; 280 } 281 } 282 switch((short)pos[i]) { 283 case 0: 284 *r = row + 1; 285 *c = col + 1; 286 break; 287 case 1: 288 *r = row + 1; 289 *c = col - 1; 290 break; 291 case 2: 292 *r = row - 1; 293 *c = col + 1; 294 break; 295 case 3: 296 *r = row - 1; 297 *c = col - 1; 298 break; 299 case 4: 300 *r = row; 301 *c = col + 1; 302 break; 303 case 5: 304 *r = row + 1; 305 *c = col; 306 break; 307 case 6: 308 *r = row; 309 *c = col; 310 break; 311 case 7: 312 *r = row - 1; 313 *c = col; 314 break; 315 case 8: 316 *r = row; 317 *c = col - 1; 318 break; 319 } 320 } 321