1 /* $NetBSD: hit.c,v 1.7 2003/08/07 09:37:37 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Timothy C. Stoehr. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 #if 0 38 static char sccsid[] = "@(#)hit.c 8.1 (Berkeley) 5/31/93"; 39 #else 40 __RCSID("$NetBSD: hit.c,v 1.7 2003/08/07 09:37:37 agc Exp $"); 41 #endif 42 #endif /* not lint */ 43 44 /* 45 * hit.c 46 * 47 * This source herein may be modified and/or distributed by anybody who 48 * so desires, with the following restrictions: 49 * 1.) No portion of this notice shall be removed. 50 * 2.) Credit shall not be taken for the creation of this source. 51 * 3.) This code is not to be traded, sold, or used for personal 52 * gain or profit. 53 * 54 */ 55 56 #include "rogue.h" 57 58 object *fight_monster = 0; 59 char hit_message[80] = ""; 60 61 void 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), 90 "the %s misses", mn); 91 message(hit_message, 1); 92 hit_message[0] = 0; 93 } 94 return; 95 } 96 if (!fight_monster) { 97 sprintf(hit_message + strlen(hit_message), "the %s hit", mn); 98 message(hit_message, 1); 99 hit_message[0] = 0; 100 } 101 if (!(monster->m_flags & STATIONARY)) { 102 damage = get_damage(monster->m_damage, 1); 103 if (cur_level >= (AMULET_LEVEL * 2)) { 104 minus = (float) ((AMULET_LEVEL * 2) - cur_level); 105 } else { 106 minus = (float) get_armor_class(rogue.armor) * 3.00; 107 minus = minus/100.00 * (float) damage; 108 } 109 damage -= (short) minus; 110 } else { 111 damage = monster->stationary_damage++; 112 } 113 if (wizard) { 114 damage /= 3; 115 } 116 if (damage > 0) { 117 rogue_damage(damage, monster, 0); 118 } 119 if (monster->m_flags & SPECIAL_HIT) { 120 special_hit(monster); 121 } 122 } 123 124 void 125 rogue_hit(monster, force_hit) 126 object *monster; 127 boolean force_hit; 128 { 129 short damage, hit_chance; 130 131 if (monster) { 132 if (check_imitator(monster)) { 133 return; 134 } 135 hit_chance = force_hit ? 100 : get_hit_chance(rogue.weapon); 136 137 if (wizard) { 138 hit_chance *= 2; 139 } 140 if (!rand_percent(hit_chance)) { 141 if (!fight_monster) { 142 (void) strcpy(hit_message, "you miss "); 143 } 144 goto RET; 145 } 146 damage = get_weapon_damage(rogue.weapon); 147 if (wizard) { 148 damage *= 3; 149 } 150 if (con_mon) { 151 s_con_mon(monster); 152 } 153 if (mon_damage(monster, damage)) { /* still alive? */ 154 if (!fight_monster) { 155 (void) strcpy(hit_message, "you hit "); 156 } 157 } 158 RET: check_gold_seeker(monster); 159 wake_up(monster); 160 } 161 } 162 163 void 164 rogue_damage(d, monster, other) 165 short d; 166 object *monster; 167 short other; 168 { 169 if (d >= rogue.hp_current) { 170 rogue.hp_current = 0; 171 print_stats(STAT_HP); 172 killed_by(monster, other); 173 } 174 if (d > 0) { 175 rogue.hp_current -= d; 176 print_stats(STAT_HP); 177 } 178 } 179 180 int 181 get_damage(ds, r) 182 const char *ds; 183 boolean r; 184 { 185 int i = 0, j, n, d, total = 0; 186 187 while (ds[i]) { 188 n = get_number(ds+i); 189 while (ds[i++] != 'd') ; 190 d = get_number(ds+i); 191 while ((ds[i] != '/') && ds[i]) i++; 192 193 for (j = 0; j < n; j++) { 194 if (r) { 195 total += get_rand(1, d); 196 } else { 197 total += d; 198 } 199 } 200 if (ds[i] == '/') { 201 i++; 202 } 203 } 204 return(total); 205 } 206 207 int 208 get_w_damage(obj) 209 const object *obj; 210 { 211 char new_damage[12]; 212 int tmp_to_hit, tmp_damage; 213 int i = 0; 214 215 if ((!obj) || (obj->what_is != WEAPON)) { 216 return(-1); 217 } 218 tmp_to_hit = get_number(obj->damage) + obj->hit_enchant; 219 while (obj->damage[i++] != 'd') ; 220 tmp_damage = get_number(obj->damage + i) + obj->d_enchant; 221 222 sprintf(new_damage, "%dd%d", tmp_to_hit, tmp_damage); 223 224 return(get_damage(new_damage, 1)); 225 } 226 227 int 228 get_number(s) 229 const char *s; 230 { 231 int i = 0; 232 int total = 0; 233 234 while ((s[i] >= '0') && (s[i] <= '9')) { 235 total = (10 * total) + (s[i] - '0'); 236 i++; 237 } 238 return(total); 239 } 240 241 long 242 lget_number(s) 243 const char *s; 244 { 245 short i = 0; 246 long total = 0; 247 248 while ((s[i] >= '0') && (s[i] <= '9')) { 249 total = (10 * total) + (s[i] - '0'); 250 i++; 251 } 252 return(total); 253 } 254 255 int 256 to_hit(obj) 257 const object *obj; 258 { 259 if (!obj) { 260 return(1); 261 } 262 return(get_number(obj->damage) + obj->hit_enchant); 263 } 264 265 int 266 damage_for_strength() 267 { 268 short strength; 269 270 strength = rogue.str_current + add_strength; 271 272 if (strength <= 6) { 273 return(strength-5); 274 } 275 if (strength <= 14) { 276 return(1); 277 } 278 if (strength <= 17) { 279 return(3); 280 } 281 if (strength <= 18) { 282 return(4); 283 } 284 if (strength <= 20) { 285 return(5); 286 } 287 if (strength <= 21) { 288 return(6); 289 } 290 if (strength <= 30) { 291 return(7); 292 } 293 return(8); 294 } 295 296 int 297 mon_damage(monster, damage) 298 object *monster; 299 short damage; 300 { 301 const char *mn; 302 short row, col; 303 304 monster->hp_to_kill -= damage; 305 306 if (monster->hp_to_kill <= 0) { 307 row = monster->row; 308 col = monster->col; 309 dungeon[row][col] &= ~MONSTER; 310 mvaddch(row, col, (int) get_dungeon_char(row, col)); 311 312 fight_monster = 0; 313 cough_up(monster); 314 mn = mon_name(monster); 315 sprintf(hit_message+strlen(hit_message), "defeated the %s", mn); 316 message(hit_message, 1); 317 hit_message[0] = 0; 318 add_exp(monster->kill_exp, 1); 319 take_from_pack(monster, &level_monsters); 320 321 if (monster->m_flags & HOLDS) { 322 being_held = 0; 323 } 324 free_object(monster); 325 return(0); 326 } 327 return(1); 328 } 329 330 void 331 fight(to_the_death) 332 boolean to_the_death; 333 { 334 short ch, c, d; 335 short row, col; 336 boolean first_miss = 1; 337 short possible_damage; 338 object *monster; 339 340 ch = 0; 341 while (!is_direction(ch = rgetchar(), &d)) { 342 sound_bell(); 343 if (first_miss) { 344 message("direction?", 0); 345 first_miss = 0; 346 } 347 } 348 check_message(); 349 if (ch == CANCEL) { 350 return; 351 } 352 row = rogue.row; col = rogue.col; 353 get_dir_rc(d, &row, &col, 0); 354 355 c = mvinch(row, col); 356 if (((c < 'A') || (c > 'Z')) || 357 (!can_move(rogue.row, rogue.col, row, col))) { 358 message("I see no monster there", 0); 359 return; 360 } 361 if (!(fight_monster = object_at(&level_monsters, row, col))) { 362 return; 363 } 364 if (!(fight_monster->m_flags & STATIONARY)) { 365 possible_damage = ((get_damage(fight_monster->m_damage, 0) * 2) / 3); 366 } else { 367 possible_damage = fight_monster->stationary_damage - 1; 368 } 369 while (fight_monster) { 370 (void) one_move_rogue(ch, 0); 371 if (((!to_the_death) && (rogue.hp_current <= possible_damage)) || 372 interrupted || (!(dungeon[row][col] & MONSTER))) { 373 fight_monster = 0; 374 } else { 375 monster = object_at(&level_monsters, row, col); 376 if (monster != fight_monster) { 377 fight_monster = 0; 378 } 379 } 380 } 381 } 382 383 void 384 get_dir_rc(dir, row, col, allow_off_screen) 385 short dir; 386 short *row, *col; 387 short allow_off_screen; 388 { 389 switch(dir) { 390 case LEFT: 391 if (allow_off_screen || (*col > 0)) { 392 (*col)--; 393 } 394 break; 395 case DOWN: 396 if (allow_off_screen || (*row < (DROWS-2))) { 397 (*row)++; 398 } 399 break; 400 case UPWARD: 401 if (allow_off_screen || (*row > MIN_ROW)) { 402 (*row)--; 403 } 404 break; 405 case RIGHT: 406 if (allow_off_screen || (*col < (DCOLS-1))) { 407 (*col)++; 408 } 409 break; 410 case UPLEFT: 411 if (allow_off_screen || ((*row > MIN_ROW) && (*col > 0))) { 412 (*row)--; 413 (*col)--; 414 } 415 break; 416 case UPRIGHT: 417 if (allow_off_screen || ((*row > MIN_ROW) && (*col < (DCOLS-1)))) { 418 (*row)--; 419 (*col)++; 420 } 421 break; 422 case DOWNRIGHT: 423 if (allow_off_screen || ((*row < (DROWS-2)) && (*col < (DCOLS-1)))) { 424 (*row)++; 425 (*col)++; 426 } 427 break; 428 case DOWNLEFT: 429 if (allow_off_screen || ((*row < (DROWS-2)) && (*col > 0))) { 430 (*row)++; 431 (*col)--; 432 } 433 break; 434 } 435 } 436 437 int 438 get_hit_chance(weapon) 439 const object *weapon; 440 { 441 short hit_chance; 442 443 hit_chance = 40; 444 hit_chance += 3 * to_hit(weapon); 445 hit_chance += (((2 * rogue.exp) + (2 * ring_exp)) - r_rings); 446 return(hit_chance); 447 } 448 449 int 450 get_weapon_damage(weapon) 451 const object *weapon; 452 { 453 short damage; 454 455 damage = get_w_damage(weapon); 456 damage += damage_for_strength(); 457 damage += ((((rogue.exp + ring_exp) - r_rings) + 1) / 2); 458 return(damage); 459 } 460 461 void 462 s_con_mon(monster) 463 object *monster; 464 { 465 if (con_mon) { 466 monster->m_flags |= CONFUSED; 467 monster->moves_confused += get_rand(12, 22); 468 message("the monster appears confused", 0); 469 con_mon = 0; 470 } 471 } 472