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