fight.c (10055B)
1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 2 /* fight.c - version 1.0.3 */ 3 4 #include <stdio.h> 5 #include "hack.h" 6 extern struct permonst li_dog, dog, la_dog; 7 extern char *exclam(), *xname(); 8 extern struct obj *mkobj_at(); 9 10 static boolean far_noise; 11 static long noisetime; 12 13 /* hitmm returns 0 (miss), 1 (hit), or 2 (kill) */ 14 hitmm(magr,mdef) register struct monst *magr,*mdef; { 15 register struct permonst *pa = magr->data, *pd = mdef->data; 16 int hit; 17 schar tmp; 18 boolean vis; 19 if(index("Eauy", pa->mlet)) return(0); 20 if(magr->mfroz) return(0); /* riv05!a3 */ 21 tmp = pd->ac + pa->mlevel; 22 if(mdef->mconf || mdef->mfroz || mdef->msleep){ 23 tmp += 4; 24 if(mdef->msleep) mdef->msleep = 0; 25 } 26 hit = (tmp > rnd(20)); 27 if(hit) mdef->msleep = 0; 28 vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my)); 29 if(vis){ 30 char buf[BUFSZ]; 31 if(mdef->mimic) seemimic(mdef); 32 if(magr->mimic) seemimic(magr); 33 (void) sprintf(buf,"%s %s", Monnam(magr), 34 hit ? "hits" : "misses"); 35 pline("%s %s.", buf, monnam(mdef)); 36 } else { 37 boolean far = (dist(magr->mx, magr->my) > 15); 38 if(far != far_noise || moves-noisetime > 10) { 39 far_noise = far; 40 noisetime = moves; 41 pline("You hear some noises%s.", 42 far ? " in the distance" : ""); 43 } 44 } 45 if(hit){ 46 if(magr->data->mlet == 'c' && !magr->cham) { 47 magr->mhpmax += 3; 48 if(vis) pline("%s is turned to stone!", Monnam(mdef)); 49 else if(mdef->mtame) 50 pline("You have a peculiarly sad feeling for a moment, then it passes."); 51 monstone(mdef); 52 hit = 2; 53 } else 54 if((mdef->mhp -= d(pa->damn,pa->damd)) < 1) { 55 magr->mhpmax += 1 + rn2(pd->mlevel+1); 56 if(magr->mtame && magr->mhpmax > 8*pa->mlevel){ 57 if(pa == &li_dog) magr->data = pa = &dog; 58 else if(pa == &dog) magr->data = pa = &la_dog; 59 } 60 if(vis) pline("%s is killed!", Monnam(mdef)); 61 else if(mdef->mtame) 62 pline("You have a sad feeling for a moment, then it passes."); 63 mondied(mdef); 64 hit = 2; 65 } 66 } 67 return(hit); 68 } 69 70 /* drop (perhaps) a cadaver and remove monster */ 71 mondied(mdef) register struct monst *mdef; { 72 register struct permonst *pd = mdef->data; 73 if(letter(pd->mlet) && rn2(3)){ 74 (void) mkobj_at(pd->mlet,mdef->mx,mdef->my); 75 if(cansee(mdef->mx,mdef->my)){ 76 unpmon(mdef); 77 atl(mdef->mx,mdef->my,fobj->olet); 78 } 79 stackobj(fobj); 80 } 81 mondead(mdef); 82 } 83 84 /* drop a rock and remove monster */ 85 monstone(mdef) register struct monst *mdef; { 86 extern char mlarge[]; 87 if(index(mlarge, mdef->data->mlet)) 88 mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my); 89 else 90 mksobj_at(ROCK, mdef->mx, mdef->my); 91 if(cansee(mdef->mx, mdef->my)){ 92 unpmon(mdef); 93 atl(mdef->mx,mdef->my,fobj->olet); 94 } 95 mondead(mdef); 96 } 97 98 99 fightm(mtmp) register struct monst *mtmp; { 100 register struct monst *mon; 101 for(mon = fmon; mon; mon = mon->nmon) if(mon != mtmp) { 102 if(DIST(mon->mx,mon->my,mtmp->mx,mtmp->my) < 3) 103 if(rn2(4)) 104 return(hitmm(mtmp,mon)); 105 } 106 return(-1); 107 } 108 109 /* u is hit by sth, but not a monster */ 110 thitu(tlev,dam,name) 111 register tlev,dam; 112 register char *name; 113 { 114 char buf[BUFSZ]; 115 setan(name,buf); 116 if(u.uac + tlev <= rnd(20)) { 117 if(Blind) pline("It misses."); 118 else pline("You are almost hit by %s!", buf); 119 return(0); 120 } else { 121 if(Blind) pline("You are hit!"); 122 else pline("You are hit by %s!", buf); 123 losehp(dam,name); 124 return(1); 125 } 126 } 127 128 char mlarge[] = "bCDdegIlmnoPSsTUwY',&"; 129 130 boolean 131 hmon(mon,obj,thrown) /* return TRUE if mon still alive */ 132 register struct monst *mon; 133 register struct obj *obj; 134 register thrown; 135 { 136 register tmp; 137 boolean hittxt = FALSE; 138 139 if(!obj){ 140 tmp = rnd(2); /* attack with bare hands */ 141 if(mon->data->mlet == 'c' && !uarmg){ 142 pline("You hit the cockatrice with your bare hands."); 143 pline("You turn to stone ..."); 144 done_in_by(mon); 145 } 146 } else if(obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) { 147 if(obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG)) 148 tmp = rnd(2); 149 else { 150 if(index(mlarge, mon->data->mlet)) { 151 tmp = rnd(objects[obj->otyp].wldam); 152 if(obj->otyp == TWO_HANDED_SWORD) tmp += d(2,6); 153 else if(obj->otyp == FLAIL) tmp += rnd(4); 154 } else { 155 tmp = rnd(objects[obj->otyp].wsdam); 156 } 157 tmp += obj->spe; 158 if(!thrown && obj == uwep && obj->otyp == BOOMERANG 159 && !rn2(3)){ 160 pline("As you hit %s, the boomerang breaks into splinters.", 161 monnam(mon)); 162 freeinv(obj); 163 setworn((struct obj *) 0, obj->owornmask); 164 obfree(obj, (struct obj *) 0); 165 tmp++; 166 } 167 } 168 if(mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD && 169 !strcmp(ONAME(obj), "Orcrist")) 170 tmp += rnd(10); 171 } else switch(obj->otyp) { 172 case HEAVY_IRON_BALL: 173 tmp = rnd(25); break; 174 case EXPENSIVE_CAMERA: 175 pline("You succeed in destroying your camera. Congratulations!"); 176 freeinv(obj); 177 if(obj->owornmask) 178 setworn((struct obj *) 0, obj->owornmask); 179 obfree(obj, (struct obj *) 0); 180 return(TRUE); 181 case DEAD_COCKATRICE: 182 pline("You hit %s with the cockatrice corpse.", 183 monnam(mon)); 184 if(mon->data->mlet == 'c') { 185 tmp = 1; 186 hittxt = TRUE; 187 break; 188 } 189 pline("%s is turned to stone!", Monnam(mon)); 190 killed(mon); 191 return(FALSE); 192 case CLOVE_OF_GARLIC: /* no effect against demons */ 193 if(index(UNDEAD, mon->data->mlet)) 194 mon->mflee = 1; 195 tmp = 1; 196 break; 197 default: 198 /* non-weapons can damage because of their weight */ 199 /* (but not too much) */ 200 tmp = obj->owt/10; 201 if(tmp < 1) tmp = 1; 202 else tmp = rnd(tmp); 203 if(tmp > 6) tmp = 6; 204 } 205 206 /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) */ 207 208 tmp += u.udaminc + dbon(); 209 if(u.uswallow) { 210 if((tmp -= u.uswldtim) <= 0) { 211 pline("Your arms are no longer able to hit."); 212 return(TRUE); 213 } 214 } 215 if(tmp < 1) tmp = 1; 216 mon->mhp -= tmp; 217 if(mon->mhp < 1) { 218 killed(mon); 219 return(FALSE); 220 } 221 if(mon->mtame && (!mon->mflee || mon->mfleetim)) { 222 mon->mflee = 1; /* Rick Richardson */ 223 mon->mfleetim += 10*rnd(tmp); 224 } 225 226 if(!hittxt) { 227 if(thrown) 228 /* this assumes that we cannot throw plural things */ 229 hit( xname(obj) /* or: objects[obj->otyp].oc_name */, 230 mon, exclam(tmp) ); 231 else if(Blind) 232 pline("You hit it."); 233 else 234 pline("You hit %s%s", monnam(mon), exclam(tmp)); 235 } 236 237 if(u.umconf && !thrown) { 238 if(!Blind) { 239 pline("Your hands stop glowing blue."); 240 if(!mon->mfroz && !mon->msleep) 241 pline("%s appears confused.",Monnam(mon)); 242 } 243 mon->mconf = 1; 244 u.umconf = 0; 245 } 246 return(TRUE); /* mon still alive */ 247 } 248 249 /* try to attack; return FALSE if monster evaded */ 250 /* u.dx and u.dy must be set */ 251 attack(mtmp) 252 register struct monst *mtmp; 253 { 254 schar tmp; 255 boolean malive = TRUE; 256 register struct permonst *mdat; 257 mdat = mtmp->data; 258 259 u_wipe_engr(3); /* andrew@orca: prevent unlimited pick-axe attacks */ 260 261 if(mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep && 262 !mtmp->mconf && mtmp->mcansee && !rn2(7) && 263 (m_move(mtmp, 0) == 2 /* he died */ || /* he moved: */ 264 mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy)) 265 return(FALSE); 266 267 #ifdef DGK 268 /* This section of code provides protection against accidentally 269 * hitting peaceful (like '@') and tame (like 'd') monsters. 270 * There is protection only if you're not blind, confused or 271 * invisible. 272 */ 273 if (flags.confirm && (mtmp->mpeaceful || mtmp->mtame) 274 && !Confusion && !Invisible) 275 if (Blind ? Telepat : (!mtmp->minvis || See_invisible)) { 276 pline("Really attack?"); 277 (void) fflush(stdout); 278 if (readchar() != 'y') { 279 flags.move = 0; 280 return(TRUE); 281 } 282 } 283 #endif 284 if(mtmp->mimic){ 285 if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp; 286 #ifdef DGK 287 if (levl[u.ux+u.dx][u.uy+u.dy].scrsym == symbol.door) 288 pline("The door actually was a Mimic."); 289 else if (levl[u.ux+u.dx][u.uy+u.dy].scrsym == '$') 290 pline("The chest was a Mimic!"); 291 else 292 pline("Wait! That's a Mimic!"); 293 #else 294 switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){ 295 case '+': 296 pline("The door actually was a Mimic."); 297 break; 298 case '$': 299 pline("The chest was a Mimic!"); 300 break; 301 default: 302 pline("Wait! That's a Mimic!"); 303 } 304 #endif 305 wakeup(mtmp); /* clears mtmp->mimic */ 306 return(TRUE); 307 } 308 309 wakeup(mtmp); 310 311 if(mtmp->mhide && mtmp->mundetected){ 312 register struct obj *obj; 313 314 mtmp->mundetected = 0; 315 if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind) 316 pline("Wait! There's a %s hiding under %s!", 317 mdat->mname, doname(obj)); 318 return(TRUE); 319 } 320 321 tmp = u.uluck + u.ulevel + mdat->ac + abon(); 322 if(uwep) { 323 if(uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE) 324 tmp += uwep->spe; 325 if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1; 326 else if(uwep->otyp == DAGGER) tmp += 2; 327 else if(uwep->otyp == CRYSKNIFE) tmp += 3; 328 else if(uwep->otyp == SPEAR && 329 index("XDne", mdat->mlet)) tmp += 2; 330 } 331 if(mtmp->msleep) { 332 mtmp->msleep = 0; 333 tmp += 2; 334 } 335 if(mtmp->mfroz) { 336 tmp += 4; 337 if(!rn2(10)) mtmp->mfroz = 0; 338 } 339 if(mtmp->mflee) tmp += 2; 340 if(u.utrap) tmp -= 3; 341 342 /* with a lot of luggage, your agility diminishes */ 343 tmp -= (inv_weight() + 40)/20; 344 345 if(tmp <= rnd(20) && !u.uswallow){ 346 if(Blind) pline("You miss it."); 347 else pline("You miss %s.",monnam(mtmp)); 348 } else { 349 /* we hit the monster; be careful: it might die! */ 350 351 if((malive = hmon(mtmp,uwep,0)) == TRUE) { 352 /* monster still alive */ 353 if(!rn2(25) && mtmp->mhp < mtmp->mhpmax/2) { 354 mtmp->mflee = 1; 355 if(!rn2(3)) mtmp->mfleetim = rnd(100); 356 if(u.ustuck == mtmp && !u.uswallow) 357 u.ustuck = 0; 358 } 359 #ifndef NOWORM 360 if(mtmp->wormno) 361 cutworm(mtmp, u.ux+u.dx, u.uy+u.dy, 362 uwep ? uwep->otyp : 0); 363 #endif /* NOWORM /**/ 364 } 365 if(mdat->mlet == 'a') { 366 if(rn2(2)) { 367 pline("You are splashed by the blob's acid!"); 368 losehp_m(rnd(6), mtmp); 369 if(!rn2(30)) corrode_armor(); 370 } 371 if(!rn2(6)) corrode_weapon(); 372 } 373 } 374 if(malive && mdat->mlet == 'E' && canseemon(mtmp) 375 && !mtmp->mcan && rn2(3)) { 376 if(mtmp->mcansee) { 377 pline("You are frozen by the floating eye's gaze!"); 378 nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200); 379 } else { 380 pline("The blinded floating eye cannot defend itself."); 381 if(!rn2(500)) if((int)u.uluck > LUCKMIN) u.uluck--; 382 } 383 } 384 return(TRUE); 385 }