Mercurial > hg > early-roguelike
comparison rogue5/fight.c @ 33:f502bf60e6e4
Import Rogue 5.4 from the Roguelike Restoration Project (r1490)
author | elwin |
---|---|
date | Mon, 24 May 2010 20:10:59 +0000 |
parents | |
children | e7aab31362af |
comparison
equal
deleted
inserted
replaced
32:2dcd75e6a736 | 33:f502bf60e6e4 |
---|---|
1 /* | |
2 * All the fighting gets done here | |
3 * | |
4 * @(#)fight.c 4.67 (Berkeley) 09/06/83 | |
5 * | |
6 * Rogue: Exploring the Dungeons of Doom | |
7 * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman | |
8 * All rights reserved. | |
9 * | |
10 * See the file LICENSE.TXT for full copyright and licensing information. | |
11 */ | |
12 | |
13 #include <stdlib.h> | |
14 #include <curses.h> | |
15 #include <string.h> | |
16 #include <ctype.h> | |
17 #include "rogue.h" | |
18 | |
19 #define EQSTR(a, b) (strcmp(a, b) == 0) | |
20 | |
21 static const char *h_names[] = { /* strings for hitting */ | |
22 " scored an excellent hit on ", | |
23 " hit ", | |
24 " have injured ", | |
25 " swing and hit ", | |
26 " scored an excellent hit on ", | |
27 " hit ", | |
28 " has injured ", | |
29 " swings and hits " | |
30 }; | |
31 | |
32 static const char *m_names[] = { /* strings for missing */ | |
33 " miss", | |
34 " swing and miss", | |
35 " barely miss", | |
36 " don't hit", | |
37 " misses", | |
38 " swings and misses", | |
39 " barely misses", | |
40 " doesn't hit", | |
41 }; | |
42 | |
43 /* | |
44 * adjustments to hit probabilities due to strength | |
45 */ | |
46 static int str_plus[] = { | |
47 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, | |
48 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, | |
49 }; | |
50 | |
51 /* | |
52 * adjustments to damage done due to strength | |
53 */ | |
54 static int add_dam[] = { | |
55 -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3, | |
56 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6 | |
57 }; | |
58 | |
59 /* | |
60 * fight: | |
61 * The player attacks the monster. | |
62 */ | |
63 int | |
64 fight(const coord *mp, const THING *weap, int thrown) | |
65 { | |
66 THING *tp; | |
67 int did_hit = TRUE; | |
68 const char *mname; | |
69 int ch; | |
70 | |
71 /* | |
72 * Find the monster we want to fight | |
73 */ | |
74 if ((tp = moat(mp->y, mp->x)) == NULL) | |
75 { | |
76 #ifdef MASTER | |
77 debug("Fight what @ %d,%d", mp->y, mp->x); | |
78 #endif | |
79 return FALSE; | |
80 } | |
81 /* | |
82 * Since we are fighting, things are not quiet so no healing takes | |
83 * place. | |
84 */ | |
85 count = 0; | |
86 quiet = 0; | |
87 runto(mp); | |
88 /* | |
89 * Let him know it was really a xeroc (if it was one). | |
90 */ | |
91 ch = '\0'; | |
92 if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND)) | |
93 { | |
94 tp->t_disguise = 'X'; | |
95 if (on(player, ISHALU)) { | |
96 ch = rnd(26) + 'A'; | |
97 mvaddch(tp->t_pos.y, tp->t_pos.x, ch); | |
98 } | |
99 msg(choose_str("heavy! That's a nasty critter!", | |
100 "wait! That's a xeroc!")); | |
101 if (!thrown) | |
102 return FALSE; | |
103 } | |
104 mname = set_mname(tp); | |
105 did_hit = FALSE; | |
106 has_hit = (terse && !to_death); | |
107 if (roll_em(&player, tp, weap, thrown)) | |
108 { | |
109 did_hit = FALSE; | |
110 if (thrown) | |
111 thunk(weap, mname, terse); | |
112 else | |
113 hit(NULL, mname, terse); | |
114 if (on(player, CANHUH)) | |
115 { | |
116 did_hit = TRUE; | |
117 tp->t_flags |= ISHUH; | |
118 player.t_flags &= ~CANHUH; | |
119 endmsg(); | |
120 has_hit = FALSE; | |
121 msg("your hands stop glowing %s", pick_color("red")); | |
122 } | |
123 if (tp->t_stats.s_hpt <= 0) | |
124 killed(tp, TRUE); | |
125 else if (did_hit && !on(player, ISBLIND)) | |
126 msg("%s appears confused", mname); | |
127 did_hit = TRUE; | |
128 } | |
129 else | |
130 if (thrown) | |
131 bounce(weap, mname, terse); | |
132 else | |
133 miss(NULL, mname, terse); | |
134 return did_hit; | |
135 } | |
136 | |
137 /* | |
138 * attack: | |
139 * The monster attacks the player | |
140 */ | |
141 int | |
142 attack(THING *mp) | |
143 { | |
144 const char *mname; | |
145 int oldhp; | |
146 | |
147 /* | |
148 * Since this is an attack, stop running and any healing that was | |
149 * going on at the time. | |
150 */ | |
151 running = FALSE; | |
152 count = 0; | |
153 quiet = 0; | |
154 if (to_death && !on(*mp, ISTARGET)) | |
155 { | |
156 to_death = FALSE; | |
157 kamikaze = FALSE; | |
158 } | |
159 if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(player, ISBLIND)) | |
160 { | |
161 mp->t_disguise = 'X'; | |
162 if (on(player, ISHALU)) | |
163 mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A'); | |
164 } | |
165 mname = set_mname(mp); | |
166 oldhp = pstats.s_hpt; | |
167 if (roll_em(mp, &player, NULL, FALSE)) | |
168 { | |
169 if (mp->t_type != 'I') | |
170 { | |
171 if (has_hit) | |
172 addmsg(". "); | |
173 hit(mname, NULL, FALSE); | |
174 } | |
175 else | |
176 if (has_hit) | |
177 endmsg(); | |
178 has_hit = FALSE; | |
179 if (pstats.s_hpt <= 0) | |
180 death(mp->t_type); /* Bye bye life ... */ | |
181 else if (!kamikaze) | |
182 { | |
183 oldhp -= pstats.s_hpt; | |
184 if (oldhp > max_hit) | |
185 max_hit = oldhp; | |
186 if (pstats.s_hpt <= max_hit) | |
187 to_death = FALSE; | |
188 } | |
189 if (!on(*mp, ISCANC)) | |
190 switch (mp->t_type) | |
191 { | |
192 case 'A': | |
193 /* | |
194 * If an aquator hits, you can lose armor class. | |
195 */ | |
196 rust_armor(cur_armor); | |
197 when 'I': | |
198 /* | |
199 * The ice monster freezes you | |
200 */ | |
201 player.t_flags &= ~ISRUN; | |
202 if (!no_command) | |
203 { | |
204 addmsg("you are frozen"); | |
205 if (!terse) | |
206 addmsg(" by the %s", mname); | |
207 endmsg(); | |
208 } | |
209 no_command += rnd(2) + 2; | |
210 if (no_command > BORE_LEVEL) | |
211 death('h'); | |
212 when 'R': | |
213 /* | |
214 * Rattlesnakes have poisonous bites | |
215 */ | |
216 if (!save(VS_POISON)) | |
217 { | |
218 if (!ISWEARING(R_SUSTSTR)) | |
219 { | |
220 chg_str(-1); | |
221 if (!terse) | |
222 msg("you feel a bite in your leg and now feel weaker"); | |
223 else | |
224 msg("a bite has weakened you"); | |
225 } | |
226 else if (!to_death) | |
227 { | |
228 if (!terse) | |
229 msg("a bite momentarily weakens you"); | |
230 else | |
231 msg("bite has no effect"); | |
232 } | |
233 } | |
234 when 'W': | |
235 case 'V': | |
236 /* | |
237 * Wraiths might drain energy levels, and Vampires | |
238 * can steal max_hp | |
239 */ | |
240 if (rnd(100) < (mp->t_type == 'W' ? 15 : 30)) | |
241 { | |
242 int fewer; | |
243 | |
244 if (mp->t_type == 'W') | |
245 { | |
246 if (pstats.s_exp == 0) | |
247 death('W'); /* All levels gone */ | |
248 if (--pstats.s_lvl == 0) | |
249 { | |
250 pstats.s_exp = 0; | |
251 pstats.s_lvl = 1; | |
252 } | |
253 else | |
254 pstats.s_exp = e_levels[pstats.s_lvl-1]+1; | |
255 fewer = roll(1, 10); | |
256 } | |
257 else | |
258 fewer = roll(1, 3); | |
259 pstats.s_hpt -= fewer; | |
260 max_hp -= fewer; | |
261 if (pstats.s_hpt <= 0) | |
262 pstats.s_hpt = 1; | |
263 if (max_hp <= 0) | |
264 death(mp->t_type); | |
265 msg("you suddenly feel weaker"); | |
266 } | |
267 when 'F': | |
268 /* | |
269 * Venus Flytrap stops the poor guy from moving | |
270 */ | |
271 player.t_flags |= ISHELD; | |
272 sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++vf_hit); | |
273 if (--pstats.s_hpt <= 0) | |
274 death('F'); | |
275 when 'L': | |
276 { | |
277 /* | |
278 * Leperachaun steals some gold | |
279 */ | |
280 int lastpurse; | |
281 | |
282 lastpurse = purse; | |
283 purse -= GOLDCALC; | |
284 if (!save(VS_MAGIC)) | |
285 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; | |
286 if (purse < 0) | |
287 purse = 0; | |
288 remove_mon(&mp->t_pos, mp, FALSE); | |
289 mp=NULL; | |
290 if (purse != lastpurse) | |
291 msg("your purse feels lighter"); | |
292 } | |
293 when 'N': | |
294 { | |
295 THING *obj, *steal; | |
296 int nobj; | |
297 | |
298 /* | |
299 * Nymph's steal a magic item, look through the pack | |
300 * and pick out one we like. | |
301 */ | |
302 steal = NULL; | |
303 for (nobj = 0, obj = pack; obj != NULL; obj = next(obj)) | |
304 if (obj != cur_armor && obj != cur_weapon | |
305 && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] | |
306 && is_magic(obj) && rnd(++nobj) == 0) | |
307 steal = obj; | |
308 if (steal != NULL) | |
309 { | |
310 remove_mon(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE); | |
311 mp=NULL; | |
312 steal = leave_pack(steal, TRUE, FALSE); | |
313 msg("she stole %s!", inv_name(steal, TRUE)); | |
314 discard(steal); | |
315 } | |
316 } | |
317 otherwise: | |
318 break; | |
319 } | |
320 } | |
321 else if (mp->t_type != 'I') | |
322 { | |
323 if (has_hit) | |
324 { | |
325 addmsg(". "); | |
326 has_hit = FALSE; | |
327 } | |
328 if (mp->t_type == 'F') | |
329 { | |
330 pstats.s_hpt -= vf_hit; | |
331 if (pstats.s_hpt <= 0) | |
332 death(mp->t_type); /* Bye bye life ... */ | |
333 } | |
334 miss(mname, NULL, FALSE); | |
335 } | |
336 if (fight_flush && !to_death) | |
337 flush_type(); | |
338 count = 0; | |
339 status(); | |
340 if (mp == NULL) | |
341 return(-1); | |
342 else | |
343 return(0); | |
344 } | |
345 | |
346 /* | |
347 * set_mname: | |
348 * return the monster name for the given monster | |
349 */ | |
350 const char * | |
351 set_mname(const THING *tp) | |
352 { | |
353 int ch; | |
354 const char *mname; | |
355 static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' }; | |
356 | |
357 if (!see_monst(tp) && !on(player, SEEMONST)) | |
358 return (terse ? "it" : "something"); | |
359 else if (on(player, ISHALU)) | |
360 { | |
361 move(tp->t_pos.y, tp->t_pos.x); | |
362 ch = toascii(CCHAR(inch())); | |
363 if (!isupper(ch)) | |
364 ch = rnd(26); | |
365 else | |
366 ch -= 'A'; | |
367 mname = monsters[ch].m_name; | |
368 } | |
369 else | |
370 mname = monsters[tp->t_type - 'A'].m_name; | |
371 strcpy(&tbuf[4], mname); | |
372 return tbuf; | |
373 } | |
374 | |
375 /* | |
376 * swing: | |
377 * Returns true if the swing hits | |
378 */ | |
379 int | |
380 swing(int at_lvl, int op_arm, int wplus) | |
381 { | |
382 int res = rnd(20); | |
383 int need = (20 - at_lvl) - op_arm; | |