1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64: #include <sys/cdefs.h>
65: #ifndef lint
66: __RCSID("$NetBSD: hack.fight.c,v 1.6 2003/04/02 18:36:36 jsm Exp $");
67: #endif
68:
69: #include "hack.h"
70: #include "extern.h"
71:
72: static boolean far_noise;
73: static long noisetime;
74:
75:
76: int
77: hitmm(magr, mdef)
78: struct monst *magr, *mdef;
79: {
80: const struct permonst *pa = magr->data, *pd = mdef->data;
81: int hit;
82: schar tmp;
83: boolean vis;
84: if (strchr("Eauy", pa->mlet))
85: return (0);
86: if (magr->mfroz)
87: return (0);
88: tmp = pd->ac + pa->mlevel;
89: if (mdef->mconf || mdef->mfroz || mdef->msleep) {
90: tmp += 4;
91: if (mdef->msleep)
92: mdef->msleep = 0;
93: }
94: hit = (tmp > rnd(20));
95: if (hit)
96: mdef->msleep = 0;
97: vis = (cansee(magr->mx, magr->my) && cansee(mdef->mx, mdef->my));
98: if (vis) {
99: char buf[BUFSZ];
100: if (mdef->mimic)
101: seemimic(mdef);
102: if (magr->mimic)
103: seemimic(magr);
104: (void) sprintf(buf, "%s %s", Monnam(magr),
105: hit ? "hits" : "misses");
106: pline("%s %s.", buf, monnam(mdef));
107: } else {
108: boolean far = (dist(magr->mx, magr->my) > 15);
109: if (far != far_noise || moves - noisetime > 10) {
110: far_noise = far;
111: noisetime = moves;
112: pline("You hear some noises%s.",
113: far ? " in the distance" : "");
114: }
115: }
116: if (hit) {
117: if (magr->data->mlet == 'c' && !magr->cham) {
118: magr->mhpmax += 3;
119: if (vis)
120: pline("%s is turned to stone!", Monnam(mdef));
121: else if (mdef->mtame)
122: pline("You have a peculiarly sad feeling for a moment, then it passes.");
123: monstone(mdef);
124: hit = 2;
125: } else if ((mdef->mhp -= d(pa->damn, pa->damd)) < 1) {
126: magr->mhpmax += 1 + rn2(pd->mlevel + 1);
127: if (magr->mtame && magr->mhpmax > 8 * pa->mlevel) {
128: if (pa == &li_dog)
129: magr->data = pa = &dog;
130: else if (pa == &dog)
131: magr->data = pa = &la_dog;
132: }
133: if (vis)
134: pline("%s is killed!", Monnam(mdef));
135: else if (mdef->mtame)
136: pline("You have a sad feeling for a moment, then it passes.");
137: mondied(mdef);
138: hit = 2;
139: }
140: }
141: return (hit);
142: }
143:
144:
145: void
146: mondied(mdef)
147: struct monst *mdef;
148: {
149: const struct permonst *pd = mdef->data;
150: if (letter(pd->mlet) && rn2(3)) {
151: (void) mkobj_at(pd->mlet, mdef->mx, mdef->my);
152: if (cansee(mdef->mx, mdef->my)) {
153: unpmon(mdef);
154: atl(mdef->mx, mdef->my, fobj->olet);
155: }
156: stackobj(fobj);
157: }
158: mondead(mdef);
159: }
160:
161:
162: void
163: monstone(mdef)
164: struct monst *mdef;
165: {
166: if (strchr(mlarge, mdef->data->mlet))
167: mksobj_at(ENORMOUS_ROCK, mdef->mx, mdef->my);
168: else
169: mksobj_at(ROCK, mdef->mx, mdef->my);
170: if (cansee(mdef->mx, mdef->my)) {
171: unpmon(mdef);
172: atl(mdef->mx, mdef->my, fobj->olet);
173: }
174: mondead(mdef);
175: }
176:
177:
178: int
179: fightm(mtmp)
180: struct monst *mtmp;
181: {
182: struct monst *mon;
183: for (mon = fmon; mon; mon = mon->nmon)
184: if (mon != mtmp) {
185: if (DIST(mon->mx, mon->my, mtmp->mx, mtmp->my) < 3)
186: if (rn2(4))
187: return (hitmm(mtmp, mon));
188: }
189: return (-1);
190: }
191:
192:
193: int
194: thitu(tlev, dam, name)
195: int tlev, dam;
196: const char *name;
197: {
198: char buf[BUFSZ];
199: setan(name, buf);
200: if (u.uac + tlev <= rnd(20)) {
201: if (Blind)
202: pline("It misses.");
203: else
204: pline("You are almost hit by %s!", buf);
205: return (0);
206: } else {
207: if (Blind)
208: pline("You are hit!");
209: else
210: pline("You are hit by %s!", buf);
211: losehp(dam, name);
212: return (1);
213: }
214: }
215:
216: char mlarge[] = "bCDdegIlmnoPSsTUwY',&";
217:
218: boolean
219: hmon(mon, obj, thrown)
220: struct monst *mon;
221: struct obj *obj;
222: int thrown;
223: {
224: int tmp;
225: boolean hittxt = FALSE;
226:
227: if (!obj) {
228: tmp = rnd(2);
229: if (mon->data->mlet == 'c' && !uarmg) {
230: pline("You hit the cockatrice with your bare hands.");
231: pline("You turn to stone ...");
232: done_in_by(mon);
233: }
234: } else if (obj->olet == WEAPON_SYM || obj->otyp == PICK_AXE) {
235: if (obj == uwep && (obj->otyp > SPEAR || obj->otyp < BOOMERANG))
236: tmp = rnd(2);
237: else {
238: if (strchr(mlarge, mon->data->mlet)) {
239: tmp = rnd(objects[obj->otyp].wldam);
240: if (obj->otyp == TWO_HANDED_SWORD)
241: tmp += d(2, 6);
242: else if (obj->otyp == FLAIL)
243: tmp += rnd(4);
244: } else {
245: tmp = rnd(objects[obj->otyp].wsdam);
246: }
247: tmp += obj->spe;
248: if (!thrown && obj == uwep && obj->otyp == BOOMERANG
249: && !rn2(3)) {
250: pline("As you hit %s, the boomerang breaks into splinters.",
251: monnam(mon));
252: freeinv(obj);
253: setworn((struct obj *) 0, obj->owornmask);
254: obfree(obj, (struct obj *) 0);
255: tmp++;
256: }
257: }
258: if (mon->data->mlet == 'O' && obj->otyp == TWO_HANDED_SWORD &&
259: !strcmp(ONAME(obj), "Orcrist"))
260: tmp += rnd(10);
261: } else
262: switch (obj->otyp) {
263: case HEAVY_IRON_BALL:
264: tmp = rnd(25);
265: break;
266: case EXPENSIVE_CAMERA:
267: pline("You succeed in destroying your camera. Congratulations!");
268: freeinv(obj);
269: if (obj->owornmask)
270: setworn((struct obj *) 0, obj->owornmask);
271: obfree(obj, (struct obj *) 0);
272: return (TRUE);
273: case DEAD_COCKATRICE:
274: pline("You hit %s with the cockatrice corpse.",
275: monnam(mon));
276: if (mon->data->mlet == 'c') {
277: tmp = 1;
278: hittxt = TRUE;
279: break;
280: }
281: pline("%s is turned to stone!", Monnam(mon));
282: killed(mon);
283: return (FALSE);
284: case CLOVE_OF_GARLIC:
285: if (strchr(UNDEAD, mon->data->mlet))
286: mon->mflee = 1;
287: tmp = 1;
288: break;
289: default:
290:
291:
292: tmp = obj->owt / 10;
293: if (tmp < 1)
294: tmp = 1;
295: else
296: tmp = rnd(tmp);
297: if (tmp > 6)
298: tmp = 6;
299: }
300:
301:
302:
303: tmp += u.udaminc + dbon();
304: if (u.uswallow) {
305: if ((tmp -= u.uswldtim) <= 0) {
306: pline("Your arms are no longer able to hit.");
307: return (TRUE);
308: }
309: }
310: if (tmp < 1)
311: tmp = 1;
312: mon->mhp -= tmp;
313: if (mon->mhp < 1) {
314: killed(mon);
315: return (FALSE);
316: }
317: if (mon->mtame && (!mon->mflee || mon->mfleetim)) {
318: mon->mflee = 1;
319: mon->mfleetim += 10 * rnd(tmp);
320: }
321: if (!hittxt) {
322: if (thrown)
323:
324: hit(xname(obj) ,
325: mon, exclam(tmp));
326: else if (Blind)
327: pline("You hit it.");
328: else
329: pline("You hit %s%s", monnam(mon), exclam(tmp));
330: }
331: if (u.umconf && !thrown) {
332: if (!Blind) {
333: pline("Your hands stop glowing blue.");
334: if (!mon->mfroz && !mon->msleep)
335: pline("%s appears confused.", Monnam(mon));
336: }
337: mon->mconf = 1;
338: u.umconf = 0;
339: }
340: return (TRUE);
341: }
342:
343:
344:
345: int
346: attack(mtmp)
347: struct monst *mtmp;
348: {
349: schar tmp;
350: boolean malive = TRUE;
351: const struct permonst *mdat;
352: mdat = mtmp->data;
353:
354: u_wipe_engr(3);
355:
356:
357: if (mdat->mlet == 'L' && !mtmp->mfroz && !mtmp->msleep &&
358: !mtmp->mconf && mtmp->mcansee && !rn2(7) &&
359: (m_move(mtmp, 0) == 2 ||
360: mtmp->mx != u.ux + u.dx || mtmp->my != u.uy + u.dy))
361: return (FALSE);
362:
363: if (mtmp->mimic) {
364: if (!u.ustuck && !mtmp->mflee)
365: u.ustuck = mtmp;
366: switch (levl[u.ux + u.dx][u.uy + u.dy].scrsym) {
367: case '+':
368: pline("The door actually was a Mimic.");
369: break;
370: case '$':
371: pline("The chest was a Mimic!");
372: break;
373: default:
374: pline("Wait! That's a Mimic!");
375: }
376: wakeup(mtmp);
377: return (TRUE);
378: }
379: wakeup(mtmp);
380:
381: if (mtmp->mhide && mtmp->mundetected) {
382: struct obj *obj;
383:
384: mtmp->mundetected = 0;
385: if ((obj = o_at(mtmp->mx, mtmp->my)) && !Blind)
386: pline("Wait! There's a %s hiding under %s!",
387: mdat->mname, doname(obj));
388: return (TRUE);
389: }
390: tmp = u.uluck + u.ulevel + mdat->ac + abon();
391: if (uwep) {
392: if (uwep->olet == WEAPON_SYM || uwep->otyp == PICK_AXE)
393: tmp += uwep->spe;
394: if (uwep->otyp == TWO_HANDED_SWORD)
395: tmp -= 1;
396: else if (uwep->otyp == DAGGER)
397: tmp += 2;
398: else if (uwep->otyp == CRYSKNIFE)
399: tmp += 3;
400: else if (uwep->otyp == SPEAR &&
401: strchr("XDne", mdat->mlet))
402: tmp += 2;
403: }
404: if (mtmp->msleep) {
405: mtmp->msleep = 0;
406: tmp += 2;
407: }
408: if (mtmp->mfroz) {
409: tmp += 4;
410: if (!rn2(10))
411: mtmp->mfroz = 0;
412: }
413: if (mtmp->mflee)
414: tmp += 2;
415: if (u.utrap)
416: tmp -= 3;
417:
418:
419: tmp -= (inv_weight() + 40) / 20;
420:
421: if (tmp <= rnd(20) && !u.uswallow) {
422: if (Blind)
423: pline("You miss it.");
424: else
425: pline("You miss %s.", monnam(mtmp));
426: } else {
427:
428:
429: if ((malive = hmon(mtmp, uwep, 0)) == TRUE) {
430:
431: if (!rn2(25) && mtmp->mhp < mtmp->mhpmax / 2) {
432: mtmp->mflee = 1;
433: if (!rn2(3))
434: mtmp->mfleetim = rnd(100);
435: if (u.ustuck == mtmp && !u.uswallow)
436: u.ustuck = 0;
437: }
438: #ifndef NOWORM
439: if (mtmp->wormno)
440: cutworm(mtmp, u.ux + u.dx, u.uy + u.dy,
441: uwep ? uwep->otyp : 0);
442: #endif
443: }
444: if (mdat->mlet == 'a') {
445: if (rn2(2)) {
446: pline("You are splashed by the blob's acid!");
447: losehp_m(rnd(6), mtmp);
448: if (!rn2(30))
449: corrode_armor();
450: }
451: if (!rn2(6))
452: corrode_weapon();
453: }
454: }
455: if (malive && mdat->mlet == 'E' && canseemon(mtmp)
456: && !mtmp->mcan && rn2(3)) {
457: if (mtmp->mcansee) {
458: pline("You are frozen by the floating eye's gaze!");
459: nomul((u.ulevel > 6 || rn2(4)) ? rn1(20, -21) : -200);
460: } else {
461: pline("The blinded floating eye cannot defend itself.");
462: if (!rn2(500))
463: if ((int) u.uluck > LUCKMIN)
464: u.uluck--;
465: }
466: }
467: return (TRUE);
468: }