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