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