1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 2 /* hack.fight.c - version 1.0.3 */ 3 /* $FreeBSD: src/games/hack/hack.fight.c,v 1.5 1999/11/16 10:26:36 marcel Exp $ */ 4 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) struct monst *magr,*mdef; { 15 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) struct monst *mdef; { 72 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) 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) struct monst *mtmp; { 100 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 int tlev,dam; 112 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 struct monst *mon; 133 struct obj *obj; 134 int thrown; 135 { 136 int 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 struct monst *mtmp; 253 { 254 schar tmp; 255 boolean malive = TRUE; 256 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 if(mtmp->mimic){ 268 if(!u.ustuck && !mtmp->mflee) u.ustuck = mtmp; 269 switch(levl[u.ux+u.dx][u.uy+u.dy].scrsym){ 270 case '+': 271 pline("The door actually was a Mimic."); 272 break; 273 case '$': 274 pline("The chest was a Mimic!"); 275 break; 276 default: 277 pline("Wait! That's a Mimic!"); 278 } 279 wakeup(mtmp); /* clears mtmp->mimic */ 280 return(TRUE); 281 } 282 283 wakeup(mtmp); 284 285 if(mtmp->mhide && mtmp->mundetected){ 286 struct obj *obj; 287 288 mtmp->mundetected = 0; 289 if((obj = o_at(mtmp->mx,mtmp->my)) && !Blind) 290 pline("Wait! There's a %s hiding under %s!", 291 mdat->mname, doname(obj)); 292 return(TRUE); 293 } 294 295 tmp = u.uluck + u.ulevel + mdat->ac + abon(); 296 if(uwep) { 297 if(uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE) 298 tmp += uwep->spe; 299 if(uwep->otyp == TWO_HANDED_SWORD) tmp -= 1; 300 else if(uwep->otyp == DAGGER) tmp += 2; 301 else if(uwep->otyp == CRYSKNIFE) tmp += 3; 302 else if(uwep->otyp == SPEAR && 303 index("XDne", mdat->mlet)) tmp += 2; 304 } 305 if(mtmp->msleep) { 306 mtmp->msleep = 0; 307 tmp += 2; 308 } 309 if(mtmp->mfroz) { 310 tmp += 4; 311 if(!rn2(10)) mtmp->mfroz = 0; 312 } 313 if(mtmp->mflee) tmp += 2; 314 if(u.utrap) tmp -= 3; 315 316 /* with a lot of luggage, your agility diminishes */ 317 tmp -= (inv_weight() + 40)/20; 318 319 if(tmp <= rnd(20) && !u.uswallow){ 320 if(Blind) pline("You miss it."); 321 else pline("You miss %s.",monnam(mtmp)); 322 } else { 323 /* we hit the monster; be careful: it might die! */ 324 325 if((malive = hmon(mtmp,uwep,0)) == TRUE) { 326 /* monster still alive */ 327 if(!rn2(25) && mtmp->mhp < mtmp->mhpmax/2) { 328 mtmp->mflee = 1; 329 if(!rn2(3)) mtmp->mfleetim = rnd(100); 330 if(u.ustuck == mtmp && !u.uswallow) 331 u.ustuck = 0; 332 } 333 #ifndef NOWORM 334 if(mtmp->wormno) 335 cutworm(mtmp, u.ux+u.dx, u.uy+u.dy, 336 uwep ? uwep->otyp : 0); 337 #endif NOWORM 338 } 339 if(mdat->mlet == 'a') { 340 if(rn2(2)) { 341 pline("You are splashed by the blob's acid!"); 342 losehp_m(rnd(6), mtmp); 343 if(!rn2(30)) corrode_armor(); 344 } 345 if(!rn2(6)) corrode_weapon(); 346 } 347 } 348 if(malive && mdat->mlet == 'E' && canseemon(mtmp) 349 && !mtmp->mcan && rn2(3)) { 350 if(mtmp->mcansee) { 351 pline("You are frozen by the floating eye's gaze!"); 352 nomul((u.ulevel > 6 || rn2(4)) ? rn1(20,-21) : -200); 353 } else { 354 pline("The blinded floating eye cannot defend itself."); 355 if(!rn2(500)) if((int)u.uluck > LUCKMIN) u.uluck--; 356 } 357 } 358 return(TRUE); 359 } 360