1 /*
2  * Functions to implement the various sticks one might find
3  * while wandering around the dungeon.
4  *
5  * @(#)sticks.c		1.2 (AI Design)		2/12/84
6  */
7 
8 #include "rogue.h"
9 #include "curses.h"
10 
11 /*
12  * fix_stick:
13  *	Set up a new stick
14  */
15 fix_stick(cur)
16 register THING *cur;
17 {
18     if (strcmp(ws_type[cur->o_which], "staff") == 0)
19 	cur->o_damage = "2d3";
20     else
21 	cur->o_damage = "1d1";
22     cur->o_hurldmg = "1d1";
23 
24     cur->o_charges = 3 + rnd(5);
25     switch (cur->o_which)
26     {
27 	when WS_HIT:
28 	    cur->o_hplus = 100;
29 	    cur->o_dplus = 3;
30 	    cur->o_damage = "1d8";
31 	when WS_LIGHT:
32 	    cur->o_charges = 10 + rnd(10);
33     }
34 }
35 
36 /*
37  * do_zap:
38  *	Perform a zap with a wand
39  */
40 do_zap()
41 {
42     THING *obj;
43     THING *tp;
44     register int y, x;
45     register char *name;
46     int which_one;
47 
48     if ((obj = get_item("zap with", STICK)) == NULL)
49 	    return;
50     which_one = obj->o_which;
51     if (obj->o_type != STICK)
52     {
53 	if (obj->o_enemy && obj->o_charges)
54 	    which_one = MAXSTICKS;
55 	else
56 	{
57 	    msg("you can't zap with that!");
58 	    after = FALSE;
59 	    return;
60 	}
61     }
62     if (obj->o_charges == 0)
63     {
64 	msg("nothing happens");
65 	return;
66     }
67     switch (which_one)
68     {
69 	when WS_LIGHT:
70 	    /*
71 	     * Reddy Kilowat wand.  Light up the room
72 	     */
73 	    if (on(player,ISBLIND))
74 	    	msg("you feel a warm glow around you");
75 	    else 
76 	    {
77 		ws_know[WS_LIGHT] = TRUE;
78 	        if (proom->r_flags & ISGONE)
79 		    msg("the corridor glows and then fades");
80 	        else
81 		    msg("the room is lit by a shimmering blue light");
82 	    }
83 	    if (!(proom->r_flags & ISGONE))
84 	    {
85 		proom->r_flags &= ~ISDARK;
86 		/*
87 		 * Light the room and put the player back up
88 		 */
89 		enter_room(&hero);
90 	    }
91 	when WS_DRAIN:
92 	    /*
93 	     * Take away 1/2 of hero's hit points, then take it away
94 	     * evenly from the monsters in the room (or next to hero
95 	     * if he is in a passage)
96 	     */
97 	    if (pstats.s_hpt < 2)
98 	    {
99 		msg("you are too weak to use it");
100 		return;
101 	    }
102 	    else
103 		drain();
104 	when WS_POLYMORPH:
105 	case WS_TELAWAY:
106 	case WS_TELTO:
107 	case WS_CANCEL:
108 	case MAXSTICKS:			/* Special case for vorpal weapon */
109 	{
110 	    register byte monster, oldch;
111 	    register int rm;
112 	    coord new_yx;
113 
114 	    y = hero.y;
115 	    x = hero.x;
116 	    while (step_ok(winat(y, x)))
117 	    {
118 		y += delta.y;
119 		x += delta.x;
120 	    }
121 	    if ((tp = moat(y, x)) != NULL)
122 	    {
123 		register byte omonst;
124 
125 		omonst = monster = tp->t_type;
126 		if (monster == 'F')
127 		    player.t_flags &= ~ISHELD;
128 		if (which_one == MAXSTICKS)
129 		{
130 		    if (monster == obj->o_enemy)
131 		    {
132 			msg("the %s vanishes in a puff of smoke",
133 			    monsters[monster-'A'].m_name);
134 			killed(tp, FALSE);
135 		    }
136 		    else
137 			msg("you hear a maniacal chuckle in the distance.");
138 		}
139 		else if (which_one == WS_POLYMORPH)
140 		{
141 		    register THING *pp;
142 
143 		    pp = tp->t_pack;
144 		    detach(mlist, tp);
145 		    if (see_monst(tp))
146 			mvaddch(y, x, chat(y, x));
147 		    oldch = tp->t_oldch;
148 		    delta.y = y;
149 		    delta.x = x;
150 		    new_monster(tp, monster = rnd(26) + 'A', &delta);
151 		    if (see_monst(tp))
152 			mvaddch(y, x, monster);
153 		    tp->t_oldch = oldch;
154 		    tp->t_pack = pp;
155 		    ws_know[WS_POLYMORPH] |= (monster != omonst);
156 		}
157 		else if (which_one == WS_CANCEL)
158 		{
159 		    tp->t_flags |= ISCANC;
160 		    tp->t_flags &= ~(ISINVIS|CANHUH);
161 		    tp->t_disguise = tp->t_type;
162 		}
163 		else
164 		{
165 		    if (see_monst(tp))
166 			mvaddch(y, x, tp->t_oldch);
167 		    if (which_one == WS_TELAWAY)
168 		    {
169 		    	tp->t_oldch = '@';
170 			do
171 			{
172 			    rm = rnd_room();
173 			    new_yx = tp->t_pos;
174 			    rnd_pos(&rooms[rm], &new_yx);
175 			}  while (!(isfloor(winat(new_yx.y, new_yx.x))));
176 			tp->t_pos = new_yx;
177 			if (see_monst(tp))
178 			    mvaddch(tp->t_pos.y, tp->t_pos.x, tp->t_disguise);
179 			else if (on(player, SEEMONST))
180 			{
181 			    standout();
182 			    mvaddch(tp->t_pos.y, tp->t_pos.x, tp->t_disguise);
183 			    standend();
184 			}
185 		    }
186 		    else /* it MUST BE at WS_TELTO */
187 		    {
188 			tp->t_pos.y = hero.y + delta.y;
189 			tp->t_pos.x = hero.x + delta.x;
190 		    }
191 		    if (tp->t_type == 'F')
192 			player.t_flags &= ~ISHELD;
193 		    if (tp->t_pos.y != y || tp->t_pos.x != x)
194 			tp->t_oldch = mvinch(tp->t_pos.y, tp->t_pos.x);
195 		}
196 		tp->t_dest = &hero;
197 		tp->t_flags |= ISRUN;
198 	    }
199 	}
200 	when WS_MISSILE:
201 	{
202 	    THING bolt;
203 
204 	    ws_know[WS_MISSILE] = TRUE;
205 	    bolt.o_type = '*';
206 	    bolt.o_hurldmg = "1d8";
207 	    bolt.o_hplus = 1000;
208 	    bolt.o_dplus = 1;
209 	    bolt.o_flags = ISMISL;
210 	    if (cur_weapon != NULL)
211 		bolt.o_launch = cur_weapon->o_which;
212 	    do_motion(&bolt, delta.y, delta.x);
213 	    if ((tp = moat(bolt.o_pos.y, bolt.o_pos.x)) != NULL && !save_throw(VS_MAGIC, tp))
214 		    hit_monster(unc(bolt.o_pos), &bolt);
215 	    else 
216 		msg("the missle vanishes with a puff of smoke");
217 	}
218 	when WS_HIT:
219 	    delta.y += hero.y;
220 	    delta.x += hero.x;
221 	    if ((tp = moat(delta.y, delta.x)) != NULL)
222 	    {
223 		if (rnd(20) == 0)
224 		{
225 		    obj->o_damage = "3d8";
226 		    obj->o_dplus = 9;
227 		}
228 		else
229 		{
230 		    obj->o_damage = "2d8";
231 		    obj->o_dplus = 4;
232 		}
233 		fight(&delta, tp->t_type, obj, FALSE);
234 	    }
235 	when WS_HASTE_M:
236 	case WS_SLOW_M:
237 	    y = hero.y;
238 	    x = hero.x;
239 	    while (step_ok(winat(y, x)))
240 	    {
241 		y += delta.y;
242 		x += delta.x;
243 	    }
244 	    if ((tp = moat(y, x)) != NULL)
245 	    {
246 		if (which_one == WS_HASTE_M)
247 		{
248 		    if (on(*tp, ISSLOW))
249 			tp->t_flags &= ~ISSLOW;
250 		    else
251 			tp->t_flags |= ISHASTE;
252 		}
253 		else
254 		{
255 		    if (on(*tp, ISHASTE))
256 			tp->t_flags &= ~ISHASTE;
257 		    else
258 			tp->t_flags |= ISSLOW;
259 		    tp->t_turn = TRUE;
260 		}
261 		delta.y = y;
262 		delta.x = x;
263 		start_run(&delta);
264 	    }
265 	when WS_ELECT:
266 	case WS_FIRE:
267 	case WS_COLD:
268 	    if (which_one == WS_ELECT)
269 		name = "bolt";
270 	    else if (which_one == WS_FIRE)
271 		name = "flame";
272 	    else
273 		name = "ice";
274 	    fire_bolt(&hero, &delta, name);
275 	    ws_know[which_one] = TRUE;
276 #ifdef DEBUG
277 	otherwise:
278 	    msg("what a bizarre schtick!");
279 #endif
280     }
281     if (--obj->o_charges < 0)
282 		obj->o_charges = 0;
283 }
284 
285 /*
286  * drain:
287  *	Do drain hit points from player schtick
288  */
289 drain()
290 {
291     THING *mp;
292     register int cnt;
293     register struct room *corp;
294     register THING **dp;
295     register bool inpass;
296     THING *drainee[40];
297 
298     /*
299      * First cnt how many things we need to spread the hit points among
300      */
301     cnt = 0;
302     if (chat(hero.y, hero.x) == DOOR)
303 	corp = &passages[flat(hero.y, hero.x) & F_PNUM];
304     else
305 	corp = NULL;
306     inpass = (proom->r_flags & ISGONE);
307     dp = drainee;
308     for (mp = mlist; mp != NULL; mp = next(mp))
309 	if (mp->t_room == proom || mp->t_room == corp ||
310 	    (inpass && chat(mp->t_pos.y, mp->t_pos.x) == DOOR &&
311 	    &passages[flat(mp->t_pos.y, mp->t_pos.x) & F_PNUM] == proom))
312 		*dp++ = mp;
313     if ((cnt = dp - drainee) == 0)
314     {
315 	msg("you have a tingling feeling");
316 	return;
317     }
318     *dp = NULL;
319     pstats.s_hpt /= 2;
320     cnt = pstats.s_hpt / cnt + 1;
321     /*
322      * Now zot all of the monsters
323      */
324     for (dp = drainee; *dp; dp++)
325     {
326 	mp = *dp;
327 	if ((mp->t_stats.s_hpt -= cnt) <= 0)
328 	    killed(mp, see_monst(mp));
329 	else
330 	    start_run(&mp->t_pos);
331     }
332 }
333 
334 /*
335  * fire_bolt:
336  *	Fire a bolt in a given direction from a specific starting place
337  */
338 fire_bolt(start, dir, name)
339 coord *start, *dir;
340 char *name;
341 {
342     register byte dirch, ch;
343     register THING *tp;
344     register bool hit_hero, used, changed;
345     register int i, j;
346     coord pos;
347 	struct {
348 		coord s_pos;
349 		byte s_under;
350 	} spotpos[BOLT_LENGTH*2];
351     THING bolt;
352     bool is_frost;
353 
354     is_frost = (strcmp(name, "frost") == 0);
355     bolt.o_type = WEAPON;
356     bolt.o_which = FLAME;
357     bolt.o_damage = bolt.o_hurldmg = "6d6";
358     bolt.o_hplus = 30;
359     bolt.o_dplus = 0;
360     w_names[FLAME] = name;
361     switch (dir->y + dir->x) {
362 	when 0: dirch = '/';
363 	when 1: case -1: dirch = (dir->y == 0 ? '-' : '|');
364 	when 2: case -2: dirch = '\\';
365     }
366 	pos = *start;
367     hit_hero = (start != &hero);
368     used = FALSE;
369     changed = FALSE;
370     for (i = 0; i < BOLT_LENGTH && !used; i++) {
371 		pos.y += dir->y;
372 		pos.x += dir->x;
373 		ch = winat(pos.y, pos.x);
374 		spotpos[i].s_pos = pos;
375 		if ((spotpos[i].s_under = mvinch(pos.y, pos.x)) == dirch)
376 			spotpos[i].s_under = 0;
377 		switch (ch) {
378 	    case DOOR:
379 	    case HWALL:
380 	    case VWALL:
381 	    case ULWALL:
382 	    case URWALL:
383 	    case LLWALL:
384 	    case LRWALL:
385 	    case ' ':
386 			if (!changed)
387 			    hit_hero = !hit_hero;
388 			changed = FALSE;
389 			dir->y = -dir->y;
390 			dir->x = -dir->x;
391 			i--;
392 			msg("the %s bounces", name);
393 			break;
394 	    default:
395 			if (!hit_hero && (tp = moat(pos.y, pos.x)) != NULL) {
396 			    hit_hero = TRUE;
397 			    changed = !changed;
398 			    if (tp->t_oldch != '@')
399 			        tp->t_oldch = chat(pos.y, pos.x);
400 			    if (!save_throw(VS_MAGIC, tp) || is_frost) {
401 					bolt.o_pos = pos;
402 					used = TRUE;
403 					if (tp->t_type == 'D' && strcmp(name, "flame") == 0)
404 					    msg("the flame bounces off the dragon");
405 					else {
406 					    hit_monster(unc(pos), &bolt);
407 						if (mvinch(unc(pos)) != dirch)
408 							spotpos[i].s_under = mvinch(unc(pos));
409 					}
410 			    } else if (ch != 'X' || tp->t_disguise == 'X') {
411 					if (start == &hero)
412 					    start_run(&pos);
413 					msg("the %s whizzes past the %s", 
414 						name, monsters[ch-'A'].m_name);
415 			    }
416 			} else if (hit_hero && ce(pos, hero)) {
417 			    hit_hero = FALSE;
418 			    changed = !changed;
419 			    if (!save(VS_MAGIC)) {
420 			    	if (is_frost) {
421 					    msg("You are frozen by a blast of frost%s.", noterse(" from the Ice Monster"));
422 			    	    if (no_command < 20)
423 							no_command += spread(7);
424 			    	} else if ((pstats.s_hpt -= roll(6, 6)) <= 0)
425 					    if (start == &hero)
426 							death('b');
427 					    else
428 							death(moat(start->y, start->x)->t_type);
429 					used = TRUE;
430 					if (!is_frost)
431 					    msg("you are hit by the %s", name);
432 			    } else
433 					msg("the %s whizzes by you", name);
434 			}
435 			if (is_frost)
436 				blue();
437 			else
438 				red();
439 			tick_pause();
440 			mvaddch(pos.y, pos.x, dirch);
441 			standend();
442 		}
443     }
444     for (j = 0; j < i; j++) {
445 		tick_pause();
446 		if (spotpos[j].s_under)
447 			mvaddch(spotpos[j].s_pos.y, spotpos[j].s_pos.x, spotpos[j].s_under);
448 	}
449 }
450 
451 /*
452  * charge_str:
453  *	Return an appropriate string for a wand charge
454  */
455 char *
456 charge_str(obj)
457 register THING *obj;
458 {
459     static char buf[20];
460 
461     if (!(obj->o_flags & ISKNOW))
462 	buf[0] = '\0';
463     else 
464 	sprintf(buf, " [%d charges]", obj->o_charges);
465     return buf;
466 }
467 