Mercurial > hg > early-roguelike
comparison rogue5/fight.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
| author | elwin |
|---|---|
| date | Mon, 24 May 2010 20:10:59 +0000 |
| parents | |
| children | e7aab31362af |
comparison
equal
deleted
inserted
replaced
| 32:2dcd75e6a736 | 33:f502bf60e6e4 |
|---|---|
| 1 /* | |
| 2 * All the fighting gets done here | |
| 3 * | |
| 4 * @(#)fight.c 4.67 (Berkeley) 09/06/83 | |
| 5 * | |
| 6 * Rogue: Exploring the Dungeons of Doom | |
| 7 * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman | |
| 8 * All rights reserved. | |
| 9 * | |
| 10 * See the file LICENSE.TXT for full copyright and licensing information. | |
| 11 */ | |
| 12 | |
| 13 #include <stdlib.h> | |
| 14 #include <curses.h> | |
| 15 #include <string.h> | |
| 16 #include <ctype.h> | |
| 17 #include "rogue.h" | |
| 18 | |
| 19 #define EQSTR(a, b) (strcmp(a, b) == 0) | |
| 20 | |
| 21 static const char *h_names[] = { /* strings for hitting */ | |
| 22 " scored an excellent hit on ", | |
| 23 " hit ", | |
| 24 " have injured ", | |
| 25 " swing and hit ", | |
| 26 " scored an excellent hit on ", | |
| 27 " hit ", | |
| 28 " has injured ", | |
| 29 " swings and hits " | |
| 30 }; | |
| 31 | |
| 32 static const char *m_names[] = { /* strings for missing */ | |
| 33 " miss", | |
| 34 " swing and miss", | |
| 35 " barely miss", | |
| 36 " don't hit", | |
| 37 " misses", | |
| 38 " swings and misses", | |
| 39 " barely misses", | |
| 40 " doesn't hit", | |
| 41 }; | |
| 42 | |
| 43 /* | |
| 44 * adjustments to hit probabilities due to strength | |
| 45 */ | |
| 46 static int str_plus[] = { | |
| 47 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, | |
| 48 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, | |
| 49 }; | |
| 50 | |
| 51 /* | |
| 52 * adjustments to damage done due to strength | |
| 53 */ | |
| 54 static int add_dam[] = { | |
| 55 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, | |
| 56 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6 | |
| 57 }; | |
| 58 | |
| 59 /* | |
| 60 * fight: | |
| 61 * The player attacks the monster. | |
| 62 */ | |
| 63 int | |
| 64 fight(const coord *mp, const THING *weap, int thrown) | |
| 65 { | |
| 66 THING *tp; | |
| 67 int did_hit = TRUE; | |
| 68 const char *mname; | |
| 69 int ch; | |
| 70 | |
| 71 /* | |
| 72 * Find the monster we want to fight | |
| 73 */ | |
| 74 if ((tp = moat(mp->y, mp->x)) == NULL) | |
| 75 { | |
| 76 #ifdef MASTER | |
| 77 debug("Fight what @ %d,%d", mp->y, mp->x); | |
| 78 #endif | |
| 79 return FALSE; | |
| 80 } | |
| 81 /* | |
| 82 * Since we are fighting, things are not quiet so no healing takes | |
| 83 * place. | |
| 84 */ | |
| 85 count = 0; | |
| 86 quiet = 0; | |
| 87 runto(mp); | |
| 88 /* | |
| 89 * Let him know it was really a xeroc (if it was one). | |
| 90 */ | |
| 91 ch = '\0'; | |
| 92 if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND)) | |
| 93 { | |
| 94 tp->t_disguise = 'X'; | |
| 95 if (on(player, ISHALU)) { | |
| 96 ch = rnd(26) + 'A'; | |
| 97 mvaddch(tp->t_pos.y, tp->t_pos.x, ch); | |
| 98 } | |
| 99 msg(choose_str("heavy! That's a nasty critter!", | |
| 100 "wait! That's a xeroc!")); | |
| 101 if (!thrown) | |
| 102 return FALSE; | |
| 103 } | |
| 104 mname = set_mname(tp); | |
| 105 did_hit = FALSE; | |
| 106 has_hit = (terse && !to_death); | |
| 107 if (roll_em(&player, tp, weap, thrown)) | |
| 108 { | |
| 109 did_hit = FALSE; | |
| 110 if (thrown) | |
| 111 thunk(weap, mname, terse); | |
| 112 else | |
| 113 hit(NULL, mname, terse); | |
| 114 if (on(player, CANHUH)) | |
| 115 { | |
| 116 did_hit = TRUE; | |
| 117 tp->t_flags |= ISHUH; | |
| 118 player.t_flags &= ~CANHUH; | |
| 119 endmsg(); | |
| 120 has_hit = FALSE; | |
| 121 msg("your hands stop glowing %s", pick_color("red")); | |
| 122 } | |
| 123 if (tp->t_stats.s_hpt <= 0) | |
| 124 killed(tp, TRUE); | |
| 125 else if (did_hit && !on(player, ISBLIND)) | |
| 126 msg("%s appears confused", mname); | |
| 127 did_hit = TRUE; | |
| 128 } | |
| 129 else | |
| 130 if (thrown) | |
| 131 bounce(weap, mname, terse); | |
| 132 else | |
| 133 miss(NULL, mname, terse); | |
| 134 return did_hit; | |
| 135 } | |
| 136 | |
| 137 /* | |
| 138 * attack: | |
| 139 * The monster attacks the player | |
| 140 */ | |
| 141 int | |
| 142 attack(THING *mp) | |
| 143 { | |
| 144 const char *mname; | |
| 145 int oldhp; | |
| 146 | |
| 147 /* | |
| 148 * Since this is an attack, stop running and any healing that was | |
| 149 * going on at the time. | |
| 150 */ | |
| 151 running = FALSE; | |
| 152 count = 0; | |
| 153 quiet = 0; | |
| 154 if (to_death && !on(*mp, ISTARGET)) | |
| 155 { | |
| 156 to_death = FALSE; | |
| 157 kamikaze = FALSE; | |
| 158 } | |
| 159 if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(player, ISBLIND)) | |
| 160 { | |
| 161 mp->t_disguise = 'X'; | |
| 162 if (on(player, ISHALU)) | |
| 163 mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A'); | |
| 164 } | |
| 165 mname = set_mname(mp); | |
| 166 oldhp = pstats.s_hpt; | |
| 167 if (roll_em(mp, &player, NULL, FALSE)) | |
| 168 { | |
| 169 if (mp->t_type != 'I') | |
| 170 { | |
| 171 if (has_hit) | |
| 172 addmsg(". "); | |
| 173 hit(mname, NULL, FALSE); | |
| 174 } | |
| 175 else | |
| 176 if (has_hit) | |
| 177 endmsg(); | |
| 178 has_hit = FALSE; | |
| 179 if (pstats.s_hpt <= 0) | |
| 180 death(mp->t_type); /* Bye bye life ... */ | |
| 181 else if (!kamikaze) | |
| 182 { | |
| 183 oldhp -= pstats.s_hpt; | |
| 184 if (oldhp > max_hit) | |
| 185 max_hit = oldhp; | |
| 186 if (pstats.s_hpt <= max_hit) | |
| 187 to_death = FALSE; | |
| 188 } | |
| 189 if (!on(*mp, ISCANC)) | |
| 190 switch (mp->t_type) | |
| 191 { | |
| 192 case 'A': | |
| 193 /* | |
| 194 * If an aquator hits, you can lose armor class. | |
| 195 */ | |
| 196 rust_armor(cur_armor); | |
| 197 when 'I': | |
| 198 /* | |
| 199 * The ice monster freezes you | |
| 200 */ | |
| 201 player.t_flags &= ~ISRUN; | |
| 202 if (!no_command) | |
| 203 { | |
| 204 addmsg("you are frozen"); | |
| 205 if (!terse) | |
| 206 addmsg(" by the %s", mname); | |
| 207 endmsg(); | |
| 208 } | |
| 209 no_command += rnd(2) + 2; | |
| 210 if (no_command > BORE_LEVEL) | |
| 211 death('h'); | |
| 212 when 'R': | |
| 213 /* | |
| 214 * Rattlesnakes have poisonous bites | |
| 215 */ | |
| 216 if (!save(VS_POISON)) | |
| 217 { | |
| 218 if (!ISWEARING(R_SUSTSTR)) | |
| 219 { | |
| 220 chg_str(-1); | |
| 221 if (!terse) | |
| 222 msg("you feel a bite in your leg and now feel weaker"); | |
| 223 else | |
| 224 msg("a bite has weakened you"); | |
| 225 } | |
| 226 else if (!to_death) | |
| 227 { | |
| 228 if (!terse) | |
| 229 msg("a bite momentarily weakens you"); | |
| 230 else | |
| 231 msg("bite has no effect"); | |
| 232 } | |
| 233 } | |
| 234 when 'W': | |
| 235 case 'V': | |
| 236 /* | |
| 237 * Wraiths might drain energy levels, and Vampires | |
| 238 * can steal max_hp | |
| 239 */ | |
| 240 if (rnd(100) < (mp->t_type == 'W' ? 15 : 30)) | |
| 241 { | |
| 242 int fewer; | |
| 243 | |
| 244 if (mp->t_type == 'W') | |
| 245 { | |
| 246 if (pstats.s_exp == 0) | |
| 247 death('W'); /* All levels gone */ | |
| 248 if (--pstats.s_lvl == 0) | |
| 249 { | |
| 250 pstats.s_exp = 0; | |
| 251 pstats.s_lvl = 1; | |
| 252 } | |
| 253 else | |
| 254 pstats.s_exp = e_levels[pstats.s_lvl-1]+1; | |
| 255 fewer = roll(1, 10); | |
| 256 } | |
| 257 else | |
| 258 fewer = roll(1, 3); | |
| 259 pstats.s_hpt -= fewer; | |
| 260 max_hp -= fewer; | |
| 261 if (pstats.s_hpt <= 0) | |
| 262 pstats.s_hpt = 1; | |
| 263 if (max_hp <= 0) | |
| 264 death(mp->t_type); | |
| 265 msg("you suddenly feel weaker"); | |
| 266 } | |
| 267 when 'F': | |
| 268 /* | |
| 269 * Venus Flytrap stops the poor guy from moving | |
| 270 */ | |
| 271 player.t_flags |= ISHELD; | |
| 272 sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++vf_hit); | |
| 273 if (--pstats.s_hpt <= 0) | |
| 274 death('F'); | |
| 275 when 'L': | |
| 276 { | |
| 277 /* | |
| 278 * Leperachaun steals some gold | |
| 279 */ | |
| 280 int lastpurse; | |
| 281 | |
| 282 lastpurse = purse; | |
| 283 purse -= GOLDCALC; | |
| 284 if (!save(VS_MAGIC)) | |
| 285 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; | |
| 286 if (purse < 0) | |
| 287 purse = 0; | |
| 288 remove_mon(&mp->t_pos, mp, FALSE); | |
| 289 mp=NULL; | |
| 290 if (purse != lastpurse) | |
| 291 msg("your purse feels lighter"); | |
| 292 } | |
| 293 when 'N': | |
| 294 { | |
| 295 THING *obj, *steal; | |
| 296 int nobj; | |
| 297 | |
| 298 /* | |
| 299 * Nymph's steal a magic item, look through the pack | |
| 300 * and pick out one we like. | |
| 301 */ | |
| 302 steal = NULL; | |
| 303 for (nobj = 0, obj = pack; obj != NULL; obj = next(obj)) | |
| 304 if (obj != cur_armor && obj != cur_weapon | |
| 305 && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] | |
| 306 && is_magic(obj) && rnd(++nobj) == 0) | |
| 307 steal = obj; | |
| 308 if (steal != NULL) | |
| 309 { | |
| 310 remove_mon(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE); | |
| 311 mp=NULL; | |
| 312 steal = leave_pack(steal, TRUE, FALSE); | |
| 313 msg("she stole %s!", inv_name(steal, TRUE)); | |
| 314 discard(steal); | |
| 315 } | |
| 316 } | |
| 317 otherwise: | |
| 318 break; | |
| 319 } | |
| 320 } | |
| 321 else if (mp->t_type != 'I') | |
| 322 { | |
| 323 if (has_hit) | |
| 324 { | |
| 325 addmsg(". "); | |
| 326 has_hit = FALSE; | |
| 327 } | |
| 328 if (mp->t_type == 'F') | |
| 329 { | |
| 330 pstats.s_hpt -= vf_hit; | |
| 331 if (pstats.s_hpt <= 0) | |
| 332 death(mp->t_type); /* Bye bye life ... */ | |
| 333 } | |
| 334 miss(mname, NULL, FALSE); | |
| 335 } | |
| 336 if (fight_flush && !to_death) | |
| 337 flush_type(); | |
| 338 count = 0; | |
| 339 status(); | |
| 340 if (mp == NULL) | |
| 341 return(-1); | |
| 342 else | |
| 343 return(0); | |
| 344 } | |
| 345 | |
| 346 /* | |
| 347 * set_mname: | |
| 348 * return the monster name for the given monster | |
| 349 */ | |
| 350 const char * | |
| 351 set_mname(const THING *tp) | |
| 352 { | |
| 353 int ch; | |
| 354 const char *mname; | |
| 355 static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' }; | |
| 356 | |
| 357 if (!see_monst(tp) && !on(player, SEEMONST)) | |
| 358 return (terse ? "it" : "something"); | |
| 359 else if (on(player, ISHALU)) | |
| 360 { | |
| 361 move(tp->t_pos.y, tp->t_pos.x); | |
| 362 ch = toascii(CCHAR(inch())); | |
| 363 if (!isupper(ch)) | |
| 364 ch = rnd(26); | |
| 365 else | |
| 366 ch -= 'A'; | |
| 367 mname = monsters[ch].m_name; | |
| 368 } | |
| 369 else | |
| 370 mname = monsters[tp->t_type - 'A'].m_name; | |
| 371 strcpy(&tbuf[4], mname); | |
| 372 return tbuf; | |
| 373 } | |
| 374 | |
| 375 /* | |
| 376 * swing: | |
| 377 * Returns true if the swing hits | |
| 378 */ | |
| 379 int | |
| 380 swing(int at_lvl, int op_arm, int wplus) | |
| 381 { | |
| 382 int res = rnd(20); | |
| 383 int need = (20 - at_lvl) - op_arm; | |
