Mercurial > hg > early-roguelike
comparison arogue7/util.c @ 125:adfa37e67084
Import Advanced Rogue 7.7 from the Roguelike Restoration Project (r1490)
author | John "Elwin" Edwards |
---|---|
date | Fri, 08 May 2015 15:24:40 -0400 |
parents | |
children | b786053d2f37 |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 125:adfa37e67084 |
---|---|
1 /* | |
2 * util.c - all sorts of miscellaneous routines | |
3 * | |
4 * Advanced Rogue | |
5 * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T | |
6 * All rights reserved. | |
7 * | |
8 * Based on "Rogue: Exploring the Dungeons of Doom" | |
9 * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman | |
10 * All rights reserved. | |
11 * | |
12 * See the file LICENSE.TXT for full copyright and licensing information. | |
13 */ | |
14 | |
15 #include "curses.h" | |
16 #include "rogue.h" | |
17 #include <ctype.h> | |
18 #ifdef PC7300 | |
19 #include <track.h> | |
20 #include <kcodes.h> | |
21 #include <sys/window.h> | |
22 extern struct uwdata wdata; | |
23 #endif | |
24 | |
25 /* | |
26 * all sorts of miscellaneous routines | |
27 * | |
28 */ | |
29 | |
30 | |
31 | |
32 | |
33 /* | |
34 * this routine computes the players current AC without dex bonus's | |
35 */ | |
36 int | |
37 ac_compute(ignoremetal) | |
38 bool ignoremetal; | |
39 { | |
40 register int ac; | |
41 | |
42 ac = pstats.s_arm; /* base armor of "skin" */ | |
43 if (cur_armor) { | |
44 if (!ignoremetal || | |
45 (cur_armor->o_which != LEATHER && | |
46 cur_armor->o_which != STUDDED_LEATHER && | |
47 cur_armor->o_which != PADDED_ARMOR)) | |
48 ac -= (10 - cur_armor->o_ac); | |
49 } | |
50 if (player.t_ctype == C_MONK) | |
51 ac -= pstats.s_lvl * 2 / 3; | |
52 ac -= ring_value(R_PROTECT); | |
53 if (cur_misc[WEAR_BRACERS] != NULL) | |
54 ac -= cur_misc[WEAR_BRACERS]->o_ac; | |
55 if (cur_misc[WEAR_CLOAK] != NULL) | |
56 ac -= cur_misc[WEAR_CLOAK]->o_ac; | |
57 | |
58 /* If player has the cloak, must be wearing it */ | |
59 if (cur_relic[EMORI_CLOAK]) ac -= 5; | |
60 | |
61 if (ac > 10) | |
62 ac = 10; | |
63 return(ac); | |
64 } | |
65 | |
66 /* | |
67 * aggravate: | |
68 * aggravate all the monsters on this level | |
69 */ | |
70 | |
71 aggravate(do_uniques, do_good) | |
72 bool do_uniques, do_good; | |
73 { | |
74 register struct linked_list *mi; | |
75 register struct thing *thingptr; | |
76 | |
77 for (mi = mlist; mi != NULL; mi = next(mi)) { | |
78 thingptr = THINGPTR(mi); | |
79 if (do_good == FALSE && off(*thingptr, ISMEAN)) continue; | |
80 if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero); | |
81 } | |
82 } | |
83 | |
84 /* | |
85 * cansee: | |
86 * returns true if the hero can see a certain coordinate. | |
87 */ | |
88 | |
89 cansee(y, x) | |
90 register int y, x; | |
91 { | |
92 register struct room *rer; | |
93 register int radius; | |
94 coord tp; | |
95 | |
96 if (on(player, ISBLIND)) | |
97 return FALSE; | |
98 | |
99 tp.y = y; | |
100 tp.x = x; | |
101 rer = roomin(&tp); | |
102 | |
103 /* How far can we see? */ | |
104 if (levtype == OUTSIDE) { | |
105 if (daytime) radius = 36; | |
106 else if (lit_room(rer)) radius = 9; | |
107 else radius = 3; | |
108 } | |
109 else radius = 3; | |
110 | |
111 /* | |
112 * We can only see if the hero in the same room as | |
113 * the coordinate and the room is lit or if it is close. | |
114 */ | |
115 return ((rer != NULL && | |
116 levtype != OUTSIDE && | |
117 (levtype != MAZELEV || /* Maze level needs direct line */ | |
118 maze_view(tp.y, tp.x)) && | |
119 rer == roomin(&hero) && | |
120 lit_room(rer)) || | |
121 DISTANCE(y, x, hero.y, hero.x) < radius); | |
122 } | |
123 | |
124 /* | |
125 * check_level: | |
126 * Check to see if the guy has gone up a level. | |
127 * | |
128 * Return points needed to obtain next level. | |
129 * | |
130 * These are certain beginning experience levels for all players. | |
131 * All further experience levels are computed by muliplying by 2 | |
132 * up through MAXDOUBLE. Then the cap is added in to compute | |
133 * further levels | |
134 */ | |
135 long | |
136 check_level() | |
137 { | |
138 register int i, j, add = 0; | |
139 register unsigned long exp; | |
140 long retval; /* Return value */ | |
141 int nsides; | |
142 | |
143 pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */ | |
144 /* See if we are past the doubling stage */ | |
145 exp = char_class[player.t_ctype].cap; | |
146 if (pstats.s_exp >= exp) { | |
147 i = pstats.s_exp/exp; /* First get amount above doubling area */ | |
148 retval = exp + i * exp; /* Compute next higher boundary */ | |
149 i += MAXDOUBLE; /* Add in the previous doubled levels */ | |
150 } | |
151 else { | |
152 i = 0; | |
153 exp = char_class[player.t_ctype].start_exp; | |
154 while (exp <= pstats.s_exp) { | |
155 i++; | |
156 exp <<= 1; | |
157 } | |
158 retval = exp; | |
159 } | |
160 if (++i > pstats.s_lvl) { | |
161 nsides = char_class[player.t_ctype].hit_pts; | |
162 for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */ | |
163 add += max(1, roll(1,nsides) + const_bonus()); | |
164 max_stats.s_hpt += add; | |
165 if ((pstats.s_hpt += add) > max_stats.s_hpt) | |
166 pstats.s_hpt = max_stats.s_hpt; | |
167 msg("Welcome, %s, to level %d", | |
168 cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i); | |
169 } | |
170 pstats.s_lvl = i; | |
171 pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */ | |
172 return(retval); | |
173 } | |
174 | |
175 /* | |
176 * Used to modify the players strength | |
177 * it keeps track of the highest it has been, just in case | |
178 */ | |
179 | |
180 chg_str(amt) | |
181 register int amt; | |
182 { | |
183 register int ring_str; /* ring strengths */ | |
184 register struct stats *ptr; /* for speed */ | |
185 | |
186 ptr = &pstats; | |
187 ring_str = ring_value(R_ADDSTR); | |
188 ptr->s_str -= ring_str; | |
189 ptr->s_str += amt; | |
190 if (ptr->s_str > 25) | |
191 ptr->s_str = 25; | |
192 if (ptr->s_str > max_stats.s_str) | |
193 max_stats.s_str = ptr->s_str; | |
194 ptr->s_str += ring_str; | |
195 if (ptr->s_str <= 0) | |
196 death(D_STRENGTH); | |
197 updpack(TRUE, &player); | |
198 } | |
199 | |
200 /* | |
201 * let's confuse the player | |
202 */ | |
203 confus_player() | |
204 { | |
205 if (off(player, ISCLEAR)) | |
206 { | |
207 msg("Wait, what's going on here. Huh? What? Who?"); | |
208 if (find_slot(unconfuse)) | |
209 lengthen(unconfuse, HUHDURATION); | |
210 else | |
211 fuse(unconfuse, 0, HUHDURATION, AFTER); | |
212 turn_on(player, ISHUH); | |
213 } | |
214 else msg("You feel dizzy for a moment, but it quickly passes."); | |
215 } | |
216 | |
217 /* | |
218 * this routine computes the players current dexterity | |
219 */ | |
220 dex_compute() | |
221 { | |
222 if (cur_misc[WEAR_GAUNTLET] != NULL && | |
223 cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) { | |
224 if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED) | |
225 return (3); | |
226 else | |
227 return (18); | |
228 } | |
229 else | |
230 return (pstats.s_dext); | |
231 } | |
232 | |
233 /* | |
234 * diag_ok: | |
235 * Check to see if the move is legal if it is diagonal | |
236 */ | |
237 | |
238 diag_ok(sp, ep, flgptr) | |
239 register coord *sp, *ep; | |
240 struct thing *flgptr; | |
241 { | |
242 register int numpaths = 0; | |
243 | |
244 /* Horizontal and vertical moves are always ok */ | |
245 if (ep->x == sp->x || ep->y == sp->y) | |
246 return TRUE; | |
247 | |
248 /* Diagonal moves are not allowed if there is a horizontal or | |
249 * vertical path to the destination | |
250 */ | |
251 if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++; | |
252 if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++; | |
253 return(numpaths != 1); | |
254 } | |
255 | |
256 /* | |
257 * pick a random position around the give (y, x) coordinates | |
258 */ | |
259 coord * | |
260 fallpos(pos, be_clear, range) | |
261 register coord *pos; | |
262 bool be_clear; | |
263 int range; | |
264 { | |
265 register int tried, i, j; | |
266 register char ch; | |
267 static coord ret; | |
268 static short masks[] = { | |
269 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 }; | |
270 | |
271 /* | |
272 * Pick a spot at random centered on the position given by 'pos' and | |
273 * up to 'range' squares away from 'pos' | |
274 * | |
275 * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE | |
276 * inorder to be considered valid | |
277 * | |
278 * | |
279 * Generate a number from 0 to 8, representing the position to pick. | |
280 * Note that this DOES include the positon 'pos' itself | |
281 * | |
282 * If this position is not valid, mark it as 'tried', and pick another. | |
283 * Whenever a position is picked that has been tried before, | |
284 * sequentially find the next untried position. This eliminates costly | |
285 * random number generation | |
286 */ | |
287 | |
288 tried = 0; | |
289 while( tried != 0x1ff ) { | |
290 i = rnd(9); | |
291 while( tried & masks[i] ) | |
292 i = (i + 1) % 9; | |
293 | |
294 tried |= masks[i]; | |
295 | |
296 for( j = 1; j <= range; j++ ) { | |
297 ret.x = pos->x + j*grid[i].x; | |
298 ret.y = pos->y + j*grid[i].y; | |
299 | |
300 if (ret.x == hero.x && ret.y == hero.y) | |
301 continue; /* skip the hero */ | |
302 | |
303 if (ret.x < 0 || ret.x > cols - 1 || | |
304 ret.y < 1 || ret.y > lines - 3) | |
305 continue; /* off the screen? */ | |
306 | |
307 ch = CCHAR( winat(ret.y, ret.x) ); | |
308 | |
309 /* | |
310 * Check to make certain the spot is valid | |
311 */ | |
312 switch( ch ) { | |
313 case FLOOR: | |
314 case PASSAGE: | |
315 return( &ret ); | |
316 case GOLD: | |
317 case SCROLL: | |
318 case POTION: | |
319 case STICK: | |
320 case RING: | |
321 case WEAPON: | |
322 case ARMOR: | |
323 case MM: | |
324 case FOOD: | |
325 if(!be_clear && levtype != POSTLEV) | |
326 return( &ret ); | |
327 default: | |
328 break; | |
329 } | |
330 } | |
331 } | |
332 return( NULL ); | |
333 } | |
334 | |
335 | |
336 /* | |
337 * findmindex: | |
338 * Find the index into the monster table of a monster given its name. | |
339 */ | |
340 | |
341 findmindex(name) | |
342 char *name; | |
343 { | |
344 int which; | |
345 | |
346 for (which=1; which<NUMMONST; which++) { | |
347 if (strcmp(name, monsters[which].m_name) == 0) | |
348 break; | |
349 } | |
350 if (which >= NUMMONST) { | |
351 debug("couldn't find monster index"); | |
352 which = 1; | |
353 } | |
354 return(which); | |
355 } | |
356 | |
357 /* | |
358 * find_mons: | |
359 * Find the monster from his coordinates | |
360 */ | |
361 | |
362 struct linked_list * | |
363 find_mons(y, x) | |
364 register int y; | |
365 register int x; | |
366 { | |
367 register struct linked_list *item; | |
368 register struct thing *th; | |
369 | |
370 for (item = mlist; item != NULL; item = next(item)) | |
371 { | |
372 th = THINGPTR(item); | |
373 if (th->t_pos.y == y && th->t_pos.x == x) | |
374 return item; | |
375 } | |
376 return NULL; | |
377 } | |
378 | |
379 /* | |
380 * find_obj: | |
381 * find the unclaimed object at y, x | |
382 */ | |