Rogue 3.6 reconstruction from http://rogue.rogueforge.net/rogue36/.
[rogue-pphs.git] / sticks.c
1 /*
2 * Functions to implement the various sticks one might find
3 * while wandering around the dungeon.
4 *
5 * @(#)sticks.c 3.14 (Berkeley) 6/15/81
6 *
7 * Rogue: Exploring the Dungeons of Doom
8 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
9 * All rights reserved.
10 *
11 * See the file LICENSE.TXT for full copyright and licensing information.
12 */
13
14 #include "curses.h"
15 #include <ctype.h>
16 #include <string.h>
17 #include "rogue.h"
18
19 fix_stick(cur)
20 register struct object *cur;
21 {
22 if (strcmp(ws_type[cur->o_which], "staff") == 0)
23 strcpy(cur->o_damage,"2d3");
24 else
25 strcpy(cur->o_damage,"1d1");
26 strcpy(cur->o_hurldmg,"1d1");
27
28 cur->o_charges = 3 + rnd(5);
29 switch (cur->o_which)
30 {
31 case WS_HIT:
32 cur->o_hplus = 3;
33 cur->o_dplus = 3;
34 strcpy(cur->o_damage,"1d8");
35 when WS_LIGHT:
36 cur->o_charges = 10 + rnd(10);
37 }
38 }
39
40 do_zap(gotdir)
41 bool gotdir;
42 {
43 register struct linked_list *item;
44 register struct object *obj;
45 register struct room *rp;
46 register struct thing *tp;
47 register int y, x;
48
49 if ((item = get_item("zap with", STICK)) == NULL)
50 return;
51 obj = (struct object *) ldata(item);
52 if (obj->o_type != STICK)
53 {
54 msg("You can't zap with that!");
55 after = FALSE;
56 return;
57 }
58 if (obj->o_charges == 0)
59 {
60 msg("Nothing happens.");
61 return;
62 }
63 if (!gotdir)
64 do {
65 delta.y = rnd(3) - 1;
66 delta.x = rnd(3) - 1;
67 } while (delta.y == 0 && delta.x == 0);
68 switch (obj->o_which)
69 {
70 case WS_LIGHT:
71 /*
72 * Reddy Kilowat wand. Light up the room
73 */
74 ws_know[WS_LIGHT] = TRUE;
75 if ((rp = roomin(&hero)) == NULL)
76 msg("The corridor glows and then fades");
77 else
78 {
79 addmsg("The room is lit");
80 if (!terse)
81 addmsg(" by a shimmering blue light.");
82 endmsg();
83 rp->r_flags &= ~ISDARK;
84 /*
85 * Light the room and put the player back up
86 */
87 light(&hero);
88 mvwaddch(cw, hero.y, hero.x, PLAYER);
89 }
90 when WS_DRAIN:
91 /*
92 * Take away 1/2 of hero's hit points, then take it away
93 * evenly from the monsters in the room (or next to hero
94 * if he is in a passage)
95 */
96 if (pstats.s_hpt < 2)
97 {
98 msg("You are too weak to use it.");
99 return;
100 }
101 else if ((rp = roomin(&hero)) == NULL)
102 drain(hero.y-1, hero.y+1, hero.x-1, hero.x+1);
103 else
104 drain(rp->r_pos.y, rp->r_pos.y+rp->r_max.y,
105 rp->r_pos.x, rp->r_pos.x+rp->r_max.x);
106 when WS_POLYMORPH:
107 case WS_TELAWAY:
108 case WS_TELTO:
109 case WS_CANCEL:
110 {
111 register char monster, oldch;
112 register int rm;
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 (isupper(monster = mvwinch(mw, y, x)))
122 {
123 register char omonst = monster;
124
125 if (monster == 'F')
126 player.t_flags &= ~ISHELD;
127 item = find_mons(y, x);
128 tp = (struct thing *) ldata(item);
129 if (obj->o_which == WS_POLYMORPH)
130 {
131 detach(mlist, item);
132 oldch = tp->t_oldch;
133 delta.y = y;
134 delta.x = x;
135 new_monster(item, monster = rnd(26) + 'A', &delta);
136 if (!(tp->t_flags & ISRUN))
137 runto(&delta, &hero);
138 if (isupper(mvwinch(cw, y, x)))
139 mvwaddch(cw, y, x, monster);
140 tp->t_oldch = oldch;
141 ws_know[WS_POLYMORPH] |= (monster != omonst);
142 }
143 else if (obj->o_which == WS_CANCEL)
144 {
145 tp->t_flags |= ISCANC;
146 tp->t_flags &= ~ISINVIS;
147 }
148 else
149 {
150 if (obj->o_which == WS_TELAWAY)
151 {
152 do
153 {
154 rm = rnd_room();
155 rnd_pos(&rooms[rm], &tp->t_pos);
156 } until(winat(tp->t_pos.y, tp->t_pos.x) == FLOOR);
157 }
158 else
159 {
160 tp->t_pos.y = hero.y + delta.y;
161 tp->t_pos.x = hero.x + delta.x;
162 }
163 if (isupper(mvwinch(cw, y, x)))
164 mvwaddch(cw, y, x, tp->t_oldch);
165 tp->t_dest = &hero;
166 tp->t_flags |= ISRUN;
167 mvwaddch(mw, y, x, ' ');
168 mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, monster);
169 if (tp->t_pos.y != y || tp->t_pos.x != x)
170 tp->t_oldch = mvwinch(cw, tp->t_pos.y, tp->t_pos.x);
171 }
172 }
173 }
174 when WS_MISSILE:
175 {
176 static struct object bolt =
177 {
178 '*' , {0, 0}, 0, "", "1d4" , 0, 0, 100, 1, 0, 0, 0
179 };
180
181 do_motion(&bolt, delta.y, delta.x);
182 if (isupper(mvwinch(mw, bolt.o_pos.y, bolt.o_pos.x))
183 && !save_throw(VS_MAGIC, ldata(find_mons(unc(bolt.o_pos)))))
184 hit_monster(unc(bolt.o_pos), &bolt);
185 else if (terse)
186 msg("Missile vanishes");
187 else
188 msg("The missile vanishes with a puff of smoke");
189 ws_know[WS_MISSILE] = TRUE;
190 }
191 when WS_HIT:
192 {
193 register char ch;
194
195 delta.y += hero.y;
196 delta.x += hero.x;
197 ch = winat(delta.y, delta.x);
198 if (isupper(ch))
199 {
200 if (rnd(20) == 0)
201 {
202 strcpy(obj->o_damage,"3d8");
203 obj->o_dplus = 9;
204 }
205 else
206 {
207 strcpy(obj->o_damage,"1d8");
208 obj->o_dplus = 3;
209 }
210 fight(&delta, ch, obj, FALSE);
211 }
212 }
213 when WS_HASTE_M:
214 case WS_SLOW_M:
215 y = hero.y;
216 x = hero.x;
217 while (step_ok(winat(y, x)))
218 {
219 y += delta.y;
220 x += delta.x;
221 }
222 if (isupper(mvwinch(mw, y, x)))
223 {
224 item = find_mons(y, x);
225 tp = (struct thing *) ldata(item);
226 if (obj->o_which == WS_HASTE_M)
227 {
228 if (on(*tp, ISSLOW))
229 tp->t_flags &= ~ISSLOW;
230 else
231 tp->t_flags |= ISHASTE;
232 }
233 else
234 {
235 if (on(*tp, ISHASTE))
236 tp->t_flags &= ~ISHASTE;
237 else
238 tp->t_flags |= ISSLOW;
239 tp->t_turn = TRUE;
240 }
241 delta.y = y;
242 delta.x = x;
243 runto(&delta, &hero);
244 }
245 when WS_ELECT:
246 case WS_FIRE:
247 case WS_COLD:
248 {
249 register char dirch, ch, *name;
250 register bool bounced, used;
251 coord pos;
252 coord spotpos[BOLT_LENGTH];
253 static struct object bolt =
254 {
255 '*' , {0, 0}, 0, "", "6d6" , 0, 0, 100, 0, 0, 0 ,0
256 };
257
258
259 switch (delta.y + delta.x)
260 {
261 case 0: dirch = '/';
262 when 1: case -1: dirch = (delta.y == 0 ? '-' : '|');
263 when 2: case -2: dirch = '\\';
264 }
265 pos = hero;
266 bounced = FALSE;
267 used = FALSE;
268 if (obj->o_which == WS_ELECT)
269 name = "bolt";
270 else if (obj->o_which == WS_FIRE)
271 name = "flame";
272 else
273 name = "ice";
274 for (y = 0; y < BOLT_LENGTH && !used; y++)
275 {
276 ch = winat(pos.y, pos.x);
277 spotpos[y] = pos;
278 switch (ch)
279 {
280 case DOOR:
281 case SECRETDOOR:
282 case '|':
283 case '-':
284 case ' ':
285 bounced = TRUE;
286 delta.y = -delta.y;
287 delta.x = -delta.x;
288 y--;
289 msg("The bolt bounces");
290 break;
291 default:
292 if (!bounced && isupper(ch))
293 {
294 if (!save_throw(VS_MAGIC, ldata(find_mons(unc(pos)))))
295 {
296 bolt.o_pos = pos;
297 hit_monster(unc(pos), &bolt);
298 used = TRUE;
299 }
300 else if (ch != 'M' || show(pos.y, pos.x) == 'M')
301 {
302 if (terse)
303 msg("%s misses", name);
304 else
305 msg("The %s whizzes past the %s", name, monsters[ch-'A'].m_name);
306 runto(&pos, &hero);
307 }
308 }
309 else if (bounced && pos.y == hero.y && pos.x == hero.x)
310 {
311 bounced = FALSE;
312 if (!save(VS_MAGIC))
313 {
314 if (terse)
315 msg("The %s hits", name);
316 else
317 msg("You are hit by the %s", name);
318 if ((pstats.s_hpt -= roll(6, 6)) <= 0)
319 death('b');
320 used = TRUE;
321 }
322 else
323 msg("The %s whizzes by you", name);
324 }
325 mvwaddch(cw, pos.y, pos.x, dirch);
326 draw(cw);
327 }
328 pos.y += delta.y;
329 pos.x += delta.x;
330 }
331 for (x = 0; x < y; x++)
332 mvwaddch(cw, spotpos[x].y, spotpos[x].x, show(spotpos[x].y, spotpos[x].x));
333 ws_know[obj->o_which] = TRUE;
334 }
335 otherwise:
336 msg("What a bizarre schtick!");
337 }
338 obj->o_charges--;
339 }
340
341 /*
342 * drain:
343 * Do drain hit points from player shtick
344 */
345
346 drain(ymin, ymax, xmin, xmax)
347 int ymin, ymax, xmin, xmax;
348 {
349 register int i, j, count;
350 register struct thing *ick;
351 register struct linked_list *item;
352
353 /*
354 * First count how many things we need to spread the hit points among
355 */
356 count = 0;
357 for (i = ymin; i <= ymax; i++)
358 for (j = xmin; j <= xmax; j++)
359 if (isupper(mvwinch(mw, i, j)))
360 count++;
361 if (count == 0)
362 {
363 msg("You have a tingling feeling");
364 return;
365 }
366 count = pstats.s_hpt / count;
367 pstats.s_hpt /= 2;
368 /*
369 * Now zot all of the monsters
370 */
371 for (i = ymin; i <= ymax; i++)
372 for (j = xmin; j <= xmax; j++)
373 if (isupper(mvwinch(mw, i, j)) &&
374 ((item = find_mons(i, j)) != NULL))
375 {
376 ick = (struct thing *) ldata(item);
377 if ((ick->t_stats.s_hpt -= count) < 1)
378 killed(item, cansee(i, j) && !on(*ick, ISINVIS));
379 }
380 }
381
382 /*
383 * charge a wand for wizards.
384 */
385 char *
386 charge_str(obj)
387 register struct object *obj;
388 {
389 static char buf[20];
390
391 if (!(obj->o_flags & ISKNOW))
392 buf[0] = '\0';
393 else if (terse)
394 sprintf(buf, " [%d]", obj->o_charges);
395 else
396 sprintf(buf, " [%d charges]", obj->o_charges);
397 return buf;
398 }