Mercurial > hg > early-roguelike
comparison rogue5/misc.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 |
comparison
equal
deleted
inserted
replaced
32:2dcd75e6a736 | 33:f502bf60e6e4 |
---|---|
1 /* | |
2 * All sorts of miscellaneous routines | |
3 * | |
4 * @(#)misc.c 4.66 (Berkeley) 08/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 /* | |
20 * look: | |
21 * A quick glance all around the player | |
22 */ | |
23 #undef DEBUG | |
24 | |
25 | |
26 void | |
27 look(int wakeup) | |
28 { | |
29 int x, y; | |
30 chtype ch; | |
31 THING *tp; | |
32 PLACE *pp; | |
33 struct room *rp; | |
34 int ey, ex; | |
35 int passcount; | |
36 int pfl, *fp, pch; | |
37 int sy, sx, sumhero = 0, diffhero = 0; | |
38 # ifdef DEBUG | |
39 static int done = FALSE; | |
40 | |
41 if (done) | |
42 return; | |
43 done = TRUE; | |
44 # endif /* DEBUG */ | |
45 passcount = 0; | |
46 rp = proom; | |
47 if (!ce(oldpos, hero)) | |
48 { | |
49 erase_lamp(&oldpos, oldrp); | |
50 oldpos = hero; | |
51 oldrp = rp; | |
52 } | |
53 ey = hero.y + 1; | |
54 ex = hero.x + 1; | |
55 sx = hero.x - 1; | |
56 sy = hero.y - 1; | |
57 if (door_stop && !firstmove && running) | |
58 { | |
59 sumhero = hero.y + hero.x; | |
60 diffhero = hero.y - hero.x; | |
61 } | |
62 pp = INDEX(hero.y, hero.x); | |
63 pch = pp->p_ch; | |
64 pfl = pp->p_flags; | |
65 | |
66 for (y = sy; y <= ey; y++) | |
67 if (y > 0 && y < NUMLINES - 1) for (x = sx; x <= ex; x++) | |
68 { | |
69 if (x < 0 || x >= NUMCOLS) | |
70 continue; | |
71 if (!on(player, ISBLIND)) | |
72 { | |
73 if (y == hero.y && x == hero.x) | |
74 continue; | |
75 } | |
76 | |
77 pp = INDEX(y, x); | |
78 ch = pp->p_ch; | |
79 if (ch == ' ') /* nothing need be done with a ' ' */ | |
80 continue; | |
81 fp = &pp->p_flags; | |
82 if (pch != DOOR && ch != DOOR) | |
83 if ((pfl & F_PASS) != (*fp & F_PASS)) | |
84 continue; | |
85 if (((*fp & F_PASS) || ch == DOOR) && | |
86 ((pfl & F_PASS) || pch == DOOR)) | |
87 { | |
88 if (hero.x != x && hero.y != y && | |
89 !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) | |
90 continue; | |
91 } | |
92 | |
93 if ((tp = pp->p_monst) == NULL) | |
94 ch = trip_ch(y, x, ch); | |
95 else | |
96 if (on(player, SEEMONST) && on(*tp, ISINVIS)) | |
97 { | |
98 if (door_stop && !firstmove) | |
99 running = FALSE; | |
100 continue; | |
101 } | |
102 else | |
103 { | |
104 if (wakeup) | |
105 wake_monster(y, x); | |
106 if (see_monst(tp)) | |
107 { | |
108 if (on(player, ISHALU)) | |
109 ch = rnd(26) + 'A'; | |
110 else | |
111 ch = tp->t_disguise; | |
112 } | |
113 } | |
114 if (on(player, ISBLIND) && (y != hero.y || x != hero.x)) | |
115 continue; | |
116 | |
117 move(y, x); | |
118 | |
119 if ((proom->r_flags & ISDARK) && !see_floor && ch == FLOOR) | |
120 ch = ' '; | |
121 | |
122 if (tp != NULL || ch != CCHAR( inch() )) | |
123 addch(ch); | |
124 | |
125 if (door_stop && !firstmove && running) | |
126 { | |
127 switch (runch) | |
128 { | |
129 case 'h': | |
130 if (x == ex) | |
131 continue; | |
132 when 'j': | |
133 if (y == sy) | |
134 continue; | |
135 when 'k': | |
136 if (y == ey) | |
137 continue; | |
138 when 'l': | |
139 if (x == sx) | |
140 continue; | |
141 when 'y': | |
142 if ((y + x) - sumhero >= 1) | |
143 continue; | |
144 when 'u': | |
145 if ((y - x) - diffhero >= 1) | |
146 continue; | |
147 when 'n': | |
148 if ((y + x) - sumhero <= -1) | |
149 continue; | |
150 when 'b': | |
151 if ((y - x) - diffhero <= -1) | |
152 continue; | |
153 } | |
154 switch (ch) | |
155 { | |
156 case DOOR: | |
157 if (x == hero.x || y == hero.y) | |
158 running = FALSE; | |
159 break; | |
160 case PASSAGE: | |
161 if (x == hero.x || y == hero.y) | |
162 passcount++; | |
163 break; | |
164 case FLOOR: | |
165 case '|': | |
166 case '-': | |
167 case ' ': | |
168 break; | |
169 default: | |
170 running = FALSE; | |
171 break; | |
172 } | |
173 } | |
174 } | |
175 if (door_stop && !firstmove && passcount > 1) | |
176 running = FALSE; | |
177 if (!running || !jump) | |
178 mvaddch(hero.y, hero.x, PLAYER); | |
179 # ifdef DEBUG | |
180 done = FALSE; | |
181 # endif /* DEBUG */ | |
182 } | |
183 | |
184 /* | |
185 * trip_ch: | |
186 * Return the character appropriate for this space, taking into | |
187 * account whether or not the player is tripping. | |
188 */ | |
189 int | |
190 trip_ch(int y, int x, int ch) | |
191 { | |
192 if (on(player, ISHALU) && after) | |
193 switch (ch) | |
194 { | |
195 case FLOOR: | |
196 case ' ': | |
197 case PASSAGE: | |
198 case '-': | |
199 case '|': | |
200 case DOOR: | |
201 case TRAP: | |
202 break; | |
203 default: | |
204 if (y != stairs.y || x != stairs.x || !seenstairs) | |
205 ch = rnd_thing(); | |
206 break; | |
207 } | |
208 return ch; | |
209 } | |
210 | |
211 /* | |
212 * erase_lamp: | |
213 * Erase the area shown by a lamp in a dark room. | |
214 */ | |
215 | |
216 void | |
217 erase_lamp(const coord *pos, const struct room *rp) | |
218 { | |
219 int y, x, ey, sy, ex; | |
220 | |
221 if (!(see_floor && (rp->r_flags & (ISGONE|ISDARK)) == ISDARK | |
222 && !on(player,ISBLIND))) | |
223 return; | |
224 | |
225 ey = pos->y + 1; | |
226 ex = pos->x + 1; | |
227 sy = pos->y - 1; | |
228 for (x = pos->x - 1; x <= ex; x++) | |
229 for (y = sy; y <= ey; y++) | |
230 { | |
231 if (y == hero.y && x == hero.x) | |
232 continue; | |
233 move(y, x); | |
234 if (CCHAR( inch() ) == FLOOR) | |
235 addch(' '); | |
236 } | |
237 } | |
238 | |
239 /* | |
240 * show_floor: | |
241 * Should we show the floor in her room at this time? | |
242 */ | |
243 int | |
244 show_floor(void) | |
245 { | |
246 if ((proom->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(player, ISBLIND)) | |
247 return see_floor; | |
248 else | |
249 return TRUE; | |
250 } | |
251 | |
252 /* | |
253 * find_obj: | |
254 * Find the unclaimed object at y, x | |
255 */ | |
256 THING * | |
257 find_obj(int y, int x) | |
258 { | |
259 THING *obj; | |
260 | |
261 for (obj = lvl_obj; obj != NULL; obj = next(obj)) | |
262 { | |
263 if (obj->o_pos.y == y && obj->o_pos.x == x) | |
264 return obj; | |
265 } | |
266 #ifdef MASTER | |
267 sprintf(prbuf, "Non-object %d,%d", y, x); | |
268 msg(prbuf); | |
269 return NULL; | |
270 #else | |
271 /* NOTREACHED */ | |
272 return NULL; | |
273 #endif | |
274 } | |
275 | |
276 /* | |
277 * eat: | |
278 * She wants to eat something, so let her try | |
279 */ | |
280 | |
281 void | |
282 eat(void) | |
283 { | |
284 THING *obj; | |
285 | |
286 if ((obj = get_item("eat", FOOD)) == NULL) | |
287 return; | |
288 if (obj->o_type != FOOD) | |
289 { | |
290 if (!terse) | |
291 msg("ugh, you would get ill if you ate that"); | |
292 else | |
293 msg("that's Inedible!"); | |
294 return; | |
295 } | |
296 if (food_left < 0) | |
297 food_left = 0; | |
298 if ((food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE) | |
299 food_left = STOMACHSIZE; | |
300 hungry_state = 0; | |
301 if (obj == cur_weapon) | |
302 cur_weapon = NULL; | |
303 if (obj->o_which == 1) | |
304 msg("my, that was a yummy %s", fruit); | |
305 else | |
306 if (rnd(100) > 70) | |
307 { | |
308 pstats.s_exp++; | |
309 msg("%s, this food tastes awful", choose_str("bummer", "yuk")); | |
310 check_level(); | |
311 } | |
312 else | |
313 msg("%s, that tasted good", choose_str("oh, wow", "yum")); | |
314 leave_pack(obj, FALSE, FALSE); | |
315 } | |
316 | |
317 /* | |
318 * check_level: | |
319 * Check to see if the guy has gone up a level. | |
320 */ | |
321 | |
322 void | |
323 check_level(void) | |
324 { | |
325 int i, add, olevel; | |
326 | |
327 for (i = 0; e_levels[i] != 0; i++) | |
328 if (e_levels[i] > pstats.s_exp) | |
329 break; | |
330 i++; | |
331 olevel = pstats.s_lvl; | |
332 pstats.s_lvl = i; | |
333 if (i > olevel) | |
334 { | |
335 add = roll(i - olevel, 10); | |
336 max_hp += add; | |
337 pstats.s_hpt += add; | |
338 msg("welcome to level %d", i); | |
339 } | |
340 } | |
341 | |
342 /* | |
343 * chg_str: | |
344 * used to modify the playes strength. It keeps track of the | |
345 * highest it has been, just in case | |
346 */ | |
347 | |
348 void | |
349 chg_str(int amt) | |
350 { | |
351 int comp; | |
352 | |
353 if (amt == 0) | |
354 return; | |
355 add_str(&pstats.s_str, amt); | |
356 comp = pstats.s_str; | |
357 if (ISRING(LEFT, R_ADDSTR)) | |
358 add_str(&comp, -cur_ring[LEFT]->o_arm); | |
359 if (ISRING(RIGHT, R_ADDSTR)) | |
360 add_str(&comp, -cur_ring[RIGHT]->o_arm); | |
361 if (comp > max_stats.s_str) | |
362 max_stats.s_str = comp; | |
363 } | |
364 | |
365 /* | |
366 * add_str: | |
367 * Perform the actual add, checking upper and lower bound limits | |
368 */ | |
369 void | |
370 add_str(int *sp, int amt) | |
371 { | |
372 if ((*sp += amt) < 3) | |
373 *sp = 3; | |
374 else if (*sp > 31) | |
375 *sp = 31; | |
376 } | |
377 | |
378 /* | |
379 * add_haste: | |
380 * Add a haste to the player | |
381 */ | |
382 int | |
383 add_haste(int potion) | |
384 { | |
385 if (on(player, ISHASTE)) | |
386 { | |
387 no_command += rnd(8); | |
388 player.t_flags &= ~(ISRUN|ISHASTE); | |
389 extinguish(nohaste); | |
390 msg("you faint from exhaustion"); | |
391 return FALSE; | |
392 } | |
393 else | |
394 { | |
395 player.t_flags |= ISHASTE; | |
396 if (potion) | |
397 fuse(nohaste, 0, rnd(4)+4, AFTER); | |
398 return TRUE; | |
399 } | |
400 } | |
401 | |
402 /* | |
403 * aggravate: | |
404 * Aggravate all the monsters on this level | |
405 */ | |
406 | |
407 void | |
408 aggravate(void) | |
409 { | |
410 THING *mp; | |
411 | |
412 for (mp = mlist; mp != NULL; mp = next(mp)) | |
413 runto(&mp->t_pos); | |
414 } | |
415 | |
416 /* | |
417 * vowelstr: | |
418 * For printfs: if string starts with a vowel, return "n" for an | |
419 * "an". | |
420 */ | |
421 char * | |
422 vowelstr(const char *str) | |
423 { | |
424 switch (*str) | |
425 { | |
426 case 'a': case 'A': | |
427 case 'e': case 'E': | |
428 case 'i': case 'I': | |
429 case 'o': case 'O': | |
430 case 'u': case 'U': | |
431 return "n"; | |
432 default: | |
433 return ""; | |
434 } | |
435 } | |
436 | |
437 /* | |
438 * is_current: | |
439 * See if the object is one of the currently used items | |
440 */ | |
441 int | |
442 is_current(const THING *obj) | |
443 { | |
444 if (obj == NULL) | |
445 return FALSE; | |
446 if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT] | |
447 || obj == cur_ring[RIGHT]) | |
448 { | |
449 if (!terse) | |
450 addmsg("That's already "); | |
451 msg("in use"); | |
452 return TRUE; | |
453 } | |
454 return FALSE; | |
455 } | |
456 | |
457 /* | |
458 * get_dir: | |
459 * Set up the direction co_ordinate for use in varios "prefix" | |
460 * commands | |
461 */ | |
462 int | |
463 get_dir(void) | |
464 { | |
465 char *prompt; | |
466 int gotit; | |
467 static coord last_delt= {0,0}; | |
468 | |
469 if (again && last_dir != '\0') | |
470 { | |
471 delta.y = last_delt.y; | |
472 delta.x = last_delt.x; | |
473 dir_ch = last_dir; | |
474 } | |
475 else | |
476 { | |
477 if (!terse) | |
478 msg(prompt = "which direction? "); | |
479 else | |
480 prompt = "direction: "; | |
481 do | |
482 { | |
483 gotit = TRUE; | |
484 switch (dir_ch = readchar()) | |
485 { | |
486 case 'h': case'H': delta.y = 0; delta.x = -1; | |
487 when 'j': case'J': delta.y = 1; delta.x = 0; | |
488 when 'k': case'K': delta.y = -1; delta.x = 0; | |
489 when 'l': case'L': delta.y = 0; delta.x = 1; | |
490 when 'y': case'Y': delta.y = -1; delta.x = -1; | |
491 when 'u': case'U': delta.y = -1; delta.x = 1; | |
492 when 'b': case'B': delta.y = 1; delta.x = -1; | |
493 when 'n': case'N': delta.y = 1; delta.x = 1; | |
494 when ESCAPE: last_dir = '\0'; reset_last(); msg(""); return FALSE; | |
495 otherwise: | |
496 mpos = 0; | |
497 msg(prompt); | |
498 gotit = FALSE; | |
499 } | |
500 } until (gotit); | |
501 if (isupper(dir_ch)) | |
502 dir_ch = tolower(dir_ch); | |
503 last_dir = dir_ch; | |
504 last_delt.y = delta.y; | |
505 last_delt.x = delta.x; | |
506 } | |
507 if (on(player, ISHUH) && rnd(5) == 0) | |
508 do | |
509 { | |
510 delta.y = rnd(3) - 1; | |
511 delta.x = rnd(3) - 1; | |
512 } while (delta.y == 0 && delta.x == 0); | |
513 mpos = 0; | |
514 msg(""); | |
515 return TRUE; | |
516 } | |
517 | |
518 /* | |
519 * sign: | |
520 * Return the sign of the number | |
521 */ | |
522 int | |
523 sign(int nm) | |
524 { | |
525 if (nm < 0) | |
526 return -1; | |
527 else | |
528 return (nm > 0); | |
529 } | |
530 | |
531 /* | |
532 * spread: | |
533 * Give a spread around a given number (+/- 20%) | |
534 */ | |
535 int | |
536 spread(int nm) | |
537 { | |
538 return nm - nm / 20 + rnd(nm / 10); | |
539 } | |
540 | |
541 /* | |
542 * call_it: | |
543 * Call an object something after use. | |
544 */ | |
545 | |
546 void | |
547 call_it(struct obj_info *info) | |
548 { | |
549 if (info->oi_know) | |
550 { | |
551 if (info->oi_guess) | |
552 { | |
553 free(info->oi_guess); | |
554 info->oi_guess = NULL; | |
555 } | |
556 } | |
557 else if (!info->oi_guess) | |
558 { | |
559 msg(terse ? "call it: " : "what do you want to call it? "); | |
560 if (get_str(prbuf, stdscr) == NORM) | |
561 { | |
562 if (info->oi_guess != NULL) | |
563 free(info->oi_guess); | |
564 info->oi_guess = malloc(strlen(prbuf) + 1); | |
565 if (info->oi_guess != NULL) | |
566 strcpy(info->oi_guess, prbuf); | |
567 } | |
568 msg(""); | |
569 } | |
570 } | |
571 | |
572 /* | |
573 * rnd_thing: | |
574 * Pick a random thing appropriate for this level | |
575 */ | |
576 int | |
577 rnd_thing(void) | |
578 { | |
579 int i; | |
580 int thing_list[] = { | |
581 POTION, SCROLL, RING, STICK, FOOD, WEAPON, ARMOR, STAIRS, GOLD, AMULET | |
582 }; | |
583 | |
584 if (level >= AMULETLEVEL) | |
585 i = rnd(sizeof thing_list / sizeof (int)); | |
586 else | |
587 i = rnd(sizeof thing_list / sizeof (int) - 1); | |
588 return thing_list[i]; | |
589 } | |
590 | |
591 /* | |
592 str str: | |
593 * Choose the first or second string depending on whether it the | |
594 * player is tripping | |
595 */ | |
596 const char * | |
597 choose_str(const char *ts, const char *ns) | |
598 { | |
599 return (on(player, ISHALU) ? ts : ns); | |
600 } |