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