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