Mercurial > hg > early-roguelike
comparison xrogue/bolt.c @ 133:e6179860cb76
Import XRogue 8.0 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Tue, 21 Apr 2015 08:55:20 -0400 |
parents | |
children | f54901b9c39b |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 133:e6179860cb76 |
---|---|
1 /* | |
2 bolt.c - functions shooting an object across the room | |
3 | |
4 XRogue: Expeditions into the Dungeons of Doom | |
5 Copyright (C) 1991 Robert Pietkivitch | |
6 All rights reserved. | |
7 | |
8 Based on "Advanced Rogue" | |
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T | |
10 All rights reserved. | |
11 | |
12 Based on "Rogue: Exploring the Dungeons of Doom" | |
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
14 All rights reserved. | |
15 | |
16 See the file LICENSE.TXT for full copyright and licensing information. | |
17 */ | |
18 | |
19 #include <curses.h> | |
20 #include <ctype.h> | |
21 #include "rogue.h" | |
22 | |
23 /* | |
24 * shoot_bolt fires a bolt from the given starting point in the | |
25 * given direction | |
26 */ | |
27 | |
28 shoot_bolt(shooter, start, dir, get_points, reason, name, damage) | |
29 struct thing *shooter; | |
30 coord start, dir; | |
31 bool get_points; | |
32 short reason; | |
33 char *name; | |
34 int damage; | |
35 { | |
36 unsigned char dirch = 0, ch; | |
37 bool used, change, see_him; | |
38 short y, x, bounces; | |
39 coord pos; | |
40 struct linked_list *target=NULL; | |
41 struct { | |
42 coord place; | |
43 char oldch; | |
44 } spotpos[BOLT_LENGTH]; | |
45 | |
46 switch (dir.y + dir.x) { | |
47 case 0: dirch = '/'; | |
48 when 1: case -1: dirch = (dir.y == 0 ? '-' : '|'); | |
49 when 2: case -2: dirch = '\\'; | |
50 } | |
51 pos.y = start.y + dir.y; | |
52 pos.x = start.x + dir.x; | |
53 used = FALSE; | |
54 change = FALSE; | |
55 | |
56 bounces = 0; /* No bounces yet */ | |
57 nofont(cw); | |
58 for (y = 0; y < BOLT_LENGTH && !used; y++) { | |
59 ch = winat(pos.y, pos.x); | |
60 spotpos[y].place = pos; | |
61 spotpos[y].oldch = mvwinch(cw, pos.y, pos.x); | |
62 | |
63 /* Are we at hero? */ | |
64 if (ce(pos, hero)) goto at_hero; | |
65 | |
66 switch (ch) { | |
67 case SECRETDOOR: | |
68 case VERTWALL: | |
69 case HORZWALL: | |
70 case ' ': | |
71 if (dirch == '-' || dirch == '|') { | |
72 dir.y = -dir.y; | |
73 dir.x = -dir.x; | |
74 } | |
75 else { | |
76 unsigned char chx = mvinch(pos.y-dir.y, pos.x), | |
77 chy = mvinch(pos.y, pos.x-dir.x); | |
78 bool anychange = FALSE; /* Did we change anthing */ | |
79 | |
80 if (chy == WALL || chy == SECRETDOOR || | |
81 chy == HORZWALL || chy == VERTWALL) { | |
82 dir.y = -dir.y; | |
83 change ^= TRUE; /* Change at least one direction */ | |
84 anychange = TRUE; | |
85 } | |
86 if (chx == WALL || chx == SECRETDOOR || | |
87 chx == HORZWALL || chx == VERTWALL) { | |
88 dir.x = -dir.x; | |
89 change ^= TRUE; /* Change at least one direction */ | |
90 anychange = TRUE; | |
91 } | |
92 | |
93 /* If we didn't make any change, make both changes */ | |
94 if (!anychange) { | |
95 dir.x = -dir.x; | |
96 dir.y = -dir.y; | |
97 } | |
98 } | |
99 | |
100 /* Do we change how the bolt looks? */ | |
101 if (change) { | |
102 change = FALSE; | |
103 if (dirch == '\\') dirch = '/'; | |
104 else if (dirch == '/') dirch = '\\'; | |
105 } | |
106 | |
107 y--; /* The bounce doesn't count as using up the bolt */ | |
108 | |
109 /* Make sure we aren't in an infinite bounce */ | |
110 if (++bounces > BOLT_LENGTH) used = TRUE; | |
111 msg("The %s bounces", name); | |
112 break; | |
113 default: | |
114 if (isalpha(ch)) { | |
115 register struct linked_list *item; | |
116 struct thing *tp; | |
117 register char *mname; | |
118 bool see_monster = cansee(pos.y, pos.x); | |
119 | |
120 item = find_mons(unc(pos)); | |
121 assert(item != NULL); | |
122 tp = THINGPTR(item); | |
123 mname = monster_name(tp); | |
124 | |
125 /* | |
126 * If our prey shot this, let's record the fact that | |
127 * he can shoot, regardless of whether he hits us. | |
128 */ | |
129 if (tp->t_dest != NULL && ce(*tp->t_dest, shooter->t_pos)) | |
130 tp->t_wasshot = TRUE; | |
131 | |
132 if (!save(VS_BREATH, tp, -(shooter->t_stats.s_lvl/10))) { | |
133 if (see_monster) { | |
134 if (on(*tp, ISDISGUISE) && | |
135 (tp->t_type != tp->t_disguise)) { | |
136 msg("Wait! That's a %s!", mname); | |
137 turn_off(*tp, ISDISGUISE); | |
138 } | |
139 | |
140 turn_off(*tp, CANSURPRISE); | |
141 msg("The %s hits %s", name, prname(mname, FALSE)); | |
142 } | |
143 | |
144 /* Should we start to chase the shooter? */ | |
145 if (shooter != &player && | |
146 shooter != tp && | |
147 shooter->t_index != tp->t_index && | |
148 (tp->t_dest == NULL || rnd(100) < 25)) { | |
149 /* | |
150 * If we're intelligent enough to realize that this | |
151 * is a friendly monster, we will attack the hero | |
152 * instead. | |
153 */ | |
154 if (on(*shooter, ISFRIENDLY) && | |
155 roll(3,6) < tp->t_stats.s_intel) | |
156 runto(tp, &hero); | |
157 | |
158 /* Otherwise, let's chase the monster */ | |
159 else runto(tp, &shooter->t_pos); | |
160 } | |
161 else if (shooter == &player) { | |
162 runto(tp, &hero); | |
163 | |
164 /* | |
165 * If the player shot a charmed monster, it may | |
166 * not like being shot at. | |
167 */ | |
168 if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) { | |
169 msg("The eyes of %s turn clear.", | |
170 prname(mname, FALSE)); | |
171 turn_off(*tp, ISCHARMED); | |
172 mname = monster_name(tp); | |
173 } | |
174 } | |
175 | |
176 /* | |
177 * Let the defender know that the attacker has | |
178 * missiles! | |
179 */ | |
180 if (ce(*tp->t_dest, shooter->t_pos)) | |
181 tp->t_wasshot = TRUE; | |
182 | |
183 used = TRUE; | |
184 | |
185 /* Hit the monster -- does it do anything? */ | |
186 if ((EQUAL(name,"ice") && on(*tp, NOCOLD)) || | |
187 (EQUAL(name,"flame") && on(*tp, NOFIRE)) || | |
188 (EQUAL(name,"acid") && on(*tp, NOACID)) || | |
189 (EQUAL(name,"lightning bolt")&& on(*tp,NOBOLT)) || | |
190 (EQUAL(name,"nerve gas") &&on(*tp,NOPARALYZE))|| | |
191 (EQUAL(name,"sleeping gas") && | |
192 (on(*tp, NOSLEEP) || on(*tp, ISUNDEAD))) || | |
193 (EQUAL(name,"slow gas") && on(*tp,NOSLOW)) || | |
194 (EQUAL(name,"fear gas") && on(*tp,NOFEAR)) || | |
195 (EQUAL(name,"confusion gas") && on(*tp,ISCLEAR)) || | |
196 (EQUAL(name,"chlorine gas") && on(*tp,NOGAS))) { | |
197 if (see_monster) | |
198 msg("The %s has no effect on %s.", | |
199 name, prname(mname, FALSE)); | |
200 } | |
201 | |
202 else { | |
203 see_him = !invisible(tp); | |
204 | |
205 /* Did a spell get disrupted? */ | |
206 dsrpt_monster(tp, FALSE, see_him); | |
207 | |
208 /* | |
209 * Check for gas with special effects | |
210 */ | |
211 if (EQUAL(name, "nerve gas")) { | |
212 tp->t_no_move = movement(tp) * FREEZETIME; | |
213 tp->t_action = A_FREEZE; | |
214 } | |
215 else if (EQUAL(name, "sleeping gas")) { | |
216 tp->t_no_move = movement(tp) * SLEEPTIME; | |
217 tp->t_action = A_FREEZE; | |
218 } | |
219 else if (EQUAL(name, "slow gas")) { | |
220 if (on(*tp, ISHASTE)) | |
221 turn_off(*tp, ISHASTE); | |
222 else | |
223 turn_on(*tp, ISSLOW); | |
224 } | |
225 else if (EQUAL(name, "fear gas")) { | |
226 turn_on(*tp, ISFLEE); | |
227 tp->t_dest = &hero; | |
228 | |
229 /* It is okay to turn tail */ | |
230 tp->t_oldpos = tp->t_pos; | |
231 } | |
232 else if (EQUAL(name, "confusion gas")) { | |
233 turn_on(*tp, ISHUH); | |
234 tp->t_dest = &hero; | |
235 } | |
236 else if ((EQUAL(name, "lightning bolt")) && | |
237 on(*tp, BOLTDIVIDE)) { | |
238 if (creat_mons(tp, tp->t_index, FALSE)) { | |
239 if (see_monster) | |
240 msg("The %s divides %s.", | |
241 name,prname(mname, FALSE)); | |
242 light(&hero); | |
243 } | |
244 else if (see_monster) | |
245 msg("The %s has no effect on %s.", | |
246 name, prname(mname, FALSE)); | |
247 } | |
248 else { | |
249 if (save(VS_BREATH, tp, | |
250 -(shooter->t_stats.s_lvl/10))) | |
251 damage /= 2; | |
252 | |
253 /* The poor fellow got killed! */ | |
254 if ((tp->t_stats.s_hpt -= damage) <= 0) { | |
255 if (see_monster) | |
256 msg("The %s kills %s", | |
257 name, prname(mname, FALSE)); | |
258 else | |
259 msg("You hear a faint groan in the distance"); | |
260 /* | |
261 * Instead of calling killed() here, we | |
262 * will record that the monster was killed | |
263 * and call it at the end of the routine, | |
264 * after we restore what was under the bolt. | |
265 * We have to do this because in the case | |
266 * of a bolt that first misses the monster | |
267 * and then gets it on the bounce. If we | |
268 * call killed here, the 'missed' space in | |
269 * spotpos puts the monster back on the | |
270 * screen | |
271 */ | |
272 target = item; | |
273 } | |
274 else { /* Not dead, so just scream */ | |
275 if (!see_monster) | |
276 msg("You hear a scream in the distance"); | |
277 } | |
278 } | |
279 } | |
280 } | |
281 else if (isalpha(show(pos.y, pos.x))) { | |
282 if (see_monster) { | |
283 if (terse) | |
284 msg("%s misses", name); | |
285 else | |
286 msg("The %s whizzes past %s", | |
287 name, prname(mname, FALSE)); | |
288 } | |
289 if (get_points) runto(tp, &hero); | |
290 } | |
291 } | |
292 else if (pos.y == hero.y && pos.x == hero.x) { | |
293 at_hero: if (!save(VS_BREATH, &player, | |
294 -(shooter->t_stats.s_lvl/10))){ | |
295 if (terse) | |
296 msg("The %s hits you", name); | |
297 else | |
298 msg("You are hit by the %s", name); | |
299 used = TRUE; | |
300 | |
301 /* | |
302 * The Amulet of Yendor protects against all "breath" | |
303 * | |
304 * The following two if statements could be combined | |
305 * into one, but it makes the compiler barf, so split | |
306 * it up | |
307 */ | |
308 if (cur_relic[YENDOR_AMULET] || | |
309 (EQUAL(name,"chlorine gas")&&on(player, NOGAS)) || | |
310 (EQUAL(name,"acid")&&on(player, NOACID)) || | |
311 (EQUAL(name,"sleeping gas")&&ISWEARING(R_ALERT))){ | |
312 msg("The %s has no effect", name); | |
313 } | |
314 else if((EQUAL(name, "flame") && on(player, NOFIRE)) || | |
315 (EQUAL(name, "ice") && on(player, NOCOLD)) || | |
316 (EQUAL(name,"lightning bolt")&& | |
317 on(player,NOBOLT)) || | |
318 (EQUAL(name,"fear gas")&&ISWEARING(R_HEROISM))){ | |
319 msg("The %s has no effect", name); | |
320 } | |
321 | |
322 else { | |
323 dsrpt_player(); | |
324 | |
325 /* | |
326 * Check for gas with special effects | |
327 */ | |
328 if (EQUAL(name, "nerve gas")) { | |
329 msg("The nerve gas paralyzes you."); | |
330 player.t_no_move += | |
331 movement(&player) * FREEZETIME; | |
332 player.t_action = A_FREEZE; | |
333 } | |