1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.zap.c - version 1.0.3 */
3 /* $FreeBSD: src/games/hack/hack.zap.c,v 1.4 1999/11/16 10:26:38 marcel Exp $ */
4 /* $DragonFly: src/games/hack/hack.zap.c,v 1.5 2006/08/21 19:45:32 pavalos Exp $ */
8 extern struct monst youmonst
;
10 static const char *fl
[]= {
18 static void bhitm(struct monst
*, struct obj
*);
19 static bool bhito(struct obj
*, struct obj
*);
20 static char dirlet(int, int);
21 static int zhit(struct monst
*, int);
22 static bool revive(struct obj
*);
23 static void rloco(struct obj
*);
24 static void burn_scrolls(void);
26 /* Routines for IMMEDIATE wands. */
27 /* bhitm: monster mtmp was hit by the effect of wand otmp */
29 bhitm(struct monst
*mtmp
, struct obj
*otmp
)
34 if (u
.uswallow
|| rnd(20) < 10 + mtmp
->data
->ac
) {
36 hit("wand", mtmp
, exclam(tmp
));
43 case WAN_SLOW_MONSTER
:
46 case WAN_SPEED_MONSTER
:
49 case WAN_UNDEAD_TURNING
:
50 if (strchr(UNDEAD
, mtmp
->data
->mlet
)) {
59 if (newcham(mtmp
, &mons
[rn2(CMNUM
)]))
60 objects
[otmp
->otyp
].oc_name_known
= 1;
62 case WAN_CANCELLATION
:
65 case WAN_TELEPORTATION
:
68 case WAN_MAKE_INVISIBLE
:
75 #endif /* WAN_PROBING */
77 impossible("What an interesting wand (%u)", otmp
->otyp
);
82 * object obj was hit by the effect of wand otmp
83 * returns TRUE if sth was done
86 bhito(struct obj
*obj
, struct obj
*otmp
)
90 if (obj
== uball
|| obj
== uchain
)
95 /* preserve symbol and quantity, but turn rocks into gems */
96 mkobj_at((obj
->otyp
== ROCK
|| obj
->otyp
== ENORMOUS_ROCK
)
97 ? GEM_SYM
: obj
->olet
,
98 obj
->ox
, obj
->oy
)->quan
= obj
->quan
;
102 if (obj
->otyp
== ENORMOUS_ROCK
)
107 case WAN_CANCELLATION
:
108 if (obj
->spe
&& obj
->olet
!= AMULET_SYM
) {
113 case WAN_TELEPORTATION
:
116 case WAN_MAKE_INVISIBLE
:
119 case WAN_UNDEAD_TURNING
:
122 case WAN_SLOW_MONSTER
: /* no effect on objects */
123 case WAN_SPEED_MONSTER
:
126 #endif /* WAN_PROBING */
130 impossible("What an interesting wand (%u)", otmp
->otyp
);
141 obj
= getobj("/", "zap");
144 if (obj
->spe
< 0 || (obj
->spe
== 0 && rn2(121))) {
145 pline("Nothing Happens.");
149 pline("You wrest one more spell from the worn-out wand.");
150 if (!(objects
[obj
->otyp
].bits
& NODIR
) && !getdir(1))
151 return (1); /* make him pay for knowing !NODIR */
153 if (objects
[obj
->otyp
].bits
& IMMEDIATE
) {
155 bhitm(u
.ustuck
, obj
);
158 struct obj
*otmp
= o_at(u
.ux
, u
.uy
);
163 bhit(u
.dx
, u
.dy
, rn1(8, 6), 0, bhitm
, bhito
, obj
);
169 case WAN_SECRET_DOOR_DETECTION
:
173 case WAN_CREATE_MONSTER
:
179 makemon(NULL
, u
.ux
, u
.uy
);
186 if (u
.uluck
+ rn2(5) < 0) {
187 pline("Unfortunately, nothing happens.");
190 pline("You may wish for an object. What do you want? ");
192 if (buf
[0] == '\033')
194 otmp
= readobjnam(buf
);
201 * Original effect (approximately):
202 * from CORR: dig until we pierce a wall
203 * from ROOM: piece wall and dig until we reach
204 * an ACCESSIBLE place.
205 * Currently: dig for digdepth positions;
206 * also down on request of Lennart Augustsson.
212 struct monst
*mtmp
= u
.ustuck
;
214 pline("You pierce %s's stomach wall!",
216 mtmp
->mhp
= 1; /* almost dead */
223 pline("You loosen a rock from the ceiling.");
224 pline("It falls on your head!");
225 losehp(1, "falling rock");
226 mksobj_at(ROCK
, u
.ux
, u
.uy
);
237 digdepth
= 8 + rn2(18);
238 Tmp_at(-1, '*'); /* open call */
239 while (--digdepth
>= 0) {
242 room
= &levl
[zx
][zy
];
245 if (zx
< 3 || zx
> COLNO
- 3 ||
246 zy
< 3 || zy
> ROWNO
- 3)
248 if (room
->typ
== HWALL
||
249 room
->typ
== VWALL
) {
253 } else if (room
->typ
== HWALL
|| room
->typ
== VWALL
||
254 room
->typ
== SDOOR
|| room
->typ
== LDOOR
) {
257 } else if (room
->typ
== SCORR
|| !room
->typ
) {
265 mnewsym(zx
, zy
); /* not always necessary */
266 Tmp_at(-1, -1); /* closing call */
270 buzz((int)obj
->otyp
- WAN_MAGIC_MISSILE
,
271 u
.ux
, u
.uy
, u
.dx
, u
.dy
);
274 if (!objects
[obj
->otyp
].oc_name_known
) {
275 objects
[obj
->otyp
].oc_name_known
= 1;
276 more_experienced(0, 10);
285 /* force == 0 occurs e.g. with sleep ray */
286 /* note that large force is usual with wands so that !! would
287 require information about hand/weapon/wand */
288 return ((force
< 0) ? "?" : (force
<= 4) ? "." : "!");
292 hit(const char *str
, struct monst
*mtmp
, const char *force
)
294 /* force: usually either "." or "!" */
295 if (!cansee(mtmp
->mx
, mtmp
->my
))
296 pline("The %s hits it.", str
);
298 pline("The %s hits %s%s", str
, monnam(mtmp
), force
);
302 miss(const char *str
, struct monst
*mtmp
)
304 if (!cansee(mtmp
->mx
, mtmp
->my
))
305 pline("The %s misses it.", str
);
307 pline("The %s misses %s.", str
, monnam(mtmp
));
311 * bhit: called when a weapon is thrown (sym = obj->olet) or when an
312 * IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of range
313 * or when a monster is hit; the monster is returned, and bhitpos is set to
314 * the final position of the weapon thrown; the ray of a wand may affect
315 * several objects and monsters on its path - for each of these an argument
316 * function is called.
318 /* check !u.uswallow before calling bhit() */
320 /* ddx, ddy, range: direction and range
321 * sym: symbol displayed on path
322 * fhitm, fhito: fns called when mon/obj hit
323 * obj: 2nd arg to fhitm/fhito
326 bhit(int ddx
, int ddy
, int range
, char sym
,
327 void (*fhitm
)(struct monst
*, struct obj
*),
328 bool (*fhito
)(struct obj
*, struct obj
*), struct obj
*obj
)
337 if (sym
) /* open call */
339 while (range
-- > 0) {
342 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
343 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
))) {
345 tmp_at(-1, -1); /* close call */
351 if (fhito
&& (otmp
= o_at(bhitpos
.x
, bhitpos
.y
))) {
352 if ((*fhito
)(otmp
, obj
))
361 tmp_at(bhitpos
.x
, bhitpos
.y
);
364 /* leave last symbol unless in a pool */
366 tmp_at(-1, (levl
[bhitpos
.x
][bhitpos
.y
].typ
== POOL
) ? -1 : 0);
371 boomhit(int dx
, int dy
)
380 for (i
= 0; i
< 8; i
++)
381 if (xdir
[i
] == dx
&& ydir
[i
] == dy
)
383 tmp_at(-1, sym
); /* open call */
384 for (ct
= 0; ct
< 10; ct
++) {
387 sym
= ')' + '(' - sym
;
388 tmp_at(-2, sym
); /* change let call */
393 if ((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)) != NULL
) {
397 if (!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
402 if (bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
403 if (rn2(20) >= 10 + u
.ulevel
) { /* we hit ourselves */
404 thitu(10, rnd(10), "boomerang");
406 } else { /* we catch it */
408 pline("Skillfully, you catch the boomerang.");
412 tmp_at(bhitpos
.x
, bhitpos
.y
);
416 tmp_at(-1, -1); /* do not leave last symbol */
421 dirlet(int dx
, int dy
)
424 (dx
== dy
) ? '\\' : (dx
&& dy
) ? '/' : dx
? '-' : '|';
427 /* type == -1: monster spitting fire at you */
428 /* type == -1,-2,-3: bolts sent out by wizard */
429 /* called with dx = dy = 0 with vertical bolts */
431 buzz(int type
, xchar sx
, xchar sy
, int dx
, int dy
)
433 int abstype
= abs(type
);
434 const char *fltxt
= (type
== -1) ? "blaze of fire" : fl
[abstype
];
444 tmp
= zhit(u
.ustuck
, type
);
445 pline("The %s rips into %s%s",
446 fltxt
, monnam(u
.ustuck
), exclam(tmp
));
452 Tmp_at(-1, dirlet(dx
, dy
)); /* open call */
453 while (range
-- > 0) {
456 if ((lev
= &levl
[sx
][sy
])->typ
)
460 if (cansee(sx
- dx
, sy
- dy
))
461 pline("The %s bounces!", fltxt
);
462 if (ZAP_POS(levl
[sx
][sy
- dy
].typ
))
464 if (ZAP_POS(levl
[sx
- dx
][sy
].typ
)) {
465 if (!bounce
|| rn2(2))
482 Tmp_at(-2, dirlet(dx
, dy
));
485 if (lev
->typ
== POOL
&& abstype
== 1 /* fire */) {
488 if (cansee(sx
, sy
)) {
490 pline("The water evaporates.");
492 pline("You hear a hissing sound.");
494 if ((mon
= m_at(sx
, sy
)) &&
495 (type
!= -1 || mon
->data
->mlet
!= 'D')) {
497 if (rnd(20) < 18 + mon
->data
->ac
) {
498 int tmp
= zhit(mon
, abstype
);
501 if (cansee(mon
->mx
, mon
->my
))
502 pline("%s is killed by the %s!",
508 hit(fltxt
, mon
, exclam(tmp
));
512 } else if (sx
== u
.ux
&& sy
== u
.uy
) {
514 if (rnd(20) < 18 + u
.uac
) {
517 pline("The %s hits you!", fltxt
);
524 pline("You don't feel hot!");
531 nomul(-rnd(25)); /* sleep ray */
535 pline("You don't feel cold!");
544 pline("The %s whizzes by you!", fltxt
);
547 if (!ZAP_POS(lev
->typ
)) {
550 pline("The %s bounces!", fltxt
);
552 if (!dx
|| !dy
|| !rn2(20)) {
556 if (ZAP_POS(rmn
= levl
[sx
][sy
- dy
].typ
) &&
557 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
+ dx
][sy
- dy
].typ
)))
559 if (ZAP_POS(rmn
= levl
[sx
- dx
][sy
].typ
) &&
560 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
- dx
][sy
+ dy
].typ
)))
561 if (!bounce
|| rn2(2))
576 Tmp_at(-2, dirlet(dx
, dy
));
584 zhit(struct monst
*mon
, int type
) /* returns damage to mon */
589 case 0: /* magic missile */
592 case -1: /* Dragon blazing fire */
594 if (strchr("Dg", mon
->data
->mlet
))
597 if (strchr("YF", mon
->data
->mlet
))
604 if (strchr("YFgf", mon
->data
->mlet
))
607 if (mon
->data
->mlet
== 'D')
611 if (strchr(UNDEAD
, mon
->data
->mlet
))
620 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
621 ? 'a' + (otyp - DEAD_ACID_BLOB)\
622 : '@' + (otyp - DEAD_HUMAN))
624 revive(struct obj
*obj
)
626 struct monst
*mtmp
= NULL
;
628 if (obj
->olet
== FOOD_SYM
&& obj
->otyp
> CORPSE
) {
629 /* do not (yet) revive shopkeepers */
630 /* Note: this might conceivably produce two monsters
631 * at the same position - strange, but harmless */
632 mtmp
= mkmon_at(CORPSE_I_TO_C(obj
->otyp
), obj
->ox
, obj
->oy
);
635 return (!!mtmp
); /* TRUE if some monster created */
639 rloco(struct obj
*obj
)
641 int tx
, ty
, otx
, oty
;
646 tx
= rn1(COLNO
- 3, 2);
648 } while (!goodpos(tx
, ty
));
651 if (cansee(otx
, oty
))
655 /* fractured by pick-axe or wand of striking */
658 fracture_rock(struct obj
*obj
)
661 obj
->quan
= 7 + rn2(60);
662 obj
->owt
= weight(obj
);
663 obj
->olet
= WEAPON_SYM
;
664 if (cansee(obj
->ox
, obj
->oy
))
665 prl(obj
->ox
, obj
->oy
);
671 struct obj
*obj
, *obj2
;
674 for (obj
= invent
; obj
; obj
= obj2
) {
676 if (obj
->olet
== SCROLL_SYM
) {
682 pline("Your scrolls catch fire!");
683 losehp(cnt
, "burning scrolls");
685 pline("Your scroll catches fire!");
686 losehp(1, "burning scroll");