1 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
2 /* hack.zap.c - version 1.0.3 */
6 extern struct obj
*mkobj_at();
7 extern struct monst
*makemon(), *mkmon_at(), youmonst
;
19 /* Routines for IMMEDIATE wands. */
20 /* bhitm: monster mtmp was hit by the effect of wand otmp */
22 register struct monst
*mtmp
;
23 register struct obj
*otmp
;
28 if(u
.uswallow
|| rnd(20) < 10+mtmp
->data
->ac
) {
29 register int tmp
= d(2,12);
30 hit("wand", mtmp
, exclam(tmp
));
32 if(mtmp
->mhp
< 1) killed(mtmp
);
33 } else miss("wand", mtmp
);
35 case WAN_SLOW_MONSTER
:
38 case WAN_SPEED_MONSTER
:
41 case WAN_UNDEAD_TURNING
:
42 if(index(UNDEAD
,mtmp
->data
->mlet
)) {
44 if(mtmp
->mhp
< 1) killed(mtmp
);
49 if( newcham(mtmp
,&mons
[rn2(CMNUM
)]) )
50 objects
[otmp
->otyp
].oc_name_known
= 1;
52 case WAN_CANCELLATION
:
55 case WAN_TELEPORTATION
:
58 case WAN_MAKE_INVISIBLE
:
67 impossible("What an interesting wand (%u)", otmp
->otyp
);
71 bhito(obj
, otmp
) /* object obj was hit by the effect of wand otmp */
72 register struct obj
*obj
, *otmp
; /* returns TRUE if sth was done */
74 register int res
= TRUE
;
76 if(obj
== uball
|| obj
== uchain
)
81 /* preserve symbol and quantity, but turn rocks into gems */
82 mkobj_at((obj
->otyp
== ROCK
|| obj
->otyp
== ENORMOUS_ROCK
)
83 ? GEM_SYM
: obj
->olet
,
84 obj
->ox
, obj
->oy
) -> quan
= obj
->quan
;
88 if(obj
->otyp
== ENORMOUS_ROCK
)
93 case WAN_CANCELLATION
:
94 if(obj
->spe
&& obj
->olet
!= AMULET_SYM
) {
99 case WAN_TELEPORTATION
:
102 case WAN_MAKE_INVISIBLE
:
105 case WAN_UNDEAD_TURNING
:
108 case WAN_SLOW_MONSTER
: /* no effect on objects */
109 case WAN_SPEED_MONSTER
:
116 impossible("What an interesting wand (%u)", otmp
->otyp
);
123 register struct obj
*obj
;
126 obj
= getobj("/", "zap");
128 if(obj
->spe
< 0 || (obj
->spe
== 0 && rn2(121))) {
129 pline("Nothing Happens.");
133 pline("You wrest one more spell from the worn-out wand.");
134 if(!(objects
[obj
->otyp
].bits
& NODIR
) && !getdir(1))
135 return(1); /* make him pay for knowing !NODIR */
137 if(objects
[obj
->otyp
].bits
& IMMEDIATE
) {
139 bhitm(u
.ustuck
, obj
);
142 register struct obj
*otmp
= o_at(u
.ux
, u
.uy
);
144 (void) bhito(otmp
, obj
);
147 (void) bhit(u
.dx
,u
.dy
,rn1(8,6),0,bhitm
,bhito
,obj
);
153 case WAN_SECRET_DOOR_DETECTION
:
154 if(!findit()) return(1);
156 case WAN_CREATE_MONSTER
:
157 { register int cnt
= 1;
158 if(!rn2(23)) cnt
+= rn2(7) + 1;
160 (void) makemon((struct permonst
*) 0, u
.ux
, u
.uy
);
165 register struct obj
*otmp
;
166 extern struct obj
*readobjnam(), *addinv();
167 if(u
.uluck
+ rn2(5) < 0) {
168 pline("Unfortunately, nothing happens.");
171 pline("You may wish for an object. What do you want? ");
173 if(buf
[0] == '\033') buf
[0] = 0;
174 otmp
= readobjnam(buf
);
180 /* Original effect (approximately):
181 * from CORR: dig until we pierce a wall
182 * from ROOM: piece wall and dig until we reach
183 * an ACCESSIBLE place.
184 * Currently: dig for digdepth positions;
185 * also down on request of Lennart Augustsson.
187 { register struct rm
*room
;
188 register int digdepth
;
190 register struct monst
*mtmp
= u
.ustuck
;
192 pline("You pierce %s's stomach wall!",
194 mtmp
->mhp
= 1; /* almost dead */
201 pline("You loosen a rock from the ceiling.");
202 pline("It falls on your head!");
203 losehp(1, "falling rock");
204 mksobj_at(ROCK
, u
.ux
, u
.uy
);
207 if(Invisible
) newsym(u
.ux
, u
.uy
);
215 digdepth
= 8 + rn2(18);
216 Tmp_at(-1, '*'); /* open call */
217 while(--digdepth
>= 0) {
218 if(!isok(zx
,zy
)) break;
219 room
= &levl
[zx
][zy
];
222 if(zx
< 3 || zx
> COLNO
-3 ||
223 zy
< 3 || zy
> ROWNO
-3)
225 if(room
->typ
== HWALL
||
231 if(room
->typ
== HWALL
|| room
->typ
== VWALL
||
232 room
->typ
== SDOOR
|| room
->typ
== LDOOR
){
236 if(room
->typ
== SCORR
|| !room
->typ
) {
244 mnewsym(zx
,zy
); /* not always necessary */
245 Tmp_at(-1,-1); /* closing call */
249 buzz((int) obj
->otyp
- WAN_MAGIC_MISSILE
,
250 u
.ux
, u
.uy
, u
.dx
, u
.dy
);
253 if(!objects
[obj
->otyp
].oc_name_known
) {
254 objects
[obj
->otyp
].oc_name_known
= 1;
255 more_experienced(0,10);
265 /* force == 0 occurs e.g. with sleep ray */
266 /* note that large force is usual with wands so that !! would
267 require information about hand/weapon/wand */
268 return( (force
< 0) ? "?" : (force
<= 4) ? "." : "!" );
273 register struct monst
*mtmp
;
274 register char *force
; /* usually either "." or "!" */
276 if(!cansee(mtmp
->mx
,mtmp
->my
)) pline("The %s hits it.", str
);
277 else pline("The %s hits %s%s", str
, monnam(mtmp
), force
);
282 register struct monst
*mtmp
;
284 if(!cansee(mtmp
->mx
,mtmp
->my
)) pline("The %s misses it.",str
);
285 else pline("The %s misses %s.",str
,monnam(mtmp
));
288 /* bhit: called when a weapon is thrown (sym = obj->olet) or when an
289 IMMEDIATE wand is zapped (sym = 0); the weapon falls down at end of
290 range or when a monster is hit; the monster is returned, and bhitpos
291 is set to the final position of the weapon thrown; the ray of a wand
292 may affect several objects and monsters on its path - for each of
293 these an argument function is called. */
294 /* check !u.uswallow before calling bhit() */
297 bhit(ddx
,ddy
,range
,sym
,fhitm
,fhito
,obj
)
298 register int ddx
,ddy
,range
; /* direction and range */
299 char sym
; /* symbol displayed on path */
300 int (*fhitm
)(), (*fhito
)(); /* fns called when mon/obj hit */
301 struct obj
*obj
; /* 2nd arg to fhitm/fhito */
303 register struct monst
*mtmp
;
304 register struct obj
*otmp
;
310 if(sym
) tmp_at(-1, sym
); /* open call */
314 typ
= levl
[bhitpos
.x
][bhitpos
.y
].typ
;
315 if(mtmp
= m_at(bhitpos
.x
,bhitpos
.y
)){
317 tmp_at(-1, -1); /* close call */
323 if(fhito
&& (otmp
= o_at(bhitpos
.x
,bhitpos
.y
))){
324 if((*fhito
)(otmp
, obj
))
332 if(sym
) tmp_at(bhitpos
.x
, bhitpos
.y
);
335 /* leave last symbol unless in a pool */
337 tmp_at(-1, (levl
[bhitpos
.x
][bhitpos
.y
].typ
== POOL
) ? -1 : 0);
344 register struct monst
*mtmp
;
346 extern schar xdir
[], ydir
[];
351 for(i
=0; i
<8; i
++) if(xdir
[i
] == dx
&& ydir
[i
] == dy
) break;
352 tmp_at(-1, sym
); /* open call */
353 for(ct
=0; ct
<10; ct
++) {
355 sym
= ')' + '(' - sym
;
356 tmp_at(-2, sym
); /* change let call */
361 if(mtmp
= m_at(bhitpos
.x
, bhitpos
.y
)){
365 if(!ZAP_POS(levl
[bhitpos
.x
][bhitpos
.y
].typ
)) {
370 if(bhitpos
.x
== u
.ux
&& bhitpos
.y
== u
.uy
) { /* ct == 9 */
371 if(rn2(20) >= 10+u
.ulevel
){ /* we hit ourselves */
372 (void) thitu(10, rnd(10), "boomerang");
374 } else { /* we catch it */
376 pline("Skillfully, you catch the boomerang.");
380 tmp_at(bhitpos
.x
, bhitpos
.y
);
383 tmp_at(-1, -1); /* do not leave last symbol */
388 dirlet(dx
,dy
) register dx
,dy
; {
390 (dx
== dy
) ? '\\' : (dx
&& dy
) ? '/' : dx
? '-' : '|';
393 /* type == -1: monster spitting fire at you */
394 /* type == -1,-2,-3: bolts sent out by wizard */
395 /* called with dx = dy = 0 with vertical bolts */
396 buzz(type
,sx
,sy
,dx
,dy
)
398 register xchar sx
,sy
;
401 int abstype
= abs(type
);
402 register char *fltxt
= (type
== -1) ? "blaze of fire" : fl
[abstype
];
411 tmp
= zhit(u
.ustuck
, type
);
412 pline("The %s rips into %s%s",
413 fltxt
, monnam(u
.ustuck
), exclam(tmp
));
418 Tmp_at(-1, dirlet(dx
,dy
)); /* open call */
422 if((lev
= &levl
[sx
][sy
])->typ
) Tmp_at(sx
,sy
);
425 if(cansee(sx
-dx
,sy
-dy
))
426 pline("The %s bounces!", fltxt
);
427 if(ZAP_POS(levl
[sx
][sy
-dy
].typ
))
429 if(ZAP_POS(levl
[sx
-dx
][sy
].typ
)) {
430 if(!bounce
|| rn2(2)) bounce
= 2;
446 Tmp_at(-2,dirlet(dx
,dy
));
449 if(lev
->typ
== POOL
&& abstype
== 1 /* fire */) {
454 pline("The water evaporates.");
456 pline("You hear a hissing sound.");
458 if((mon
= m_at(sx
,sy
)) &&
459 (type
!= -1 || mon
->data
->mlet
!= 'D')) {
461 if(rnd(20) < 18 + mon
->data
->ac
) {
462 register int tmp
= zhit(mon
,abstype
);
465 if(cansee(mon
->mx
,mon
->my
))
466 pline("%s is killed by the %s!",
472 hit(fltxt
, mon
, exclam(tmp
));
476 } else if(sx
== u
.ux
&& sy
== u
.uy
) {
478 if(rnd(20) < 18+u
.uac
) {
479 register int dam
= 0;
481 pline("The %s hits you!",fltxt
);
488 pline("You don't feel hot!");
494 nomul(-rnd(25)); /* sleep ray */
498 pline("You don't feel cold!");
505 } else pline("The %s whizzes by you!",fltxt
);
508 if(!ZAP_POS(lev
->typ
)) {
510 if(cansee(sx
,sy
)) pline("The %s bounces!",fltxt
);
512 if(!dx
|| !dy
|| !rn2(20)){
516 if(ZAP_POS(rmn
= levl
[sx
][sy
-dy
].typ
) &&
517 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
+dx
][sy
-dy
].typ
)))
519 if(ZAP_POS(rmn
= levl
[sx
-dx
][sy
].typ
) &&
520 (IS_ROOM(rmn
) || ZAP_POS(levl
[sx
-dx
][sy
+dy
].typ
)))
521 if(!bounce
|| rn2(2))
536 Tmp_at(-2, dirlet(dx
,dy
));
543 zhit(mon
,type
) /* returns damage to mon */
544 register struct monst
*mon
;
547 register int tmp
= 0;
550 case 0: /* magic missile */
553 case -1: /* Dragon blazing fire */
555 if(index("Dg", mon
->data
->mlet
)) break;
557 if(index("YF", mon
->data
->mlet
)) tmp
+= 7;
563 if(index("YFgf", mon
->data
->mlet
)) break;
565 if(mon
->data
->mlet
== 'D') tmp
+= 7;
568 if(index(UNDEAD
, mon
->data
->mlet
)) break;
576 #define CORPSE_I_TO_C(otyp) (char) ((otyp >= DEAD_ACID_BLOB)\
577 ? 'a' + (otyp - DEAD_ACID_BLOB)\
578 : '@' + (otyp - DEAD_HUMAN))
580 register struct obj
*obj
;
582 register struct monst
*mtmp
;
584 if(obj
->olet
== FOOD_SYM
&& obj
->otyp
> CORPSE
) {
585 /* do not (yet) revive shopkeepers */
586 /* Note: this might conceivably produce two monsters
587 at the same position - strange, but harmless */
588 mtmp
= mkmon_at(CORPSE_I_TO_C(obj
->otyp
),obj
->ox
,obj
->oy
);
591 return(!!mtmp
); /* TRUE if some monster created */
595 register struct obj
*obj
;
597 register tx
,ty
,otx
,oty
;
604 } while(!goodpos(tx
,ty
));
611 fracture_rock(obj
) /* fractured by pick-axe or wand of striking */
612 register struct obj
*obj
; /* no texts here! */
616 obj
->quan
= 7 + rn2(60);
617 obj
->owt
= weight(obj
);
618 obj
->olet
= WEAPON_SYM
;
619 if(cansee(obj
->ox
,obj
->oy
))
620 prl(obj
->ox
,obj
->oy
);
625 register struct obj
*obj
, *obj2
;
626 register int cnt
= 0;
628 for(obj
= invent
; obj
; obj
= obj2
) {
630 if(obj
->olet
== SCROLL_SYM
) {
636 pline("Your scrolls catch fire!");
637 losehp(cnt
, "burning scrolls");
639 pline("Your scroll catches fire!");
640 losehp(1, "burning scroll");