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