Mercurial > hg > early-roguelike
comparison arogue5/fight.c @ 63:0ed67132cf10
Import Advanced Rogue 5.8 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Thu, 09 Aug 2012 22:58:48 +0000 |
| parents | |
| children | 56e748983fa8 |
comparison
equal
deleted
inserted
replaced
| 62:0ef99244acb8 | 63:0ed67132cf10 |
|---|---|
| 1 /* | |
| 2 * All the fighting gets done here | |
| 3 * | |
| 4 * Advanced Rogue | |
| 5 * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
| 6 * All rights reserved. | |
| 7 * | |
| 8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
| 9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
| 10 * All rights reserved. | |
| 11 * | |
| 12 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 13 */ | |
| 14 | |
| 15 #include "curses.h" | |
| 16 #include <ctype.h> | |
| 17 #include <string.h> | |
| 18 #include "rogue.h" | |
| 19 | |
| 20 #define CONF_DAMAGE -1 | |
| 21 #define PARAL_DAMAGE -2 | |
| 22 #define DEST_DAMAGE -3 | |
| 23 | |
| 24 static const struct matrix att_mat[5] = { | |
| 25 /* Base Max_lvl, Factor, Offset, Range */ | |
| 26 { 10, 25, 2, 1, 2 }, | |
| 27 { 9, 18, 2, 1, 5 }, | |
| 28 { 10, 19, 2, 1, 3 }, | |
| 29 { 10, 21, 2, 1, 4 }, | |
| 30 { 7, 25, 1, 0, 2 } | |
| 31 }; | |
| 32 | |
| 33 /* | |
| 34 * fight: | |
| 35 * The player attacks the monster. | |
| 36 */ | |
| 37 | |
| 38 fight(mp, weap, thrown) | |
| 39 register coord *mp; | |
| 40 struct object *weap; | |
| 41 bool thrown; | |
| 42 { | |
| 43 register struct thing *tp; | |
| 44 register struct linked_list *item; | |
| 45 register bool did_hit = TRUE; | |
| 46 bool back_stab = FALSE; | |
| 47 | |
| 48 /* | |
| 49 * Find the monster we want to fight | |
| 50 */ | |
| 51 if ((item = find_mons(mp->y, mp->x)) == NULL) { | |
| 52 return(FALSE); /* must have killed him already */ | |
| 53 } | |
| 54 tp = THINGPTR(item); | |
| 55 /* | |
| 56 * Since we are fighting, things are not quiet so no healing takes | |
| 57 * place. | |
| 58 */ | |
| 59 player.t_quiet = 0; | |
| 60 tp->t_quiet = 0; | |
| 61 | |
| 62 /* | |
| 63 * if its in the wall, we can't hit it | |
| 64 */ | |
| 65 if (on(*tp, ISINWALL) && off(player, CANINWALL)) | |
| 66 return(FALSE); | |
| 67 | |
| 68 /* | |
| 69 * Let him know it was really a mimic (if it was one). | |
| 70 */ | |
| 71 if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) && | |
| 72 off(player, ISBLIND)) | |
| 73 { | |
| 74 msg("Wait! That's a %s!", monsters[tp->t_index].m_name); | |
| 75 turn_off(*tp, ISDISGUISE); | |
| 76 did_hit = thrown; | |
| 77 } | |
| 78 if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) { | |
| 79 msg("Wait! There's a %s!", monsters[tp->t_index].m_name); | |
| 80 turn_off(*tp, CANSURPRISE); | |
| 81 did_hit = thrown; | |
| 82 } | |
| 83 /* | |
| 84 * if he's a thief and the creature is asleep then he gets a chance | |
| 85 * for a backstab | |
| 86 */ | |
| 87 if (player.t_ctype == C_THIEF && | |
| 88 (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_no_move > 0)&& | |
| 89 !on(*tp, NOSTAB)) | |
| 90 back_stab = TRUE; | |
| 91 | |
| 92 runto(tp, &hero); | |
| 93 | |
| 94 if (did_hit) | |
| 95 { | |
| 96 register const char *mname; | |
| 97 | |
| 98 did_hit = FALSE; | |
| 99 mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name; | |
| 100 if (!can_blink(tp) && | |
| 101 ( ((weap != NULL) && (weap->o_type == RELIC)) || | |
| 102 ((off(*tp, MAGICHIT) || ((weap != NULL) && (weap->o_hplus > 0 || weap->o_dplus > 0)) ) && | |
| 103 (off(*tp, BMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 1 || weap->o_dplus > 1)) ) && | |
| 104 (off(*tp, CMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 2 || weap->o_dplus > 2)) ) ) ) | |
| 105 && roll_em(&player, tp, weap, thrown, cur_weapon, back_stab)) | |
| 106 { | |
| 107 did_hit = TRUE; | |
| 108 | |
| 109 if (on(*tp, NOMETAL) && weap != NULL && | |
| 110 weap->o_type != RELIC && weap->o_flags & ISMETAL) { | |
| 111 sprintf(outstring,"Your %s passes right through the %s!", | |
| 112 weaps[weap->o_which].w_name, mname); | |
| 113 msg(outstring); | |
| 114 } | |
| 115 else if (thrown) { | |
| 116 tp->t_wasshot = TRUE; | |
| 117 thunk(weap, tp, mname); | |
| 118 } | |
| 119 else | |
| 120 hit(weap, tp, NULL, mname, back_stab); | |
| 121 | |
| 122 /* If the player hit a rust monster, he better have a + weapon */ | |
| 123 if (on(*tp, CANRUST) && !thrown && (weap != NULL) && | |
| 124 weap->o_type != RELIC && | |
| 125 (weap->o_flags & ISMETAL) && | |
| 126 !(weap->o_flags & ISPROT) && | |
| 127 (weap->o_hplus < 1) && (weap->o_dplus < 1)) { | |
| 128 if (rnd(100) < 50) weap->o_hplus--; | |
| 129 else weap->o_dplus--; | |
| 130 msg(terse ? "Your %s weakens!" | |
| 131 : "Your %s appears to be weaker now!", | |
| 132 weaps[weap->o_which].w_name); | |
| 133 } | |
| 134 | |
| 135 /* If the player hit something that shrieks, wake the dungeon */ | |
| 136 if (on(*tp, CANSHRIEK)) { | |
| 137 turn_off(*tp, CANSHRIEK); | |
| 138 msg("The %s emits a piercing shriek.", mname); | |
| 139 aggravate(); | |
| 140 } | |
| 141 | |
| 142 /* If the player hit something that can surprise, it can't now */ | |
| 143 if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE); | |
| 144 | |
| 145 | |
| 146 /* | |
| 147 * Can the player confuse? | |
| 148 */ | |
| 149 if (on(player, CANHUH) && !thrown) { | |
| 150 msg("Your hands stop glowing red"); | |
| 151 msg("The %s appears confused.", mname); | |
| 152 turn_on(*tp, ISHUH); | |
| 153 turn_off(player, CANHUH); | |
| 154 } | |
| 155 /* | |
| 156 * does the creature explode when hit? | |
| 157 */ | |
| 158 if (on(*tp, CANEXPLODE)) | |
| 159 explode(tp); | |
| 160 | |
| 161 /* | |
| 162 * Merchants just disappear if hit | |
| 163 */ | |
| 164 if (on(*tp, CANSELL)) { | |
| 165 msg("The %s disappears with his wares in a flash.",mname); | |
| 166 killed(item, FALSE, FALSE); | |
| 167 } | |
| 168 | |
| 169 else if (tp->t_stats.s_hpt <= 0) | |
| 170 killed(item, TRUE, TRUE); | |
| 171 | |
| 172 /* If the monster is fairly intelligent and about to die, it | |
| 173 * may turn tail and run. | |
| 174 */ | |
| 175 else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) && | |
| 176 (rnd(25) < tp->t_stats.s_intel)) { | |
| 177 turn_on(*tp, ISFLEE); | |
| 178 | |
| 179 /* If monster was suffocating, stop it */ | |
| 180 if (on(*tp, DIDSUFFOCATE)) { | |
| 181 turn_off(*tp, DIDSUFFOCATE); | |
| 182 extinguish(suffocate); | |
| 183 } | |
| 184 | |
| 185 /* If monster held us, stop it */ | |
| 186 if (on(*tp, DIDHOLD) && (--hold_count == 0)) | |
| 187 turn_off(player, ISHELD); | |
| 188 turn_off(*tp, DIDHOLD); | |
| 189 } | |
| 190 } | |
| 191 else { | |
| 192 if (thrown) | |
| 193 bounce(weap, tp, mname); | |
| 194 else | |
| 195 miss(weap, tp, NULL, mname); | |
| 196 } | |
| 197 } | |
| 198 count = 0; | |
| 199 return did_hit; | |
| 200 } | |
| 201 | |
| 202 /* | |
| 203 * attack: | |
| 204 * The monster attacks the player | |
| 205 */ | |
| 206 | |
| 207 attack(mp, weapon, thrown) | |
| 208 register struct thing *mp; | |
| 209 register struct object *weapon; | |
| 210 bool thrown; | |
| 211 { | |
| 212 register const char *mname; | |
| 213 register bool did_hit = FALSE; | |
| 214 register struct object *wielded; /* The wielded weapon */ | |
| 215 | |
| 216 /* | |
| 217 * Since this is an attack, stop running and any healing that was | |
| 218 * going on at the time. | |
| 219 */ | |
| 220 running = FALSE; | |
| 221 player.t_quiet = 0; | |
| 222 mp->t_quiet = 0; | |
| 223 | |
| 224 if (on(*mp, ISDISGUISE) && off(player, ISBLIND)) | |
| 225 turn_off(*mp, ISDISGUISE); | |
| 226 mname = on(player, ISBLIND) ? "it" : monsters[mp->t_index].m_name; | |
| 227 | |
| 228 /* | |
| 229 * Try to find a weapon to wield. Wield_weap will return a | |
| 230 * projector if weapon is a projectile (eg. bow for arrow). | |
| 231 * If weapon is NULL, it will try to find a suitable weapon. | |
| 232 */ | |
| 233 wielded = wield_weap(weapon, mp); | |
| 234 if (weapon == NULL) weapon = wielded; | |
| 235 | |
| 236 if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) { | |
| 237 did_hit = TRUE; | |
| 238 | |
| 239 if (thrown) m_thunk(weapon, mp, mname); | |
| 240 else hit(weapon, mp, mname, NULL, FALSE); | |
| 241 | |
| 242 if (pstats.s_hpt <= 0) | |
| 243 death(mp->t_index); /* Bye bye life ... */ | |
| 244 | |
| 245 /* | |
| 246 * suprising monsters appear after they shoot at you | |
| 247 */ | |
| 248 if (thrown) { | |
| 249 if (on(*mp, CANSURPRISE)) | |
| 250 turn_off(*mp, CANSURPRISE); | |
| 251 } | |
| 252 if (!thrown) { | |
| 253 /* | |
| 254 * If a vampire hits, it may take half your hit points | |
| 255 */ | |
| 256 if (on(*mp, CANSUCK) && !save(VS_MAGIC, &player, 0)) { | |
| 257 if (pstats.s_hpt == 1) death(mp->t_index); | |
| 258 else { | |
| 259 pstats.s_hpt /= 2; | |
| 260 msg("You feel your life force being drawn from you."); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 /* | |
| 265 * Stinking monsters make player weaker (to hit) | |
| 266 */ | |
| 267 if (on(*mp, CANSTINK)) { | |
| 268 turn_off(*mp, CANSTINK); | |
| 269 if (!save(VS_POISON, &player, 0)) { | |
| 270 msg("The stench of the %s sickens you.", mname); | |
| 271 if (on(player, HASSTINK)) lengthen(unstink, STINKTIME); | |
| 272 else { | |
| 273 turn_on(player, HASSTINK); | |
| 274 fuse(unstink, 0, STINKTIME, AFTER); | |
| 275 } | |
| 276 } | |
| 277 } | |
| 278 | |
| 279 /* | |
| 280 * Chilling monster reduces strength each time | |
| 281 */ | |
| 282 if (on(*mp, CANCHILL)) { | |
| 283 if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, &player, 0)) { | |
| 284 msg("You cringe at the %s's chilling touch.", mname); | |
| 285 chg_str(-1); | |
| 286 if (lost_str++ == 0) | |
| 287 fuse(res_strength, 0, CHILLTIME, AFTER); | |
| 288 else lengthen(res_strength, CHILLTIME); | |
| 289 } | |
| 290 } | |
| 291 | |
| 292 /* | |
| 293 * itching monsters reduce dexterity (temporarily) | |
| 294 */ | |
| 295 if (on(*mp, CANITCH) && !save(VS_POISON, &player, 0)) { | |
| 296 msg("The claws of the %s scratch you", mname); | |
| 297 if(ISWEARING(R_SUSABILITY)) { | |
| 298 msg("The scratch has no effect"); | |
| 299 } | |
| 300 else { | |
| 301 turn_on(player, HASITCH); | |
| 302 add_dexterity(TRUE); | |
| 303 lost_dext++; | |
| 304 fuse(un_itch, 0, roll(HEALTIME,SICKTIME), AFTER); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 | |
| 309 /* | |
| 310 * If a hugging monster hits, it may SQUEEEEEEEZE | |
| 311 */ | |
| 312 if (on(*mp, CANHUG)) { | |
| 313 if (roll(1,20) >= 18 || roll(1,20) >= 18) { | |
| 314 msg("The %s squeezes you against itself.", mname); | |
| 315 if ((pstats.s_hpt -= roll(2,8)) <= 0) | |
| 316 death(mp->t_index); | |
| 317 } | |
| 318 } | |
| 319 | |
| 320 /* | |
| 321 * If a disease-carrying monster hits, there is a chance the | |
| 322 * player will catch the disease | |
| 323 */ | |
| 324 if (on(*mp, CANDISEASE) && | |
| 325 (rnd(pstats.s_const) < mp->t_stats.s_lvl) && | |
| 326 off(player, HASDISEASE)) { | |
| 327 if (ISWEARING(R_HEALTH)) msg("The wound heals quickly."); | |
| 328 else { | |
| 329 turn_on(player, HASDISEASE); | |
| 330 fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER); | |
| 331 msg(terse ? "You have been diseased." | |
| 332 : "You have contracted a disease!"); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 /* | |
| 337 * If a rust monster hits, you lose armor | |
| 338 */ | |
| 339 if (on(*mp, CANRUST)) { | |
| 340 if (cur_armor != NULL && | |
| 341 cur_armor->o_which != LEATHER && | |
| 342 cur_armor->o_which != STUDDED_LEATHER && | |
| 343 cur_armor->o_which != PADDED_ARMOR && | |
| 344 !(cur_armor->o_flags & ISPROT) && | |
| 345 cur_armor->o_ac < pstats.s_arm+1 ) { | |
| 346 msg(terse ? "Your armor weakens" | |
| 347 : "Your armor appears to be weaker now. Oh my!"); | |
| 348 cur_armor->o_ac++; | |
| 349 } | |
| 350 if (cur_misc[WEAR_BRACERS] != NULL && | |
| 351 cur_misc[WEAR_BRACERS]->o_ac > 0 && | |
| 352 !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) { | |
| 353 cur_misc[WEAR_BRACERS]->o_ac--; | |
| 354 if (cur_misc[WEAR_BRACERS]->o_ac == 0) { | |
| 355 register struct linked_list *item; | |
| 356 | |
| 357 for (item=pack; item!=NULL; item=next(item)) { | |
| 358 if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) { | |
| 359 detach(pack, item); | |
| 360 o_discard(item); | |
| 361 break; | |
| 362 } | |
| 363 } | |
| 364 msg ("Your bracers crumble and fall off!"); | |
| 365 cur_misc[WEAR_BRACERS] = NULL; | |
| 366 inpack--; | |
| 367 } | |
| 368 else { | |
| 369 msg("Your bracers weaken!"); | |
