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
));
38 if(mtmp
->mhp
< 1) killed(mtmp
);
39 } else miss("wand", mtmp
);
41 case WAN_SLOW_MONSTER
:
44 case WAN_SPEED_MONSTER
:
47 case WAN_UNDEAD_TURNING
:
48 if(index(UNDEAD
,mtmp
->data
->mlet
)) {
50 if(mtmp
->mhp
< 1) killed(mtmp
);
55 if( newcham(mtmp
,&mons
[rn2(CMNUM
)]) )
56 objects
[otmp
->otyp
].oc_name_known
= 1;
58 case WAN_CANCELLATION
:
61 case WAN_TELEPORTATION
:
64 case WAN_MAKE_INVISIBLE
:
71 #endif /* WAN_PROBING */
73 impossible("What an interesting wand (%u)", otmp
->otyp
);
78 bhito(struct obj
*obj
, struct obj
*otmp
)
79 /* object obj was hit by the effect of wand otmp */
80 /* returns TRUE if sth was done */
84 if(obj
== uball
|| obj
== uchain
)
89 /* preserve symbol and quantity, but turn rocks into gems */
90 mkobj_at((obj
->otyp
== ROCK
|| obj
->otyp
== ENORMOUS_ROCK
)
91 ? GEM_SYM
: obj
->olet
,
92 obj
->ox
, obj
->oy
) -> quan
= obj
->quan
;
96 if(obj
->otyp
== ENORMOUS_ROCK
)
101 case WAN_CANCELLATION
:
102 if(obj
->spe
&& obj
->olet
!= AMULET_SYM
) {
107 case WAN_TELEPORTATION
:
110 case WAN_MAKE_INVISIBLE
:
113 case WAN_UNDEAD_TURNING
:
116 case WAN_SLOW_MONSTER
: /* no effect on objects */
117 case WAN_SPEED_MONSTER
:
120 #endif /* WAN_PROBING */
124 impossible("What an interesting wand (%u)", otmp
->otyp
);
135 obj
= getobj("/", "zap");
137 if(obj
->spe
< 0 || (obj
->spe
== 0 && rn2(121))) {
138 pline("Nothing Happens.");
142 pline("You wrest one more spell from the worn-out wand.");
143 if(!(objects
[obj
->otyp
].bits
& NODIR
) && !getdir(1))
144 return(1); /* make him pay for knowing !NODIR */
146 if(objects
[obj
->otyp
].bits
& IMMEDIATE
) {
148 bhitm(u
.ustuck
, obj
);
151 struct obj
*otmp
= o_at(u
.ux
, u
.uy
);
156 bhit(u
.dx
,u
.dy
,rn1(8,6),0,bhitm
,bhito
,obj
);
162 case WAN_SECRET_DOOR_DETECTION
:
163 if(!findit()) return(1);
165 case WAN_CREATE_MONSTER
:
167 if(!rn2(23)) cnt
+= rn2(7) + 1;
169 makemon((struct permonst
*) 0, u
.ux
, u
.uy
);
175 if(u
.uluck
+ rn2(5) < 0) {
176 pline("Unfortunately, nothing happens.");
179 pline("You may wish for an object. What do you want? ");
181 if(buf
[0] == '\033') buf
[0] = 0;
182 otmp
= readobjnam(buf
);
188 /* Original effect (approximately):
189 * from CORR: dig until we pierce a wall
190 * from ROOM: piece wall and dig until we reach
191 * an ACCESSIBLE place.
192 * Currently: dig for digdepth positions;
193 * also down on request of Lennart Augustsson.
198 struct monst
*mtmp
= u
.ustuck
;
200 pline("You pierce %s's stomach wall!",
202 mtmp
->mhp
= 1; /* almost dead */
209 pline("You loosen a rock from the ceiling.");
210 pline("It falls on your head!");
211 losehp(1, "falling rock");
212 mksobj_at(ROCK
, u
.ux
, u
.uy
);
215 if(Invisible
) newsym(u
.ux
, u
.uy
);
223 digdepth
= 8 + rn2(18);
224 Tmp_at(-1, '*'); /* open call */
225 while(--digdepth
>= 0) {
226 if(!isok(zx
,zy
)) break;
227 room
= &levl
[zx
][zy
];
230 if(zx
< 3 || zx
> COLNO
-3 ||
231 zy
< 3 || zy
> ROWNO
-3)
233 if(room
->typ
== HWALL
||
239 if(room
->typ
== HWALL
|| room
->typ
== VWALL
||
240 room
->typ
== SDOOR
|| room
->typ
== LDOOR
){
244 if(room
->typ
== SCORR
|| !room
->typ
) {
252 mnewsym(zx
,zy
); /* not always necessary */
253 Tmp_at(-1,-1); /* closing call */
257 buzz((int) obj
->otyp
- WAN_MAGIC_MISSILE
,
258 u
.ux
, u
.uy
, u
.dx
, u
.dy
);
261 if(!objects
[obj
->otyp
].oc_name_known
) {
262 objects
[obj
->otyp
].oc_name_known
= 1;
263 more_experienced(0,10);
272 /* force == 0 occurs e.g. with sleep ray */
273 /* note that large force is usual with wands so that !! would
274 require information about hand/weapon/wand */
275 return( (force
< 0) ? "?" : (force
<= 4) ? "." : "!" );
279 hit(const char *str
, struct monst
*mtmp
, const char *force
)
280 /* force: usually either "." or "!" */
282 if(!cansee(mtmp
->mx
,mtmp
->my
)) pline("The %s hits it.", str
);
283 else pline("The %s hits %s%s", str
, monnam(mtmp
), force
);
287 miss(const char *str
, struct monst
*mtmp
)
289 if(!cansee(mtmp
->mx
,mtmp
->my
)) pline("The %s misses it.",str
);
290 else pline("The %s misses %s.",str
,monnam(mtmp
));
293 /* bhit: called when a weapon is thrown (sym = obj->olet) or when an
294 IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of
295 range or when a monster is hit; the monster is returned, and bhitpos
296 is set to the final position of the weapon thrown; the ray of a wand
297 may affect several objects and monsters on its path - for each of
298 these an argument function is called. */
299 /* check !u.uswallow before calling bhit() */
301 /* ddx, ddy, range: direction and range
302 * sym: symbol displayed on path
303 * fhitm, fhito: fns called when mon/obj hit
304 * obj: 2nd arg to fhitm/fhito
307 bhit(int ddx
, int ddy
, int range
, char sym
,
308 void (*fhitm
)(struct monst
*, struct obj
*),
309 bool (*fhito
)(struct obj
*, struct obj
*), struct obj
*obj
)
318 if(sym
) tmp_at(-1, sym
); /* open call */
322 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
323 if((mtmp
= m_at(bhitpos
.x
,bhitpos
.y
))){
325 tmp_at(-1, -1); /* close call */
331 if(fhito
&& (otmp
= o_at(bhitpos
.x
,bhitpos
.y
))){
332 if((*fhito
)(otmp
, obj
))
340 if(sym
) tmp_at(bhitpos
.x
, bhitpos
.y
);
343 /* leave last symbol unless in a pool */
345 tmp_at(-1, (levl
[bhitpos
.x
][bhitpos
.y
].typ
== POOL
) ? -1 : 0);
350 boomhit(int dx
, int dy
)
359 for(i
=0; i
<8; i
++) if(xdir
[i
] == dx
&& ydir
[i
] == dy
) break;
360 tmp_at(-1, sym
); /* open call */
361 for(ct
=0; ct
<10; ct
++) {
363 sym
= ')' + '(' - sym
;
364 tmp_at(-2, sym
); /* change let call */
369 if((mtmp
= m_at(bhitpos
.x
, bhitpos
.y
))){
373 if(!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
378 if(bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
379 if(rn2(20) >= 10+u
.ulevel
){ /* we hit ourselves */
380 thitu(10, rnd(10), "boomerang");
382 } else { /* we catch it */
384 pline("Skillfully, you catch the boomerang.");
388 tmp_at(bhitpos
.x
, bhitpos
.y
);
391 tmp_at(-1, -1); /* do not leave last symbol */
396 dirlet(int dx
, int dy
)
399 (dx
== dy
) ? '\\' : (dx
&& dy
) ? '/' : dx
? '-' : '|';
402 /* type == -1: monster spitting fire at you */
403 /* type == -1,-2,-3: bolts sent out by wizard */
404 /* called with dx = dy = 0 with vertical bolts */
406 buzz(int type
, xchar sx
, xchar sy
, int dx
, int dy
)
408 int abstype
= abs(type
);
409 const char *fltxt
= (type
== -1) ? "blaze of fire" : fl
[abstype
];
418 tmp
= zhit(u
.ustuck
, type
);
419 pline("The %s rips into %s%s",
420 fltxt
, monnam(u
.ustuck
), exclam(tmp
));
425 Tmp_at(-1, dirlet(dx
,dy
)); /* open call */
429 if((lev
= &levl
[sx
][sy
])->typ
) Tmp_at(sx
,sy
);
432 if(cansee(sx
-dx
,sy
-dy
))
433 pline("The %s bounces!", fltxt
);
434 if(ZAP_POS(levl
[sx
][sy
-dy
].typ
))
436 if(ZAP_POS(levl
[sx
-dx
][sy
].typ
)) {
437 if(!bounce
|| rn2(2)) bounce
= 2;
453 Tmp_at(-2,dirlet(dx
,dy
));
456 if(lev
->typ
== POOL
&& abstype
== 1 /* fire */) {
461 pline("The water evaporates.");
463 pline("You hear a hissing sound.");
465 if((mon
= m_at(sx
,sy
)) &&
466 (type
!= -1 || mon
->data
->mlet
!= 'D')) {
468 if(rnd(20) < 18 + mon
->data
->ac
) {
469 int tmp
= zhit(mon
,abstype
);
472 if(cansee(mon
->mx
,mon
->my
))
473 pline("%s is killed by the %s!",
479 hit(fltxt
, mon
, exclam(tmp
));
483 } else if(sx
== u
.ux
&& sy
== u
.uy
) {
485 if(rnd(20) < 18+u
.uac
) {
488 pline("The %s hits you!",fltxt
);
495 pline("You don't feel hot!");
501 nomul(-rnd(25)); /* sleep ray */
505 pline("You don't feel cold!");
512 } else pline("The %s whizzes by you!",fltxt
);
515 if(!ZAP_POS(lev
->typ
)) {
517 if(cansee(sx
,sy
)) pline("The %s bounces!",fltxt
);
519 if(!dx
|| !dy
|| !rn2(20)){
523 if(ZAP_POS(rmn
= levl
[sx
][sy
-dy
].typ
) &&
524 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
+dx
][sy
-dy
].typ
)))
526 if(ZAP_POS(rmn
= levl
[sx
-dx
][sy
].typ
) &&
527 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
-dx
][sy
+dy
].typ
)))
528 if(!bounce
|| rn2(2))
543 Tmp_at(-2, dirlet(dx
,dy
));
551 zhit(struct monst
*mon
, int type
) /* returns damage to mon */
556 case 0: /* magic missile */
559 case -1: /* Dragon blazing fire */
561 if(index("Dg", mon
->data
->mlet
)) break;
563 if(index("YF", mon
->data
->mlet
)) tmp
+= 7;
569 if(index("YFgf", mon
->data
->mlet
)) break;
571 if(mon
->data
->mlet
== 'D') tmp
+= 7;
574 if(index(UNDEAD
, mon
->data
->mlet
)) break;
582 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
583 ? 'a' + (otyp - DEAD_ACID_BLOB)\
584 : '@' + (otyp - DEAD_HUMAN))
586 revive(struct obj
*obj
)
588 struct monst
*mtmp
= NULL
;
590 if(obj
->olet
== FOOD_SYM
&& obj
->otyp
> CORPSE
) {
591 /* do not (yet) revive shopkeepers */
592 /* Note: this might conceivably produce two monsters
593 at the same position - strange, but harmless */
594 mtmp
= mkmon_at(CORPSE_I_TO_C(obj
->otyp
),obj
->ox
,obj
->oy
);
597 return(!!mtmp
); /* TRUE if some monster created */
601 rloco(struct obj
*obj
)
610 } while(!goodpos(tx
,ty
));
618 fracture_rock(struct obj
*obj
) /* fractured by pick-axe or wand of striking */
622 obj
->quan
= 7 + rn2(60);
623 obj
->owt
= weight(obj
);
624 obj
->olet
= WEAPON_SYM
;
625 if(cansee(obj
->ox
,obj
->oy
))
626 prl(obj
->ox
,obj
->oy
);
632 struct obj
*obj
, *obj2
;
635 for(obj
= invent
; obj
; obj
= obj2
) {
637 if(obj
->olet
== SCROLL_SYM
) {
643 pline("Your scrolls catch fire!");
644 losehp(cnt
, "burning scrolls");
646 pline("Your scroll catches fire!");
647 losehp(1, "burning scroll");