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