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 */ 35 36 /* 37 * throw.c 38 * 39 * This source herein may be modified and/or distributed by anybody who 40 * so desires, with the following restrictions: 41 * 1.) No portion of this notice shall be removed. 42 * 2.) Credit shall not be taken for the creation of this source. 43 * 3.) This code is not to be traded, sold, or used for personal 44 * gain or profit. 45 * 46 */ 47 48 #include "rogue.h" 49 50 static void flop_weapon(object *, short, short); 51 static object *get_thrown_at_monster(object *, short, short *, short *); 52 static boolean throw_at_monster(object *, object *); 53 54 void 55 throw(void) 56 { 57 short wch, d; 58 boolean first_miss = 1; 59 object *weapon; 60 short dir, row, col; 61 object *monster; 62 63 while (!is_direction(dir = rgetchar(), &d)) { 64 sound_bell(); 65 if (first_miss) { 66 message("direction? ", 0); 67 first_miss = 0; 68 } 69 } 70 check_message(); 71 if (dir == CANCEL) { 72 return; 73 } 74 if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) { 75 return; 76 } 77 check_message(); 78 79 if (!(weapon = get_letter_object(wch))) { 80 message("no such item.", 0); 81 return; 82 } 83 if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) { 84 message(curse_message, 0); 85 return; 86 } 87 row = rogue.row; col = rogue.col; 88 89 if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) { 90 unwield(rogue.weapon); 91 } else if (weapon->in_use_flags & BEING_WORN) { 92 mv_aquatars(); 93 unwear(rogue.armor); 94 print_stats(STAT_ARMOR); 95 } else if (weapon->in_use_flags & ON_EITHER_HAND) { 96 un_put_on(weapon); 97 } 98 monster = get_thrown_at_monster(weapon, d, &row, &col); 99 mvaddch(rogue.row, rogue.col, rogue.fchar); 100 refresh(); 101 102 if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))) { 103 mvaddch(row, col, get_dungeon_char(row, col)); 104 } 105 if (monster) { 106 wake_up(monster); 107 check_gold_seeker(monster); 108 109 if (!throw_at_monster(monster, weapon)) { 110 flop_weapon(weapon, row, col); 111 } 112 } else { 113 flop_weapon(weapon, row, col); 114 } 115 vanish(weapon, 1, &rogue.pack); 116 } 117 118 static boolean 119 throw_at_monster(object *monster, object *weapon) 120 { 121 short damage, hit_chance; 122 short t; 123 124 hit_chance = get_hit_chance(weapon); 125 damage = get_weapon_damage(weapon); 126 if ((weapon->which_kind == ARROW) && 127 (rogue.weapon && (rogue.weapon->which_kind == BOW))) { 128 damage += get_weapon_damage(rogue.weapon); 129 damage = ((damage * 2) / 3); 130 hit_chance += (hit_chance / 3); 131 } else if ((weapon->in_use_flags & BEING_WIELDED) && 132 ((weapon->which_kind == DAGGER) || 133 (weapon->which_kind == SHURIKEN) || 134 (weapon->which_kind == DART))) { 135 damage = ((damage * 3) / 2); 136 hit_chance += (hit_chance / 3); 137 } 138 t = weapon->quantity; 139 weapon->quantity = 1; 140 sprintf(hit_message, "the %s", name_of(weapon)); 141 weapon->quantity = t; 142 143 if (!rand_percent(hit_chance)) { 144 strcat(hit_message, "misses "); 145 return(0); 146 } 147 s_con_mon(monster); 148 strcat(hit_message, "hit "); 149 mon_damage(monster, damage); 150 return(1); 151 } 152 153 static object * 154 get_thrown_at_monster(object *obj, short dir, short *row, short *col) 155 { 156 short orow, ocol; 157 short i, ch; 158 159 orow = *row; ocol = *col; 160 161 ch = get_mask_char(obj->what_is); 162 163 for (i = 0; i < 24; i++) { 164 get_dir_rc(dir, row, col, 0); 165 if ( (((*col <= 0) || (*col >= DCOLS-1)) || 166 (dungeon[*row][*col] == NOTHING)) || 167 ((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) && 168 (!(dungeon[*row][*col] & TRAP)))) { 169 *row = orow; 170 *col = ocol; 171 return(0); 172 } 173 if ((i != 0) && rogue_can_see(orow, ocol)) { 174 mvaddch(orow, ocol, get_dungeon_char(orow, ocol)); 175 } 176 if (rogue_can_see(*row, *col)) { 177 if (!(dungeon[*row][*col] & MONSTER)) { 178 mvaddch(*row, *col, ch); 179 } 180 refresh(); 181 } 182 orow = *row; ocol = *col; 183 if (dungeon[*row][*col] & MONSTER) { 184 if (!imitating(*row, *col)) { 185 return(object_at(&level_monsters, *row, *col)); 186 } 187 } 188 if (dungeon[*row][*col] & TUNNEL) { 189 i += 2; 190 } 191 } 192 return(0); 193 } 194 195 static void 196 flop_weapon(object *weapon, short row, short col) 197 { 198 object *new_weapon, *monster; 199 short i = 0; 200 char msg[80]; 201 boolean found = 0; 202 short mch, dch; 203 unsigned short mon; 204 205 while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) { 206 rand_around(i++, &row, &col); 207 if ((row > (DROWS-2)) || (row < MIN_ROW) || 208 (col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) || 209 (dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) { 210 continue; 211 } 212 found = 1; 213 break; 214 } 215 216 if (found || (i == 0)) { 217 new_weapon = alloc_object(); 218 *new_weapon = *weapon; 219 new_weapon->in_use_flags = NOT_USED; 220 new_weapon->quantity = 1; 221 new_weapon->ichar = 'L'; 222 place_at(new_weapon, row, col); 223 if (rogue_can_see(row, col) && 224 ((row != rogue.row) || (col != rogue.col))) { 225 mon = dungeon[row][col] & MONSTER; 226 dungeon[row][col] &= (~MONSTER); 227 dch = get_dungeon_char(row, col); 228 if (mon) { 229 mch = mvinch(row, col); 230 if ((monster = object_at(&level_monsters, 231 row, col)) != NULL) { 232 monster->trail_char = dch; 233 } 234 if ((mch < 'A') || (mch > 'Z')) { 235 mvaddch(row, col, dch); 236 } 237 } else { 238 mvaddch(row, col, dch); 239 } 240 dungeon[row][col] |= mon; 241 } 242 } else { 243 short t; 244 245 t = weapon->quantity; 246 weapon->quantity = 1; 247 sprintf(msg, "the %svanishes as it hits the ground", 248 name_of(weapon)); 249 weapon->quantity = t; 250 message(msg, 0); 251 } 252 } 253 254 void 255 rand_around(short i, short *r, short *c) 256 { 257 static char pos[] = "\010\007\001\003\004\005\002\006\0"; 258 static short row, col; 259 short j; 260 261 if (i == 0) { 262 short x, y, o, t; 263 264 row = *r; 265 col = *c; 266 267 o = get_rand(1, 8); 268 269 for (j = 0; j < 5; j++) { 270 x = get_rand(0, 8); 271 y = (x + o) % 9; 272 t = pos[x]; 273 pos[x] = pos[y]; 274 pos[y] = t; 275 } 276 } 277 switch((short)pos[i]) { 278 case 0: 279 *r = row + 1; 280 *c = col + 1; 281 break; 282 case 1: 283 *r = row + 1; 284 *c = col - 1; 285 break; 286 case 2: 287 *r = row - 1; 288 *c = col + 1; 289 break; 290 case 3: 291 *r = row - 1; 292 *c = col - 1; 293 break; 294 case 4: 295 *r = row; 296 *c = col + 1; 297 break; 298 case 5: 299 *r = row + 1; 300 *c = col; 301 break; 302 case 6: 303 *r = row; 304 *c = col; 305 break; 306 case 7: 307 *r = row - 1; 308 *c = col; 309 break; 310 case 8: 311 *r = row; 312 *c = col - 1; 313 break; 314 } 315 } 316