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 * @(#)hit.c 8.1 (Berkeley) 5/31/93 37 * $FreeBSD: src/games/rogue/hit.c,v 1.6 1999/11/30 03:49:22 billf Exp $ 38 * $DragonFly: src/games/rogue/hit.c,v 1.2 2003/06/17 04:25:24 dillon Exp $ 39 */ 40 41 /* 42 * hit.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 object *fight_monster = 0; 56 char hit_message[80] = ""; 57 58 extern short halluc, blind, cur_level; 59 extern short add_strength, ring_exp, r_rings; 60 extern boolean being_held, interrupted, wizard, con_mon; 61 62 mon_hit(monster) 63 object *monster; 64 { 65 short damage, hit_chance; 66 const char *mn; 67 float minus; 68 69 if (fight_monster && (monster != fight_monster)) { 70 fight_monster = 0; 71 } 72 monster->trow = NO_ROOM; 73 if (cur_level >= (AMULET_LEVEL * 2)) { 74 hit_chance = 100; 75 } else { 76 hit_chance = monster->m_hit_chance; 77 hit_chance -= (((2 * rogue.exp) + (2 * ring_exp)) - r_rings); 78 } 79 if (wizard) { 80 hit_chance /= 2; 81 } 82 if (!fight_monster) { 83 interrupted = 1; 84 } 85 mn = mon_name(monster); 86 87 if (!rand_percent(hit_chance)) { 88 if (!fight_monster) { 89 sprintf(hit_message + strlen(hit_message), "the %s misses", mn); 90 message(hit_message, 1); 91 hit_message[0] = 0; 92 } 93 return; 94 } 95 if (!fight_monster) { 96 sprintf(hit_message + strlen(hit_message), "the %s hit", mn); 97 message(hit_message, 1); 98 hit_message[0] = 0; 99 } 100 if (!(monster->m_flags & STATIONARY)) { 101 damage = get_damage(monster->m_damage, 1); 102 if (cur_level >= (AMULET_LEVEL * 2)) { 103 minus = (float) ((AMULET_LEVEL * 2) - cur_level); 104 } else { 105 minus = (float) get_armor_class(rogue.armor) * 3.00; 106 minus = minus/100.00 * (float) damage; 107 } 108 damage -= (short) minus; 109 } else { 110 damage = monster->stationary_damage++; 111 } 112 if (wizard) { 113 damage /= 3; 114 } 115 if (damage > 0) { 116 rogue_damage(damage, monster, 0); 117 } 118 if (monster->m_flags & SPECIAL_HIT) { 119 special_hit(monster); 120 } 121 } 122 123 rogue_hit(monster, force_hit) 124 object *monster; 125 boolean force_hit; 126 { 127 short damage, hit_chance; 128 129 if (monster) { 130 if (check_imitator(monster)) { 131 return; 132 } 133 hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon); 134 135 if (wizard) { 136 hit_chance *= 2; 137 } 138 if (!rand_percent(hit_chance)) { 139 if (!fight_monster) { 140 (void) strcpy(hit_message, "you miss "); 141 } 142 goto RET; 143 } 144 damage = get_weapon_damage(rogue.weapon); 145 if (wizard) { 146 damage *= 3; 147 } 148 if (con_mon) { 149 s_con_mon(monster); 150 } 151 if (mon_damage(monster, damage)) { /* still alive? */ 152 if (!fight_monster) { 153 (void) strcpy(hit_message, "you hit "); 154 } 155 } 156 RET: check_gold_seeker(monster); 157 wake_up(monster); 158 } 159 } 160 161 rogue_damage(d, monster, other) 162 short d; 163 object *monster; 164 short other; 165 { 166 if (d >= rogue.hp_current) { 167 rogue.hp_current = 0; 168 print_stats(STAT_HP); 169 killed_by(monster, other); 170 } 171 if (d > 0) { 172 rogue.hp_current -= d; 173 print_stats(STAT_HP); 174 } 175 } 176 177 get_damage(ds, r) 178 const char *ds; 179 boolean r; 180 { 181 int i = 0, j, n, d, total = 0; 182 183 while (ds[i]) { 184 n = get_number(ds+i); 185 while (ds[i++] != 'd') ; 186 d = get_number(ds+i); 187 while ((ds[i] != '/') && ds[i]) i++; 188 189 for (j = 0; j < n; j++) { 190 if (r) { 191 total += get_rand(1, d); 192 } else { 193 total += d; 194 } 195 } 196 if (ds[i] == '/') { 197 i++; 198 } 199 } 200 return(total); 201 } 202 203 get_w_damage(obj) 204 const object *obj; 205 { 206 char new_damage[12]; 207 int to_hit, damage; 208 int i = 0; 209 210 if ((!obj) || (obj->what_is != WEAPON)) { 211 return(-1); 212 } 213 to_hit = get_number(obj->damage) + obj->hit_enchant; 214 while (obj->damage[i++] != 'd') ; 215 damage = get_number(obj->damage + i) + obj->d_enchant; 216 217 sprintf(new_damage, "%dd%d", to_hit, damage); 218 219 return(get_damage(new_damage, 1)); 220 } 221 222 get_number(s) 223 const char *s; 224 { 225 int i = 0; 226 int total = 0; 227 228 while ((s[i] >= '0') && (s[i] <= '9')) { 229 total = (10 * total) + (s[i] - '0'); 230 i++; 231 } 232 return(total); 233 } 234 235 long 236 lget_number(s) 237 const char *s; 238 { 239 short i = 0; 240 long total = 0; 241 242 while ((s[i] >= '0') && (s[i] <= '9')) { 243 total = (10 * total) + (s[i] - '0'); 244 i++; 245 } 246 return(total); 247 } 248 249 to_hit(obj) 250 const object *obj; 251 { 252 if (!obj) { 253 return(1); 254 } 255 return(get_number(obj->damage) + obj->hit_enchant); 256 } 257 258 damage_for_strength() 259 { 260 short strength; 261 262 strength = rogue.str_current + add_strength; 263 264 if (strength <= 6) { 265 return(strength-5); 266 } 267 if (strength <= 14) { 268 return(1); 269 } 270 if (strength <= 17) { 271 return(3); 272 } 273 if (strength <= 18) { 274 return(4); 275 } 276 if (strength <= 20) { 277 return(5); 278 } 279 if (strength <= 21) { 280 return(6); 281 } 282 if (strength <= 30) { 283 return(7); 284 } 285 return(8); 286 } 287 288 mon_damage(monster, damage) 289 object *monster; 290 short damage; 291 { 292 const char *mn; 293 short row, col; 294 295 monster->hp_to_kill -= damage; 296 297 if (monster->hp_to_kill <= 0) { 298 row = monster->row; 299 col = monster->col; 300 dungeon[row][col] &= ~MONSTER; 301 mvaddch(row, col, (int) get_dungeon_char(row, col)); 302 303 fight_monster = 0; 304 cough_up(monster); 305 mn = mon_name(monster); 306 sprintf(hit_message+strlen(hit_message), "defeated the %s", mn); 307 message(hit_message, 1); 308 hit_message[0] = 0; 309 add_exp(monster->kill_exp, 1); 310 take_from_pack(monster, &level_monsters); 311 312 if (monster->m_flags & HOLDS) { 313 being_held = 0; 314 } 315 free_object(monster); 316 return(0); 317 } 318 return(1); 319 } 320 321 fight(to_the_death) 322 boolean to_the_death; 323 { 324 short ch, c, d; 325 short row, col; 326 boolean first_miss = 1; 327 short possible_damage; 328 object *monster; 329 330 while (!is_direction(ch = rgetchar(), &d)) { 331 sound_bell(); 332 if (first_miss) { 333 message("direction?", 0); 334 first_miss = 0; 335 } 336 } 337 check_message(); 338 if (ch == CANCEL) { 339 return; 340 } 341 row = rogue.row; col = rogue.col; 342 get_dir_rc(d, &row, &col, 0); 343 344 c = mvinch(row, col); 345 if (((c < 'A') || (c > 'Z')) || 346 (!can_move(rogue.row, rogue.col, row, col))) { 347 message("I see no monster there", 0); 348 return; 349 } 350 if (!(fight_monster = object_at(&level_monsters, row, col))) { 351 return; 352 } 353 if (!(fight_monster->m_flags & STATIONARY)) { 354 possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3); 355 } else { 356 possible_damage = fight_monster->stationary_damage - 1; 357 } 358 while (fight_monster) { 359 (void) one_move_rogue(ch, 0); 360 if (((!to_the_death) && (rogue.hp_current <= possible_damage)) || 361 interrupted || (!(dungeon[row][col] & MONSTER))) { 362 fight_monster = 0; 363 } else { 364 monster = object_at(&level_monsters, row, col); 365 if (monster != fight_monster) { 366 fight_monster = 0; 367 } 368 } 369 } 370 } 371 372 get_dir_rc(dir, row, col, allow_off_screen) 373 short dir; 374 short *row, *col; 375 short allow_off_screen; 376 { 377 switch(dir) { 378 case LEFT: 379 if (allow_off_screen || (*col > 0)) { 380 (*col)--; 381 } 382 break; 383 case DOWN: 384 if (allow_off_screen || (*row < (DROWS-2))) { 385 (*row)++; 386 } 387 break; 388 case UPWARD: 389 if (allow_off_screen || (*row > MIN_ROW)) { 390 (*row)--; 391 } 392 break; 393 case RIGHT: 394 if (allow_off_screen || (*col < (DCOLS-1))) { 395 (*col)++; 396 } 397 break; 398 case UPLEFT: 399 if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) { 400 (*row)--; 401 (*col)--; 402 } 403 break; 404 case UPRIGHT: 405 if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) { 406 (*row)--; 407 (*col)++; 408 } 409 break; 410 case DOWNRIGHT: 411 if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) { 412 (*row)++; 413 (*col)++; 414 } 415 break; 416 case DOWNLEFT: 417 if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) { 418 (*row)++; 419 (*col)--; 420 } 421 break; 422 } 423 } 424 425 get_hit_chance(weapon) 426 const object *weapon; 427 { 428 short hit_chance; 429 430 hit_chance = 40; 431 hit_chance += 3 * to_hit(weapon); 432 hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings); 433 return(hit_chance); 434 } 435 436 get_weapon_damage(weapon) 437 const object *weapon; 438 { 439 short damage; 440 441 damage = get_w_damage(weapon); 442 damage += damage_for_strength(); 443 damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2); 444 return(damage); 445 } 446 447 s_con_mon(monster) 448 object *monster; 449 { 450 if (con_mon) { 451 monster->m_flags |= CONFUSED; 452 monster->moves_confused += get_rand(12, 22); 453 message("the monster appears confused", 0); 454 con_mon = 0; 455 } 456 } 457