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