Mercurial > hg > early-roguelike
comparison arogue7/move.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 | a0a57cf42810 |
comparison
equal
deleted
inserted
replaced
124:d10fc4a065ac | 125:adfa37e67084 |
---|---|
1 /* | |
2 * move.c - Hero movement commands | |
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 /* | |
16 * Hero movement commands | |
17 * | |
18 */ | |
19 | |
20 #include "curses.h" | |
21 #include <ctype.h> | |
22 #include "rogue.h" | |
23 #ifdef PC7300 | |
24 #include "menu.h" | |
25 #endif | |
26 | |
27 /* | |
28 * Used to hold the new hero position | |
29 */ | |
30 | |
31 static coord nh; | |
32 | |
33 static char Moves[3][3] = { | |
34 { 'y', 'k', 'u' }, | |
35 { 'h', '.', 'l' }, | |
36 { 'b', 'j', 'n' } | |
37 }; | |
38 | |
39 /* | |
40 * be_trapped: | |
41 * The guy stepped on a trap.... Make him pay. | |
42 */ | |
43 | |
44 be_trapped(th, tc) | |
45 register struct thing *th; | |
46 register coord *tc; | |
47 { | |
48 register struct trap *tp; | |
49 register char ch, *mname; | |
50 register bool is_player = (th == &player), | |
51 can_see; | |
52 register struct linked_list *mitem; | |
53 register struct thing *mp; | |
54 | |
55 | |
56 /* Can the player see the creature? */ | |
57 can_see = (cansee(tc->y, tc->x) && (is_player || !invisible(th))); | |
58 | |
59 tp = trap_at(tc->y, tc->x); | |
60 /* | |
61 * if he's wearing boots of elvenkind, he won't set off the trap | |
62 * unless its a magic pool (they're not really traps) | |
63 */ | |
64 if (is_player && | |
65 cur_misc[WEAR_BOOTS] != NULL && | |
66 cur_misc[WEAR_BOOTS]->o_which == MM_ELF_BOOTS && | |
67 tp->tr_type != POOL) | |
68 return '\0'; | |
69 | |
70 /* | |
71 * if the creature is flying then it won't set off the trap | |
72 */ | |
73 if (on(*th, ISFLY)) | |
74 return '\0'; | |
75 | |
76 tp->tr_flags |= ISFOUND; | |
77 | |
78 if (!is_player) { | |
79 mitem = find_mons(th->t_pos.y, th->t_pos.x); | |
80 mname = monster_name(th); | |
81 } | |
82 else { | |
83 count = running = FALSE; | |
84 mvwaddch(cw, tp->tr_pos.y, tp->tr_pos.x, tp->tr_type); | |
85 } | |
86 switch (ch = tp->tr_type) { | |
87 case TRAPDOOR: | |
88 if (is_player) { | |
89 level++; | |
90 pstats.s_hpt -= roll(1, 10); | |
91 msg("You fell into a trap!"); | |
92 if (pstats.s_hpt <= 0) death(D_FALL); | |
93 new_level(NORMLEV); | |
94 } | |
95 else { | |
96 if (can_see) msg("%s fell into a trap!", prname(mname, TRUE)); | |
97 | |
98 /* | |
99 * See if the fall killed the monster | |
100 * don't let a UNIQUE die since it might have an artifact | |
101 * that we need | |
102 */ | |
103 if (off(*th,ISUNIQUE) && (th->t_stats.s_hpt-=roll(1,10)) <= 0){ | |
104 killed(mitem, FALSE, FALSE, FALSE); | |
105 } | |
106 else { /* Just move monster to next level */ | |
107 check_residue(th); | |
108 | |
109 /* Erase the monster from the old position */ | |
110 if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) | |
111 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); | |
112 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
113 | |
114 /* let him summon on next lvl */ | |
115 if (on (*th, HASSUMMONED)) { | |
116 turn_off(*th, HASSUMMONED); | |
117 turn_on(*th, CANSUMMON); | |
118 } | |
119 turn_on(*th,ISELSEWHERE); | |
120 detach(mlist, mitem); | |
121 attach(tlist, mitem); /* remember him next level */ | |
122 | |
123 /* Make sure that no one is still chasing us */ | |
124 for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { | |
125 mp = THINGPTR(mitem); | |
126 if (mp->t_dest == &th->t_pos) { | |
127 mp->t_dest = &hero; | |
128 mp->t_wasshot = FALSE; | |
129 turn_off(*mp, ISFLEE); /* Don't run away! */ | |
130 } | |
131 } | |
132 | |
133 /* Make sure we were not chasing a monster here */ | |
134 th->t_dest = &hero; | |
135 if (on(*th, ISFRIENDLY), turn_off(*th, ISFLEE)); | |
136 } | |
137 } | |
138 when BEARTRAP: | |
139 if (is_stealth(th)) { | |
140 if (is_player) msg("You pass a bear trap."); | |
141 else if (can_see) msg("%s passes a bear trap.", | |
142 prname(mname, TRUE)); | |
143 } | |
144 else { | |
145 th->t_no_move += movement(&player) * BEARTIME; | |
146 th->t_action = A_FREEZE; | |
147 if (is_player) msg("You are caught in a bear trap."); | |
148 else if (can_see) msg("%s is caught in a bear trap.", | |
149 prname(mname, TRUE)); | |
150 } | |
151 when SLEEPTRAP: | |
152 if (is_player) { | |
153 msg("A strange white mist envelops you."); | |
154 if (!ISWEARING(R_ALERT)) { | |
155 msg("You fall asleep."); | |
156 player.t_no_move += movement(&player) * SLEEPTIME; | |
157 player.t_action = A_FREEZE; | |
158 } | |
159 } | |
160 else { | |
161 if (can_see) | |
162 msg("A strange white mist envelops %s.", | |
163 prname(mname, FALSE)); | |
164 if (on(*th, ISUNDEAD)) { | |
165 if (can_see) | |
166 msg("The mist doesn't seem to affect %s.", | |
167 prname(mname, FALSE)); | |
168 } | |
169 else { | |
170 th->t_no_move += movement(th) * SLEEPTIME; | |
171 th->t_action = A_FREEZE; | |
172 } | |
173 } | |
174 when ARROWTRAP: | |
175 if (swing(th->t_ctype, th->t_stats.s_lvl-1, th->t_stats.s_arm, 1)) | |
176 { | |
177 if (is_player) { | |
178 msg("Oh no! An arrow shot you."); | |
179 if ((pstats.s_hpt -= roll(1, 6)) <= 0) { | |
180 msg("The arrow killed you."); | |
181 death(D_ARROW); | |
182 } | |
183 } | |
184 else { | |
185 if (can_see) | |
186 msg("An arrow shot %s.", prname(mname, FALSE)); | |
187 if ((th->t_stats.s_hpt -= roll(1, 6)) <= 0) { | |
188 if (can_see) | |
189 msg("The arrow killed %s.", prname(mname, FALSE)); | |
190 killed(mitem, FALSE, FALSE, TRUE); | |
191 } | |
192 } | |
193 } | |
194 else | |
195 { | |
196 register struct linked_list *item; | |
197 register struct object *arrow; | |
198 | |
199 if (is_player) msg("An arrow shoots past you."); | |
200 else if (can_see) | |
201 msg("An arrow shoots by %s.", prname(mname, FALSE)); | |
202 item = new_item(sizeof *arrow); | |
203 arrow = OBJPTR(item); | |
204 arrow->o_type = WEAPON; | |
205 arrow->contents = NULL; | |
206 arrow->o_which = ARROW; | |
207 arrow->o_hplus = rnd(3) - 1; | |
208 arrow->o_dplus = rnd(3) - 1; | |
209 init_weapon(arrow, ARROW); | |
210 arrow->o_count = 1; | |
211 arrow->o_pos = *tc; | |
212 arrow->o_mark[0] = '\0'; | |
213 fall(item, FALSE); | |
214 } | |
215 when TELTRAP: | |
216 if (is_player) teleport(); | |
217 else { | |
218 register int rm; | |
219 struct room *old_room; /* old room of monster */ | |
220 | |
221 /* | |
222 * Erase the monster from the old position | |
223 */ | |
224 if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) | |
225 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); | |
226 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
227 /* | |
228 * check to see if room should go dark | |
229 */ | |
230 if (on(*th, HASFIRE)) { | |
231 old_room=roomin(&th->t_pos); | |
232 if (old_room != NULL) { | |
233 register struct linked_list *fire_item; | |
234 | |
235 for (fire_item = old_room->r_fires; fire_item != NULL; | |
236 fire_item = next(fire_item)) { | |
237 if (THINGPTR(fire_item) == th) { | |
238 detach(old_room->r_fires, fire_item); | |
239 destroy_item(fire_item); | |
240 | |
241 if (old_room->r_fires == NULL) { | |
242 old_room->r_flags &= ~HASFIRE; | |
243 if (can_see) light(&hero); | |
244 } | |
245 } | |
246 } | |
247 } | |
248 } | |
249 | |
250 /* Get a new position */ | |
251 do { | |
252 rm = rnd_room(); | |
253 rnd_pos(&rooms[rm], &th->t_pos); | |
254 } until(winat(th->t_pos.y, th->t_pos.x) == FLOOR); | |
255 | |
256 /* Put it there */ | |
257 mvwaddch(mw, th->t_pos.y, th->t_pos.x, th->t_type); | |
258 th->t_oldch = CCHAR( mvwinch(cw, th->t_pos.y, th->t_pos.x) ); | |
259 /* | |
260 * check to see if room that creature appears in should | |
261 * light up | |
262 */ | |
263 if (on(*th, HASFIRE)) { | |
264 register struct linked_list *fire_item; | |
265 | |
266 fire_item = creat_item(); | |
267 ldata(fire_item) = (char *) th; | |
268 attach(rooms[rm].r_fires, fire_item); | |
269 | |
270 rooms[rm].r_flags |= HASFIRE; | |
271 if(cansee(th->t_pos.y, th->t_pos.x) && | |
272 next(rooms[rm].r_fires) == NULL) | |
273 light(&hero); | |
274 } | |
275 if (can_see) | |
276 msg("%s seems to have disappeared!", prname(mname, TRUE)); | |
277 } | |
278 when DARTTRAP: | |
279 if (swing(th->t_ctype, th->t_stats.s_lvl+1, th->t_stats.s_arm, 1)) { | |
280 if (is_player) { | |
281 msg("A small dart just hit you in the shoulder."); | |
282 if ((pstats.s_hpt -= roll(1, 4)) <= 0) { | |
283 msg("The dart killed you."); | |
284 death(D_DART); | |
285 } | |
286 | |
287 /* Now the poison */ | |
288 if (!save(VS_POISON, &player, 0)) { | |
289 /* 75% chance it will do point damage - else strength */ | |
290 if (rnd(100) < 75) { | |
291 pstats.s_hpt /= 2; | |
292 if (pstats.s_hpt == 0) death(D_POISON); | |
293 } | |
294 else if (!ISWEARING(R_SUSABILITY)) | |
295 chg_str(-1); | |
296 } | |
297 } | |
298 else { | |
299 if (can_see) | |
300 msg("A small dart just hit %s in the shoulder.", | |
301 prname(mname, FALSE)); | |
302 if ((th->t_stats.s_hpt -= roll(1,4)) <= 0) { | |
303 if (can_see) | |
304 msg("The dart killed %s.", prname(mname, FALSE)); | |
305 killed(mitem, FALSE, FALSE, TRUE); | |
306 } | |
307 if (!save(VS_POISON, th, 0)) { | |
308 th->t_stats.s_hpt /= 2; | |
309 if (th->t_stats.s_hpt <= 0) { | |
310 if (can_see) | |
311 msg("The dart killed %s.", prname(mname,FALSE)); | |
312 killed(mitem, FALSE, FALSE, TRUE); | |
313 } | |
314 } | |
315 } | |
316 } | |
317 else { | |
318 if (is_player) | |
319 msg("A small dart whizzes by your ear and vanishes."); | |
320 else if (can_see) | |
321 msg("A small dart whizzes by %s's ear and vanishes.", | |
322 prname(mname, FALSE)); | |
323 } | |
324 when POOL: { | |
325 register int i; | |
326 | |
327 i = rnd(100); | |
328 if (is_player) { | |
329 if ((tp->tr_flags & ISGONE)) { | |
330 if (i < 30) { | |
331 teleport(); /* teleport away */ | |
332 pool_teleport = TRUE; | |
333 } | |
334 else if((i < 45) && level > 2) { | |
335 level -= rnd(2) + 1; | |
336 cur_max = level; | |
337 new_level(NORMLEV); | |
338 pool_teleport = TRUE; | |
339 msg("You here a faint groan from below."); | |
340 } | |
341 else if(i < 70) { | |
342 level += rnd(4) + 1; | |
343 new_level(NORMLEV); | |
344 pool_teleport = TRUE; | |
345 msg("You find yourself in strange surroundings."); | |
346 } | |
347 else if(i > 95) { | |
348 msg("Oh no!!! You drown in the pool!!! --More--"); | |
349 wait_for(' '); | |
350 death(D_DROWN); | |
351 } | |
352 } | |
353 } | |
354 else { | |
355 if (i < 60) { | |
356 if (can_see) { | |
357 /* Drowns */ | |
358 if (i < 30) | |
359 msg("%s drowned in the pool!", prname(mname, TRUE)); | |
360 | |
361 /* Teleported to another level */ | |
362 else msg("%s disappeared!", prname(mname, TRUE)); | |
363 } | |
364 killed(mitem, FALSE, FALSE, TRUE); | |
365 } | |
366 } | |
367 } | |
368 when MAZETRAP: | |
369 if (is_player) { | |
370 pstats.s_hpt -= roll(1, 10); | |
371 level++; | |
372 msg("You fell through a trap door!"); | |
373 if (pstats.s_hpt <= 0) death(D_FALL); | |
374 new_level(MAZELEV); | |
375 msg("You are surrounded by twisty passages!"); | |
376 } | |
377 else { | |
378 if (can_see) msg("%s fell into a trap!", prname(mname, TRUE)); | |
379 | |
380 if (on(*th, ISUNIQUE)) { | |
381 check_residue(th); | |
382 | |
383 /* Erase the monster from the old position */ | |
384 if (isalpha(mvwinch(cw, th->t_pos.y, th->t_pos.x))) | |
385 mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); | |
386 mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); | |
387 | |
388 /* let him summon on next lvl */ | |
389 if (on (*th, HASSUMMONED)) { | |
390 turn_off(*th, HASSUMMONED); | |
391 turn_on(*th, CANSUMMON); | |
392 } | |
393 turn_on(*th,ISELSEWHERE); | |
394 detach(mlist, mitem); | |
395 attach(tlist, mitem); /* remember him next level */ | |
396 | |
397 /* Make sure that no one is still chasing us */ | |
398 for (mitem = mlist; mitem != NULL; mitem = next(mitem)) { | |
399 mp = THINGPTR(mitem); | |
400 if (mp->t_dest == &th->t_pos) { | |
401 mp->t_dest = &hero; | |
402 mp->t_wasshot = FALSE; | |
403 turn_off(*mp, ISFLEE); /* Don't run away! */ | |
404 } | |
405 } | |
406 | |
407 /* Make sure we were not chasing a monster here */ | |
408 th->t_dest = &hero; | |
409 if (on(*th, ISFRIENDLY), turn_off(*th, ISFLEE)); | |
410 } | |
411 else | |
412 killed(mitem, FALSE, FALSE, FALSE); | |
413 } | |
414 } | |
415 | |
416 /* Move the cursor back onto the hero */ | |
417 wmove(cw, hero.y, hero.x); | |
418 | |
419 md_flushinp(); | |
420 return(ch); | |
421 } | |
422 | |
423 /* | |
424 * blue_light: | |
425 * magically light up a room (or level or make it dark) | |
426 */ | |
427 | |
428 bool | |
429 blue_light(blessed, cursed) | |
430 bool blessed, cursed; | |
431 { | |
432 register struct room *rp; | |
433 bool ret_val=FALSE; /* Whether or not affect is known */ | |
434 | |
435 rp = roomin(&hero); /* What room is hero in? */ | |
436 | |
437 /* Darken the room if the magic is cursed */ | |
438 if (cursed) { | |
439 if ((rp == NULL) || !lit_room(rp)) msg(nothing); | |
440 else { | |
441 rp->r_flags |= ISDARK; | |
442 if (!lit_room(rp) && (levtype != OUTSIDE || !daytime)) | |
443 msg("The %s suddenly goes dark.", | |
444 levtype == OUTSIDE ? "area" : "room"); | |
445 else msg(nothing); | |
446 ret_val = TRUE; | |
447 } | |
448 } | |
449 else { | |
450 ret_val = TRUE; | |
451 if (rp && !lit_room(rp) && | |
452 (levtype != OUTSIDE || !daytime)) { | |
453 addmsg("The %s is lit", levtype == OUTSIDE ? "area" : "room"); | |
454 if (!terse) | |
455 addmsg(" by a %s blue light.", | |
456 blessed ? "bright" : "shimmering"); | |
457 endmsg(); | |
458 } | |
459 else if (winat(hero.y, hero.x) == PASSAGE) | |
460 msg("The corridor glows %sand then fades", | |
461 blessed ? "brightly " : ""); | |
462 else { | |
463 ret_val = FALSE; | |
464 msg(nothing); | |
465 } | |
466 if (blessed) { | |
467 register int i; /* Index through rooms */ | |
468 | |
469 for (i=0; i<MAXROOMS; i++) | |
470 rooms[i].r_flags &= ~ISDARK; | |
471 } | |
472 else if (rp) rp->r_flags &= ~ISDARK; | |
473 } | |
474 | |
475 /* | |
476 * Light the room and put the player back up | |
477 */ | |
478 light(&hero); | |
479 mvwaddch(cw, hero.y, hero.x, PLAYER); | |
480 return(ret_val); | |
481 } | |
482 | |
483 /* | |
484 * corr_move: | |
485 * Check to see that a move is legal. If so, return correct character. | |
486 * If not, if player came from a legal place, then try to turn him. | |
487 */ | |
488 | |
489 corr_move(dy, dx) | |
490 int dy, dx; | |
491 { | |
492 int legal=0; /* Number of legal alternatives */ | |
493 register int y, x, /* Indexes though possible positions */ | |
494 locy, locx; /* Hold delta of chosen location */ | |
495 | |
496 /* New position */ | |
497 nh.y = hero.y + dy; | |
498 nh.x = hero.x + dx; | |
499 | |
500 /* If it is a legal move, just return */ | |
501 if (nh.x >= 0 && nh.x < cols && nh.y > 0 && nh.y < lines - 2) { | |
502 | |
503 switch (winat(nh.y, nh.x)) { | |
504 case WALL: | |
505 case '|': | |
506 case '-': | |
507 break; | |
508 default: | |
509 if (diag_ok(&hero, &nh, &player)) | |
510 return; | |
511 } | |
512 } | |
513 | |
514 /* Check legal places surrounding the player -- ignore previous position */ | |
515 for (y = hero.y - 1; y <= hero.y + 1; y++) { | |
516 if (y < 1 || y > lines - 3) | |
517 continue; | |
518 for (x = hero.x - 1; x <= hero.x + 1; x++) { | |
519 /* Ignore borders of the screen */ | |
520 if (x < 0 || x > cols - 1) | |
521 continue; | |
522 | |
523 /* | |
524 * Ignore where we came from, where we are, and where we couldn't go | |
525 */ | |
526 if ((x == hero.x - dx && y == hero.y - dy) || | |
527 (x == hero.x + dx && y == hero.y + dy) || | |
528 (x == hero.x && y == hero.y)) | |
529 continue; | |
530 | |
531 switch (winat(y, x)) { | |
532 case WALL: | |
533 case '|': | |
534 case '-': | |
535 break; | |
536 default: | |
537 nh.y = y; | |
538 nh.x = x; | |
539 if (diag_ok(&hero, &nh, &player)) { | |
540 legal++; | |
541 locy = y - (hero.y - 1); | |
542 locx = x - (hero.x - 1); | |
543 } | |
544 } | |
545 } | |
546 } | |
547 | |
548 /* If we have 2 or more legal moves, make no change */ | |
549 if (legal != 1) { | |
550 return; | |
551 } | |
552 | |
553 runch = Moves[locy][locx]; | |
554 | |
555 /* | |
556 * For mazes, pretend like it is the beginning of a new run at each turn | |
557 * in order to get the lighting correct. | |
558 */ | |
559 if (levtype == MAZELEV) firstmove = TRUE; | |
560 return; | |
561 } | |
562 | |
563 /* | |
564 * dip_it: | |
565 * Dip an object into a magic pool | |
566 */ | |
567 dip_it() | |
568 { | |
569 reg struct linked_list *what; | |
570 reg struct object *ob; | |
571 reg struct trap *tp; | |
572 reg int wh, i; | |
573 | |
574 tp = trap_at(hero.y,hero.x); | |
575 if (tp == NULL || tp->tr_type != POOL) { | |
576 msg("I see no shimmering pool here"); | |
577 return; | |
578 } | |
579 if (tp->tr_flags & ISGONE) { | |
580 msg("This shimmering pool appears to have been used once already."); | |
581 return; | |
582 } | |
583 | |
584 /* It takes 3 movement periods to dip something */ | |
585 if (player.t_action != C_DIP) { | |
586 if ((what = get_item(pack, "dip", ALL, FALSE, FALSE)) == NULL) { | |
587 msg(""); | |
588 after = FALSE; | |
589 return; | |
590 } | |
591 | |
592 ob = OBJPTR(what); | |
593 if (ob == cur_armor || | |
594 ob == cur_misc[WEAR_BOOTS] || ob == cur_misc[WEAR_JEWEL] || | |
595 ob == cur_misc[WEAR_GAUNTLET] || | |
596 ob == cur_misc[WEAR_CLOAK] || | |
597 ob == cur_misc[WEAR_BRACERS] || | |
598 ob == cur_misc[WEAR_NECKLACE]|| | |
599 ob == cur_ring[LEFT_1] || ob == cur_ring[LEFT_2] || | |
600 ob == cur_ring[LEFT_3] || ob == cur_ring[LEFT_4] || | |
601 ob == cur_ring[RIGHT_1] || ob == cur_ring[RIGHT_2] || | |
602 ob == cur_ring[RIGHT_3] || ob == cur_ring[RIGHT_4]) { | |
603 mpos = 0; | |
604 msg("You'll have to take it off first."); | |
605 return; | |
606 } | |
607 | |
608 player.t_using = what; /* Remember what it is */ | |
609 player.t_action = C_DIP; /* We are dipping */ | |
610 player.t_no_move = 3 * movement(&player); | |
611 return; | |
612 } | |
613 | |
614 /* We have waited our time, let's dip it */ | |
615 what = player.t_using; | |
616 player.t_using = NULL; | |
617 player.t_action = A_NIL; | |
618 | |
619 ob = OBJPTR(what); | |
620 | |
621 tp->tr_flags |= ISGONE; | |
622 if (ob != NULL) { | |
623 wh = ob->o_which; | |
624 ob->o_flags |= ISKNOW; | |
625 i = rnd(100); | |
626 switch(ob->o_type) { | |
627 case WEAPON: | |
628 if(i < 50) { /* enchant weapon here */ | |
629 if ((ob->o_flags & ISCURSED) == 0) { | |
630 ob->o_hplus += 1; | |
631 ob->o_dplus += 1; | |
632 } | |
633 else { /* weapon was prev cursed here */ | |
634 ob->o_hplus = rnd(2); | |
635 ob->o_dplus = rnd(2); | |
636 } | |
637 ob->o_flags &= ~ISCURSED; | |
638 msg("The %s glows blue for a moment.",weaps[wh].w_name); | |
639 } | |
640 else if(i < 70) { /* curse weapon here */ | |
641 if ((ob->o_flags & ISCURSED) == 0) { | |
642 ob->o_hplus = -(rnd(2)+1); | |
643 ob->o_dplus = -(rnd(2)+1); | |
644 } | |
645 else { /* if already cursed */ | |
646 ob->o_hplus--; | |
647 ob->o_dplus--; | |
648 } | |
649 ob->o_flags |= ISCURSED; | |
650 msg("The %s glows red for a moment.",weaps[wh].w_name); | |
651 } | |
652 else | |
653 msg(nothing); | |
654 when ARMOR: | |
655 if (i < 50) { /* enchant armor */ | |
656 if((ob->o_flags & ISCURSED) == 0) | |
657 ob->o_ac -= rnd(2) + 1; | |
658 else | |
659 ob->o_ac = -rnd(3)+ armors[wh].a_class; | |
660 ob->o_flags &= ~ISCURSED; | |
661 msg("The %s glows blue for a moment",armors[wh].a_name); | |
662 } | |
663 else if(i < 75){ /* curse armor */ | |
664 if ((ob->o_flags & ISCURSED) == 0) | |
665 ob->o_ac = rnd(3)+ armors[wh].a_class; | |
666 else | |
667 ob->o_ac += rnd(2) + 1; | |
668 ob->o_flags |= ISCURSED; | |
669 msg("The %s glows red for a moment.",armors[wh].a_name); | |
670 } | |
671 else | |
672 msg(nothing); | |
673 when STICK: { | |
674 int j; | |
675 j = rnd(8) + 1; | |
676 if(i < 50) { /* add charges */ | |
677 ob->o_charges += j; | |
678 ws_know[wh] = TRUE; | |
679 if (ob->o_flags & ISCURSED) | |
680 ob->o_flags &= ~ISCURSED; | |
681 msg("The %s %s glows blue for a moment.", | |
682 ws_made[wh],ws_type[wh]); | |
683 } | |
684 else if(i < 65) { /* remove charges */ | |
685 if ((ob->o_charges -= i) < 0) | |
686 ob->o_charges = 0; | |
687 ws_know[wh] = TRUE; | |
688 if (ob->o_flags & ISBLESSED) | |
689 ob->o_flags &= ~ISBLESSED; | |
690 else | |
691 ob->o_flags |= ISCURSED; | |
692 msg("The %s %s glows red for a moment.", | |
693 ws_made[wh],ws_type[wh]); | |
694 } | |
695 else | |
696 msg(nothing); | |
697 } | |
698 when SCROLL: | |
699 s_know[wh] = TRUE; | |
700 msg("The '%s' scroll unfurls.",s_names[wh]); | |
701 when POTION: | |
702 p_know[wh] = TRUE; | |
703 msg("The %s potion bubbles for a moment.",p_colors[wh]); | |
704 when RING: | |
705 if(i < 50) { /* enchant ring */ | |
706 if ((ob->o_flags & ISCURSED) == 0) | |
707 ob->o_ac += rnd(2) + 1; | |
708 else | |
709 ob->o_ac = rnd(2) + 1; | |
710 ob->o_flags &= ~ISCURSED; | |
711 } | |
712 else if(i < 80) { /* curse ring */ | |
713 if ((ob->o_flags & ISCURSED) == 0) | |
714 ob->o_ac = -(rnd(2) + 1); | |
715 else | |
716 ob->o_ac -= (rnd(2) + 1); | |
717 ob->o_flags |= ISCURSED; | |
718 } | |
719 r_know[wh] = TRUE; | |
720 msg("The %s ring vibrates for a moment.",r_stones[wh]); | |
721 when MM: | |
722 m_know[wh] = TRUE; | |
723 switch (ob->o_which) { | |
724 case MM_BRACERS: | |
725 case MM_PROTECT: | |
726 if(i < 50) { /* enchant item */ | |
727 if ((ob->o_flags & ISCURSED) == 0) | |
728 ob->o_ac += rnd(2) + 1; | |
729 else | |
730 ob->o_ac = rnd(2) + 1; | |
731 ob->o_flags &= ~ISCURSED; | |
732 } | |
733 else if(i < 80) { /* curse item */ | |
734 if ((ob->o_flags & ISCURSED) == 0) | |
735 ob->o_ac = -(rnd(2) + 1); | |
736 else | |
737 ob->o_ac -= (rnd(2) + 1); | |
738 ob->o_flags |= ISCURSED; | |
739 } | |
740 msg("The item vibrates for a moment."); | |
741 when MM_CHOKE: | |
742 case MM_DISAPPEAR: | |
743 ob->o_ac = 0; | |
744 msg ("The dust dissolves in the pool!"); | |
745 } | |
746 otherwise: | |
747 msg("The pool bubbles for a moment."); | |
748 } | |
749 updpack(FALSE, &player); | |
750 } | |
751 else | |
752 msg(nothing); | |
753 } | |
754 | |
755 /* | |
756 * do_move: | |
757 * Check to see that a move is legal. If it is handle the | |
758 * consequences (fighting, picking up, etc.) | |
759 */ | |
760 | |
761 do_move(dy, dx) | |
762 int dy, dx; | |
763 { | |
764 register struct room *rp, *orp; | |
765 register char ch; | |
766 struct linked_list *item; | |
767 register struct thing *tp; | |
768 coord old_hero; | |
769 register int wasfirstmove, moved, num_hits; | |
770 bool changed=FALSE; /* Did we switch places with a friendly monster? */ | |
771 | |
772 wasfirstmove = firstmove; | |
773 firstmove = FALSE; | |
774 curprice = -1; /* if in trading post, we've moved off obj */ | |
775 | |
776 /* | |
777 * Do a confused move (maybe) | |
778 */ | |
779 if (player.t_action == A_NIL && | |
780 ((on(player, ISHUH) && rnd(100) < 80) || | |
781 (on(player, ISDANCE) && rnd(100) < 80) || | |
782 (ISWEARING(R_DELUSION) && rnd(100) < 25))) | |
783 /* Get a random move */ | |
784 nh = *rndmove(&player); | |
785 else { | |
786 nh.y = hero.y + dy; | |
787 nh.x = hero.x + dx; | |
788 } | |
789 | |
790 /* | |
791 * Check if he tried to move off the screen or make an illegal | |
792 * diagonal move, and stop him if he did. | |
793 */ | |
794 if (nh.x < 0 || nh.x > cols-1 || nh.y < 1 || nh.y >= lines - 2 | |
795 || !diag_ok(&hero, &nh, &player)) | |
796 { | |
797 after = running = FALSE; | |
798 player.t_action = A_NIL; | |
799 return; | |
800 } | |
801 if (running && ce(hero, nh)) | |
802 after = running = FALSE; | |
803 ch = CCHAR( winat(nh.y, nh.x) ); | |
804 | |
805 /* Take care of hero trying to move close to something frightening */ | |
806 if (on(player, ISFLEE)) { | |
807 if (rnd(100) < 10) { | |
808 turn_off(player, ISFLEE); | |
809 msg("You regain your composure."); | |
810 } | |
811 else if (DISTANCE(nh.y, nh.x, player.t_dest->y, player.t_dest->x) < | |
812 DISTANCE(hero.y, hero.x, player.t_dest->y, player.t_dest->x)) { | |
813 running = FALSE; | |
814 msg("You are too terrified to move that way"); | |
815 player.t_action = A_NIL; | |
816 player.t_no_move = movement(&player); | |
817 return; | |
818 } | |
819 } | |
820 | |
821 /* If we want to move to a monster, see what it is */ | |
822 if (isalpha(ch)) { | |
823 item = find_mons(nh.y, nh.x); | |
824 if (item == NULL) { | |
825 debug("Cannot find monster in move."); | |
826 player.t_action = A_NIL; | |
827 return; | |
828 } | |
829 tp = THINGPTR(item); | |
830 } | |
831 | |
832 /* | |
833 * Take care of hero being held. If the player is being held, he | |
834 * can't move unless he is either attacking a non-friendly monster | |
835 * or attacking a friendly monster that can't move. | |
836 */ | |
837 if (on(player, ISHELD) && | |
838 (!isalpha(ch) || (on(*tp, ISFRIENDLY) && off(*tp, ISHELD)))) { | |
839 msg("You are being held."); | |
840 player.t_action = A_NIL; | |
841 return; | |
842 } | |
843 | |
844 /* See if we have to wait for our movement rate */ | |
845 if (player.t_action == A_NIL) { | |
846 after = FALSE; | |
847 firstmove = wasfirstmove; /* Remember if this is first move */ | |
848 player.t_no_move = movement(&player); | |
849 if (player.t_ctype == C_MONK) | |
850 player.t_no_move -= pstats.s_lvl/6; | |
851 if (on(player, ISFLY)) | |
852 player.t_no_move /= 2; /* If flying, speed him up */ | |
853 | |
854 if (player.t_no_move < 1) player.t_no_move = 1; | |
855 | |
856 /* Remember our action */ | |
857 player.t_action = Moves[dy+1][dx+1]; | |
858 return; | |
859 } | |
860 | |
861 /* Now let's forget the old move and just do it */ | |
862 player.t_action = A_NIL; | |
863 | |
864 /* If we're moving onto a friendly monster, let's change places. */ | |
865 if (isalpha(ch) && on(*tp, ISFRIENDLY) && off(*tp, ISHELD)) { | |
866 coord tpos, /* Where monster may have been going */ | |
867 current; /* Current hero position */ | |
868 int action; /* The monster's action */ | |
869 | |
870 current = hero; | |
871 tpos = tp->t_newpos; | |
872 action = tp->t_action; | |
873 | |
874 /* Disrupt whatever our friend was doing */ | |
875 tp->t_action = A_NIL; | |
876 | |
877 /* Tentatively move us to where he is */ | |
878 hero = tp->t_pos; | |
879 | |
880 /* See if we can move him to where we were */ | |
881 tp->t_newpos = current; | |
882 do_chase(tp); | |
883 | |
884 /* Did we succeed? */ | |
885 if (ce(tp->t_pos, current)) { | |
886 /* Reset our idea of what ch is */ | |
887 ch = CCHAR( winat(nh.y, nh.x) ); | |
888 | |
889 /* Let it be known that we made the switch */ | |
890 changed = TRUE; | |
891 old_hero = current; | |
892 | |
893 /* Make the monster think it didn't move */ | |
894 tp->t_oldpos = current; | |
895 tp->t_doorgoal = NULL; | |
896 | |
897 /* Let the player know something funny happened. */ | |
898 msg("What a sidestep!"); | |
899 } | |
900 else { | |
901 /* Restore things -- we couldn't move */ | |
902 hero = current; | |
903 tp->t_newpos = tpos; | |
904 tp->t_action = action; | |
905 } | |
906 } | |
907 | |
908 /* assume he's not in a wall */ | |
909 if (!isalpha(ch)) turn_off(player, ISINWALL); | |
910 | |
911 switch (ch) { | |
912 case '|': | |
913 case '-': | |
914 if (levtype == OUTSIDE) { | |
915 hero = nh; | |
916 new_level(OUTSIDE); | |
917 return; | |
918 } | |
919 case WALL: | |
920 case SECRETDOOR: | |
921 if (off(player, CANINWALL) || running) { | |
922 after = running = FALSE; | |
923 | |
924 /* Light if finishing run */ | |
925 if (levtype == MAZELEV && lit_room(&rooms[0])) | |
926 look(FALSE, TRUE); | |
927 | |
928 after = running = FALSE; | |
929 | |
930 return; | |
931 } | |
932 turn_on(player, ISINWALL); | |
933 break; | |
934 case POOL: | |
935 if (levtype == OUTSIDE) { | |
936 lake_check(&nh); | |
937 running = FALSE; | |
938 break; | |
939 } | |
940 case MAZETRAP: | |
941 if (levtype == OUTSIDE) { | |
942 running = FALSE; | |
943 break; | |
944 } | |
945 case TRAPDOOR: | |
946 case TELTRAP: | |
947 case BEARTRAP: | |
948 case SLEEPTRAP: | |
949 case ARROWTRAP: | |
950 case DARTTRAP: | |
951 ch = be_trapped(&player, &nh); | |
952 if (ch == TRAPDOOR || ch == TELTRAP || | |
953 pool_teleport || ch == MAZETRAP) { | |
954 pool_teleport = FALSE; | |
955 return; | |
956 } | |
957 break; | |
958 case GOLD: | |
959 case POTION: | |
960 case SCROLL: | |
961 case FOOD: | |
962 case WEAPON: | |
963 case ARMOR: | |
964 case RING: | |
965 case MM: | |
966 case RELIC: | |
967 case STICK: | |
968 running = FALSE; | |
969 take = ch; | |
970 break; | |
971 case DOOR: | |
972 case STAIRS: | |
973 case POST: | |
974 running = FALSE; | |
975 break; | |
976 default: | |
977 break; | |
978 } | |
979 | |
980 if (isalpha(ch)) { /* if its a monster then fight it */ | |
981 /* | |
982 * If we were running down a corridor and didn't start right | |
983 * next to the critter, don't do anything. | |
984 */ | |
985 if (running && wasfirstmove == FALSE && roomin(&hero) == NULL) { | |
986 struct linked_list *item; | |
987 | |
988 item = find_mons(nh.y, nh.x); | |
989 if (item != NULL && !invisible(THINGPTR(item))) { | |
990 after = running = FALSE; | |
991 return; | |
992 } | |
993 } | |
994 | |
995 /* We have to add time because we're attacking */ | |
996 player.t_no_move = FIGHTBASE; | |
997 player.t_no_move += weap_move(&player, cur_weapon); | |
998 if (on(player, ISHASTE)) | |
999 player.t_no_move /= 2; | |
1000 else if (on(player, ISSLOW)) | |
1001 player.t_no_move *= 2; | |
1002 | |
1003 /* We may attack faster if we're high enough level | |
1004 * and the right class | |
1005 */ | |
1006 switch(player.t_ctype) { | |
1007 case C_FIGHTER: num_hits = player.t_stats.s_lvl/9 + 1; | |
1008 when C_PALADIN: num_hits = player.t_stats.s_lvl/12 + 1; | |
1009 when C_RANGER: num_hits = player.t_stats.s_lvl/13 + 1; | |
1010 when C_MONK: if(cur_weapon) num_hits= 1; | |
1011 else num_hits= player.t_stats.s_lvl/5 + 1; | |
1012 otherwise: num_hits = 1; | |
1013 } | |
1014 | |
1015 /* | |
1016 * The player has already moved the initial movement period. | |
1017 * Let's add that in, do our division, and then subtract it | |
1018 * out so that the total time is divided, not just the | |
1019 * additional attack time. | |
1020 */ | |
1021 moved = movement(&player), | |
1022 player.t_no_move += moved; | |
1023 player.t_no_move /= num_hits; | |
1024 player.t_no_move -= moved; | |
1025 running = FALSE; | |
1026 | |
1027 /* Mark that we are attacking and save the attack coordinate */ | |
1028 player.t_action = A_ATTACK; | |
1029 player.t_newpos = nh; | |
1030 runch = Moves[dy+1][dx+1]; /* Remember the direction */ | |
1031 | |
1032 if (player.t_no_move <= 0) after = FALSE; | |
1033 return; | |
1034 } | |
1035 | |
1036 /* | |
1037 * if not fighting then move the hero | |
1038 */ | |
1039 if (changed == FALSE) { | |
1040 old_hero = hero; /* Save hero's old position */ | |
1041 hero = nh; /* Move the hero */ | |
1042 } | |
1043 rp = roomin(&hero); | |
1044 orp = roomin(&old_hero); | |
1045 | |
1046 /* Unlight any possible cross-corridor */ | |
1047 if (levtype == MAZELEV) { | |
1048 register bool call_light = FALSE; | |
1049 register char wall_check; | |
1050 | |
1051 if (wasfirstmove && lit_room(&rooms[0])) { | |
1052 /* Are we moving out of a corridor? */ | |
1053 switch (runch) { | |
1054 case 'h': | |
1055 case 'l': | |
1056 if (old_hero.y + 1 < lines - 2) { | |
1057 wall_check = CCHAR( winat(old_hero.y + 1, old_hero.x) ); | |
1058 if (!isrock(wall_check)) call_light = TRUE; | |
1059 } | |
1060 if (old_hero.y - 1 > 0) { | |
1061 wall_check = CCHAR( winat(old_hero.y - 1, old_hero.x) ); | |
1062 if (!isrock(wall_check)) call_light = TRUE; | |
1063 } | |
1064 break; | |
1065 case 'j': | |
1066 case 'k': | |
1067 if (old_hero.x + 1 < cols) { | |
1068 wall_check = CCHAR( winat(old_hero.y, old_hero.x + 1) ); | |
1069 if (!isrock(wall_check)) call_light = TRUE; | |
1070 } | |
1071 if (old_hero.x - 1 >= 0) { | |
1072 wall_check = CCHAR( winat(old_hero.y, old_hero.x - 1) ); | |
1073 if (!isrock(wall_check)) call_light = TRUE; | |
1074 } | |
1075 break; | |
1076 default: | |
1077 call_light = TRUE; | |
1078 } | |
1079 player.t_oldpos = old_hero; | |
1080 if (call_light) light(&old_hero); | |
1081 } | |
1082 } | |
1083 | |
1084 else if (orp != NULL && rp == NULL) { /* Leaving a room -- darken it */ | |
1085 orp->r_flags |= FORCEDARK; /* Fake darkness */ | |
1086 light(&old_hero); | |
1087 orp->r_flags &= ~FORCEDARK; /* Restore light state */ | |
1088 } | |
1089 else if (rp != NULL && orp == NULL){/* Entering a room */ | |
1090 light(&hero); | |
1091 if (rp->r_flags & ISTREAS) | |
1092 wake_room(rp); | |
1093 } | |
1094 ch = CCHAR( winat(old_hero.y, old_hero.x) ); | |
1095 wmove(cw, unc(old_hero)); | |
1096 waddch(cw, ch); | |
1097 wmove(cw, unc(hero)); | |
1098 waddch(cw, PLAYER); | |
1099 } | |
1100 | |
1101 /* | |
1102 * do_run: | |
1103 * Start the hero running | |
1104 */ | |
1105 | |
1106 do_run(ch) | |
1107 char ch; | |
1108 { | |
1109 firstmove = TRUE; | |
1110 running = TRUE; | |
1111 after = FALSE; | |
1112 runch = ch; | |
1113 } | |
1114 | |
1115 /* | |
1116 * getdelta: | |
1117 * Takes a movement character (eg. h, j, k, l) and returns the | |
1118 * y and x delta corresponding to it in the remaining arguments. | |
1119 * Returns TRUE if it could find it, FALSE otherwise. | |
1120 */ | |
1121 bool | |
1122 getdelta(match, dy, dx) | |
1123 char match; | |
1124 int *dy, *dx; | |
1125 { | |
1126 register y, x; | |
1127 | |
1128 for (y = 0; y < 3; y++) | |
1129 for (x = 0; x < 3; x++) | |
1130 if (Moves[y][x] == match) { | |
1131 *dy = y - 1; | |
1132 *dx = x - 1; | |
1133 return(TRUE); | |
1134 } | |
1135 | |
1136 return(FALSE); | |
1137 } | |
1138 | |
1139 /* | |
1140 * isatrap: | |
1141 * Returns TRUE if this character is some kind of trap | |
1142 */ | |
1143 isatrap(ch) | |
1144 reg char ch; | |
1145 { | |
1146 switch(ch) { | |
1147 case DARTTRAP: | |
1148 case TELTRAP: | |
1149 case TRAPDOOR: | |
1150 case ARROWTRAP: | |
1151 case SLEEPTRAP: | |
1152 case BEARTRAP: return(TRUE); | |
1153 case MAZETRAP: | |
1154 case POOL: return(levtype != OUTSIDE); | |
1155 default: return(FALSE); | |
1156 } | |
1157 } | |
1158 | |
1159 /* | |
1160 * Called to illuminate a room. | |
1161 * If it is dark, remove anything that might move. | |
1162 */ | |
1163 | |
1164 light(cp) | |
1165 coord *cp; | |
1166 { | |
1167 register struct room *rp; | |
1168 register int j, k, x, y; | |
1169 register char ch, rch, sch; | |
1170 register struct linked_list *item; | |
1171 int jlow, jhigh, klow, khigh; /* Boundaries of lit area */ | |
1172 | |
1173 if ((rp = roomin(cp)) != NULL) { | |
1174 /* | |
1175 * is he wearing ring of illumination? | |
1176 */ | |
1177 if (&hero == cp && ISWEARING(R_LIGHT)) /* Must be hero's room */ | |
1178 rp->r_flags &= ~ISDARK; | |
1179 | |
1180 /* If we are in a maze, don't look at the whole room (level) */ | |
1181 if (levtype == MAZELEV) { | |
1182 int see_radius; | |
1183 | |
1184 see_radius = 1; | |
1185 | |
1186 /* If we are looking at the hero in a rock, broaden our sights */ | |
1187 if (&hero == cp || &player.t_oldpos == cp) { | |
1188 ch = CCHAR( winat(hero.y, hero.x) ); | |
1189 if (isrock(ch)) see_radius = 2; | |
1190 ch = CCHAR( winat(player.t_oldpos.y, player.t_oldpos.x) ); | |
1191 if (isrock(ch)) see_radius = 2; | |
1192 } | |
1193 | |
1194 jlow = max(0, cp->y - see_radius - rp->r_pos.y); | |
1195 jhigh = min(rp->r_max.y, cp->y + see_radius + 1 - rp->r_pos.y); | |
1196 klow = max(0, cp->x - see_radius - rp->r_pos.x); | |
1197 khigh = min(rp->r_max.x, cp->x + see_radius + 1 - rp->r_pos.x); | |
1198 } | |
1199 else { | |
1200 jlow = klow = 0; | |
1201 jhigh = rp->r_max.y; | |
1202 khigh = rp->r_max.x; | |
1203 } | |
1204 for (j = 0; j < rp->r_max.y; j++) | |
1205 { | |
1206 for (k = 0; k < rp->r_max.x; k++) | |
1207 { | |
1208 bool see_here, see_before; | |
1209 | |
1210 /* Is this in the give area -- needed for maze */ | |
1211 if ((j < jlow || j >= jhigh) && (k < klow || k >= khigh)) | |
1212 continue; | |
1213 | |
1214 y = rp->r_pos.y + j; | |
1215 x = rp->r_pos.x + k; | |
1216 | |
1217 /* | |
1218 * If we are in a maze do not look at this area unless | |
1219 * we can see it from where we are or where we last were | |
1220 * (for erasing purposes). | |
1221 */ | |
1222 if (levtype == MAZELEV) { | |
1223 /* If we can't see it from here, could we see it before? */ | |
1224 if ((see_here = maze_view(y, x)) == FALSE) { | |
1225 coord savhero; | |
1226 | |
1227 /* Could we see it from where we were? */ | |
1228 savhero = hero; | |
1229 hero = player.t_oldpos; | |
1230 see_before = maze_view(y, x); | |
1231 hero = savhero; | |
1232 | |
1233 if (!see_before) continue; | |
1234 } | |
1235 } | |
1236 | |
1237 ch = show(y, x); | |
1238 wmove(cw, y, x); | |
1239 /* | |
1240 * Figure out how to display a secret door | |
1241 */ | |
1242 if (ch == SECRETDOOR) { | |
1243 if (j == 0 || j == rp->r_max.y - 1) | |
1244 ch = '-'; | |
1245 else | |
1246 ch = '|'; | |
1247 } | |
1248 /* For monsters, if they were previously not seen and | |
1249 * now can be seen, or vice-versa, make sure that will | |
1250 * happen. This is for dark rooms as opposed to invisibility. | |
1251 * | |
1252 * Call winat() in the test because ch will not reveal | |
1253 * invisible monsters. | |
1254 */ | |
1255 if (isalpha(winat(y, x))) { | |
1256 struct thing *tp; /* The monster */ | |
1257 | |
1258 item = wake_monster(y, x); | |
1259 tp = THINGPTR(item); | |
1260 | |
1261 /* Previously not seen -- now can see it */ | |
1262 if (tp->t_oldch == ' ' && cansee(tp->t_pos.y, tp->t_pos.x)) | |
1263 tp->t_oldch = CCHAR( mvinch(y, x) ); | |
1264 | |
1265 /* Previously seen -- now can't see it */ | |
1266 else if (!cansee(tp->t_pos.y, tp->t_pos.x) && | |
1267 roomin(&tp->t_pos) != NULL) | |
1268 switch (tp->t_oldch) { | |
1269 /* | |
1270 * Only blank it out if it is in a room and not | |
1271 * the border (or other wall) of the room. | |
1272 */ | |
1273 case DOOR: | |
1274 case SECRETDOOR: | |
1275 case '-': | |
1276 case '|': | |
1277 break; | |
1278 | |
1279 otherwise: | |
1280 tp->t_oldch = ' '; | |
1281 } | |
1282 } | |
1283 | |
1284 /* | |
1285 * If the room is a dark room, we might want to remove | |
1286 * monsters and the like from it (since they might | |
1287 * move). | |
1288 * A dark room. | |
1289 */ | |
1290 if ((!lit_room(rp) && (levtype != OUTSIDE)) || | |
1291 (levtype == OUTSIDE && !daytime) || | |
1292 on(player, ISBLIND) || | |
1293 (rp->r_flags & FORCEDARK) || | |
1294 (levtype == MAZELEV && !see_here && see_before)) { | |
1295 sch = CCHAR( mvwinch(cw, y, x) ); /* What's seen */ | |
1296 rch = CCHAR( mvinch(y, x) ); /* What's really there */ | |
1297 switch (rch) { | |
1298 case DOOR: | |
1299 case SECRETDOOR: | |
1300 case STAIRS: | |
1301 case TRAPDOOR: | |
1302 case TELTRAP: | |
1303 case BEARTRAP: | |
1304 case SLEEPTRAP: | |
1305 case ARROWTRAP: | |
1306 case DARTTRAP: | |
1307 case MAZETRAP: | |
1308 case POOL: | |
1309 case POST: | |
1310 case '|': | |
1311 case '-': | |
1312 case WALL: | |
1313 if (isalpha(sch)) ch = rch; | |
1314 else if (sch != FLOOR) ch = sch; | |
1315 else ch = ' '; /* Hide undiscoverd things */ | |
1316 when FLOOR: | |
1317 ch = ' '; | |
1318 otherwise: | |
1319 ch = ' '; | |
1320 } | |
1321 /* Take care of our magic bookkeeping. */ | |
1322 switch (sch) { | |
1323 case MAGIC: | |
1324 case BMAGIC: | |
1325 case CMAGIC: | |
1326 ch = sch; | |
1327 } | |
1328 } | |
1329 mvwaddch(cw, y, x, ch); | |
1330 } | |
1331 } | |
1332 } | |
1333 } | |
1334 | |
1335 /* | |
1336 * lit_room: | |
1337 * Called to see if the specified room is lit up or not. | |
1338 */ | |
1339 | |
1340 bool | |
1341 lit_room(rp) | |
1342 register struct room *rp; | |
1343 { | |
1344 register struct linked_list *fire_item; | |
1345 register struct thing *fire_creature; | |
1346 | |
1347 if (!(rp->r_flags & ISDARK)) return(TRUE); /* A definitely lit room */ | |
1348 | |
1349 /* Is it lit by fire light? */ | |
1350 if (rp->r_flags & HASFIRE) { | |
1351 switch ((int)levtype) { | |
1352 case MAZELEV: | |
1353 /* See if a fire creature is in line of sight */ | |
1354 for (fire_item = rp->r_fires; fire_item != NULL; | |
1355 fire_item = next(fire_item)) { | |
1356 fire_creature = THINGPTR(fire_item); | |
1357 if (maze_view(fire_creature->t_pos.y, | |
1358 fire_creature->t_pos.x)) return(TRUE); | |
1359 } | |
1360 | |
1361 /* Couldn't find any in line-of-sight */ | |
1362 return(FALSE); | |
1363 | |
1364 /* We should probably do something special for the outside */ | |
1365 otherwise: | |
1366 return TRUE; | |
1367 } | |
1368 } | |
1369 return(FALSE); | |
1370 } | |
1371 | |
1372 /* | |
1373 * movement: | |
1374 * Given a pointer to a player/monster structure, calculate the | |
1375 * movement rate for that character. | |
1376 */ | |
1377 | |
1378 short | |
1379 movement(tp) | |
1380 register struct thing *tp; | |
1381 { | |
1382 register int result; | |
1383 register int carry; /* Percentage carried */ | |
1384 | |
1385 result = 0; | |
1386 | |
1387 /* Adjust for armor (player only) */ | |
1388 if (tp == &player && cur_armor) { | |
1389 int diff; /* Now armor class differs from normal one of same type */ | |
1390 | |
1391 /* Blessed armor adds less */ | |
1392 diff = cur_armor->o_ac - armors[cur_armor->o_which].a_class; | |
1393 switch (cur_armor->o_which) { | |
1394 case LEATHER: | |
1395 case RING_MAIL: | |
1396 case STUDDED_LEATHER: | |
1397 case SCALE_MAIL: | |
1398 case PADDED_ARMOR: | |
1399 diff += 1; | |
1400 when CHAIN_MAIL: | |
1401 case SPLINT_MAIL: | |
1402 case BANDED_MAIL: | |
1403 case PLATE_MAIL: | |
1404 diff += 2; | |
1405 when PLATE_ARMOR: | |
1406 diff += 3; | |
1407 otherwise: | |
1408 debug("forgot an armor in movement()"); | |
1409 } | |
1410 if (diff < 0) diff = 0; | |
1411 result += diff; | |
1412 | |
1413 } | |
1414 | |
1415 /* Adjust for the pack */ | |
1416 carry = 100 * tp->t_stats.s_pack / tp->t_stats.s_carry; | |
1417 if (carry > 75) result++; | |
1418 | |
1419 /* Get a bonus for dexterity */ | |
1420 result -= dext_plus(tp == &player ? dex_compute() : tp->t_stats.s_dext); | |
1421 | |
1422 /* only allow adjust for the minus's */ | |
1423 if (result < 0) result = 0; | |
1424 result += tp->t_movement; /* now add in movement rate */ | |
1425 | |
1426 /* Is the character slowed? */ | |
1427 if (on(*tp, ISSLOW) || on(*tp, ISDANCE)) result *= 2; | |
1428 | |
1429 /* Is the character hasted? */ | |
1430 if (on(*tp, ISHASTE)) result /= 2; | |
1431 | |
1432 /* We have a minimum of 1 */ | |
1433 if (result < 1) result = 1; | |
1434 | |
1435 return(result); | |
1436 } | |
1437 | |
1438 /* | |
1439 * rndmove: | |
1440 * move in a random direction if the monster/person is confused | |
1441 */ | |
1442 | |
1443 coord * | |
1444 rndmove(who) | |
1445 struct thing *who; | |
1446 { | |
1447 register int x, y; | |
1448 register int ex, ey, nopen = 0; | |
1449 static coord ret; /* what we will be returning */ | |
1450 static coord dest; | |
1451 | |
1452 ret = who->t_pos; | |
1453 /* | |
1454 * Now go through the spaces surrounding the player and | |
1455 * set that place in the array to true if the space can be | |
1456 * moved into | |
1457 */ | |
1458 ey = ret.y + 1; | |
1459 ex = ret.x + 1; | |
1460 for (y = who->t_pos.y - 1; y <= ey; y++) | |
1461 if (y > 0 && y < lines - 2) | |
1462 for (x = who->t_pos.x - 1; x <= ex; x++) | |
1463 { | |
1464 if (x < 0 || x >= cols) | |
1465 continue; | |
1466 if (step_ok(y, x, NOMONST, who) == TRUE) | |
1467 { | |
1468 dest.y = y; | |
1469 dest.x = x; | |
1470 if (!diag_ok(&who->t_pos, &dest, who)) | |
1471 continue; | |
1472 if (rnd(++nopen) == 0) | |
1473 ret = dest; | |
1474 } | |
1475 } | |
1476 return &ret; | |
1477 } | |
1478 | |
1479 | |
1480 | |
1481 #define TRAPTYPES 9 /* 9 total trap types that can be set */ | |
1482 #define WIZARDTRAPS 3 /* Only wizards can set 3 of these */ | |
1483 | |
1484 static char *trap_types[TRAPTYPES] = { | |
1485 "Trap Door", | |
1486 "Bear Trap", | |
1487 "Sleep Trap", | |
1488 "Arrow Trap", | |
1489 "Teleport Trap", | |
1490 "Dart Trap", | |
1491 "Magic pool", | |
1492 "Maze Trap", | |
1493 "Trading Post" | |
1494 }; | |
1495 | |
1496 #ifdef PC7300 | |
1497 #define TRAPWIDTH 13 /* Length of longest named trap from above list */ | |
1498 #define TRAPPREFIX 4 /* Length of prefix (eg. "[9] ") */ | |
1499 static menu_t Display; /* The menu structure */ | |
1500 static mitem_t Dispitems[TRAPTYPES+1]; /* Info for each line */ | |
1501 static char Displines[TRAPTYPES+1][TRAPWIDTH+TRAPPREFIX+1]; | |
1502 #endif | |
1503 | |
1504 /* | |
1505 * set_trap: | |
1506 * set a trap at (y, x) on screen. | |
1507 */ | |
1508 | |
1509 set_trap(tp, y, x) | |
1510 register struct thing *tp; | |
1511 register int y, x; | |
1512 { | |
1513 register bool is_player = (tp == &player); | |
1514 register int selection = rnd(TRAPTYPES-WIZARDTRAPS) + '1'; | |
1515 register int i, num_traps; | |
1516 register char ch, och; | |
1517 int thief_bonus = 0; | |
1518 int s_dext; | |
1519 | |
1520 if (is_player && player.t_ctype != C_THIEF && player.t_ctype != C_ASSASIN) { | |
1521 msg("Only thieves and assassins can set traps."); | |
1522 return; | |
1523 } | |
1524 switch (och = CCHAR( mvinch(y, x) )) { | |
1525 case WALL: | |
1526 case FLOOR: | |
1527 case PASSAGE: | |
1528 break; | |
1529 default: | |
1530 if (is_player) msg("The trap failed!"); | |
1531 return; | |
1532 } | |
1533 | |
1534 if (is_player) { | |
1535 int state = 0, /* 0 -> current screen, 1 -> prompt screen, 2 -> done */ | |
1536 units; /* Number of movement units for the given trap */ | |
1537 | |
1538 if (player.t_action == C_SETTRAP) { | |
1539 selection = player.t_selection; | |
1540 player.t_selection = 0; | |
1541 player.t_using = NULL; | |
1542 player.t_action = A_NIL; | |
1543 } | |
1544 else { | |
1545 msg("Which kind of trap do you wish to set? (* for a list): "); | |
1546 num_traps = TRAPTYPES - (wizard ? 0 : WIZARDTRAPS); | |
1547 do { | |
1548 selection = tolower(readchar()); | |
1549 switch (selection) { | |
1550 case '*': | |
1551 if (state != 1) { | |
1552 #ifdef PC7300 | |
1553 for (i=0; i<TRAPTYPES; i++) { | |
1554 /* | |
1555 * Add numbers so the player can use a | |
1556 * number later, if he knows it. Let's | |
1557 * put the number on here instead of in | |
1558 * trap_types in case we want to drop it | |
1559 * later. | |
1560 */ | |
1561 sprintf(Displines[i], "[%d] %s", | |
1562 i+1, trap_types[i]); | |
1563 Dispitems[i].mi_name = Displines[i]; | |
1564 Dispitems[i].mi_flags = 0; | |
1565 Dispitems[i].mi_val = i+'1'; | |
1566 } | |
1567 | |
1568 /* Place an end marker for the items */ | |
1569 Dispitems[num_traps].mi_name = 0; | |
1570 | |
1571 /* Set up the main menu structure */ | |
1572 Display.m_label = "Trap Creation"; | |
1573 Display.m_title = "Trap Types"; | |
1574 Display.m_prompt = "Select a trap type or press Cancl."; | |
1575 Display.m_curptr = '\0'; | |
1576 Display.m_markptr = '\0'; | |
1577 Display.m_flags = 0; | |
1578 Display.m_selcnt = 1; | |
1579 Display.m_items = Dispitems; | |
1580 Display.m_curi = 0; | |
1581 | |
1582 /* | |
1583 * Try to display the menu. If we don't have a local | |
1584 * terminal, the call will fail and we will just | |
1585 * continue with the normal mode. | |
1586 */ | |
1587 if (menu(&Display) >= 0) { | |
1588 if (Display.m_selcnt == 0) { | |
1589 /* Cancelled menu */ | |
1590 msg(""); | |
1591 | |
1592 trap_tries--; /* Don't count this one */ | |
1593 after = FALSE; | |
1594 return; | |
1595 } | |
1596 selection = Display.m_curi->mi_val; | |
1597 state = 2; | |
1598 break; | |
1599 } | |
1600 #endif | |
1601 | |
1602 wclear(hw); | |
1603 touchwin(hw); | |
1604 for (i=0; i<num_traps; i++) { | |
1605 wmove(hw, i+2, 0); | |
1606 wprintw(hw, "[%d] %s", i+1, trap_types[i]); | |
1607 } | |
1608 mvwaddstr(hw, 0, 0, | |
1609 "Which kind of trap do you wish to set? "); | |
1610 | |
1611 if (menu_overlay) | |
1612 /* | |
1613 * Put out the selection. The longest line is | |
1614 * the prompt line (39 characters long). | |
1615 */ | |
1616 over_win(cw, hw, num_traps + 3, 41, 0, 39, NULL); | |
1617 else | |
1618 draw(hw); | |
1619 state = 1; /* Now in prompt window */ | |
1620 } | |
1621 break; | |
1622 | |
1623 case ESCAPE: | |
1624 if (state == 1) { | |
1625 clearok(cw, FALSE); /* Set up for redraw */ | |
1626 touchwin(cw); | |
1627 } | |
1628 msg(""); | |
1629 | |
1630 trap_tries--; /* Don't count this one */ | |
1631 after = FALSE; | |
1632 return; | |
1633 | |
1634 case '1': | |
1635 case '2': | |
1636 case '3': | |
1637 case '4': | |
1638 case '5': | |
1639 case '6': | |
1640 case '7': | |
1641 case '8': | |
1642 case '9': | |
1643 if (selection < '7' || wizard) { | |
1644 if (state == 1) { /* In prompt window */ | |
1645 clearok(cw, FALSE); /* Set up for redraw */ | |
1646 touchwin(cw); | |
1647 } | |
1648 | |
1649 msg(""); | |
1650 | |
1651 /* | |
1652 * Make sure there is a floor below us for trap | |
1653 * doors. | |
1654 */ | |
1655 if (selection == '1' && level >= nfloors) { | |
1656 if (state == 1) draw(cw); | |
1657 msg("There is no level below this one."); | |
1658 return; | |
1659 } | |
1660 state = 2; /* Finished */ | |
1661 break; | |
1662 } | |
1663 | |
1664 /* Fall through for non-wizard, unusual trap case */ | |
1665 default: | |
1666 if (state == 1) { /* In the prompt window */ | |
1667 wmove(hw, 0, 0); | |
1668 wprintw(hw, | |
1669 "Please enter a selection between 1 and %d: ", | |
1670 num_traps); | |
1671 if (menu_overlay) | |
1672 /* | |
1673 * Put out the selection. The longest line is | |
1674 * the prompt line (43 characters long). | |
1675 */ | |
1676 over_win(cw, hw, num_traps+3, 45, 0, 43, NULL); | |
1677 else | |
1678 draw(hw); | |
1679 } | |
1680 else { /* Normal window */ | |
1681 mpos = 0; | |
1682 msg("Please enter a selection between 1 and %d: ", | |
1683 num_traps); | |
1684 } | |
1685 } | |
1686 } while (state != 2); | |
1687 | |
1688 switch ((player.t_selection = selection)) { | |
1689 case '1': units = 20; /* Trap door */ | |
1690 when '2': units = 5; /* Bear trap */ | |
1691 when '3': units = 6; /* Sleeping gas trap */ | |
1692 when '4': units = 5; /* Arrow trap */ | |
1693 when '5': units = 8; /* Teleport trap */ | |
1694 when '6': units = 5; /* Dart trap */ | |
1695 otherwise: units = 10; /* Unknown trap */ | |
1696 } | |
1697 player.t_no_move = units * movement(&player); | |
1698 player.t_action = C_SETTRAP; | |
1699 player.t_using = NULL; | |
1700 return; | |
1701 } | |
1702 } | |
1703 | |
1704 if (is_player && player.t_ctype == C_THIEF) thief_bonus = 30; | |
1705 if (is_player && player.t_ctype == C_ASSASIN) thief_bonus = 20; | |
1706 | |
1707 s_dext = (tp == &player) ? dex_compute() : tp->t_stats.s_dext; | |
1708 | |
1709 if (ntraps >= MAXTRAPS || ++trap_tries >= MAXTRPTRY || levtype == POSTLEV || | |
1710 rnd(80) >= (s_dext + tp->t_stats.s_lvl/2 + thief_bonus)) { | |
1711 if (is_player) msg("The trap failed!"); | |
1712 return; | |
1713 } | |
1714 | |
1715 switch (selection) { | |
1716 case '1': ch = TRAPDOOR; | |
1717 when '2': ch = BEARTRAP; | |
1718 when '3': ch = SLEEPTRAP; | |
1719 when '4': ch = ARROWTRAP; | |
1720 when '5': ch = TELTRAP; | |
1721 when '6': ch = DARTTRAP; | |
1722 when '7': ch = POOL; | |
1723 when '8': ch = MAZETRAP; | |
1724 when '9': ch = POST; | |
1725 } | |
1726 | |
1727 mvaddch(y, x, ch); | |
1728 traps[ntraps].tr_show = och; | |
1729 traps[ntraps].tr_type = ch; | |
1730 traps[ntraps].tr_pos.y = y; | |
1731 traps[ntraps].tr_pos.x = x; | |
1732 if (is_player) | |
1733 traps[ntraps].tr_flags = ISTHIEFSET; | |
1734 if (ch == POOL || ch == POST) { | |
1735 traps[ntraps].tr_flags |= ISFOUND; | |
1736 } | |
1737 | |
1738 ntraps++; | |
1739 } | |
1740 | |
1741 /* | |
1742 * show: | |
1743 * returns what a certain thing will display as to the un-initiated | |
1744 */ | |
1745 | |
1746 show(y, x) | |
1747 register int y, x; | |
1748 { | |
1749 register char ch = CCHAR( winat(y, x) ); | |
1750 register struct linked_list *it; | |
1751 register struct thing *tp; | |
1752 | |
1753 if (isatrap(ch)) { | |
1754 register struct trap *trp = trap_at(y, x); | |
1755 | |
1756 return (trp->tr_flags & ISFOUND) ? ch : trp->tr_show; | |
1757 } | |
1758 else if (isalpha(ch)) { | |
1759 if ((it = find_mons(y, x)) == NULL) { | |
1760 msg("Show: Can't find monster in show (%d, %d)", y, x); | |
1761 return(mvwinch(stdscr, y, x)); | |
1762 } | |
1763 tp = THINGPTR(it); | |
1764 | |
1765 if (on(*tp, ISDISGUISE)) ch = tp->t_disguise; /* As a mimic */ | |
1766 | |
1767 /* Hide invisible creatures */ | |
1768 else if (invisible(tp)) { | |
1769 /* We can't see surprise-type creatures through "see invisible" */ | |
1770 if (off(player,CANSEE) || on(*tp,CANSURPRISE)) | |
1771 ch = CCHAR( mvwinch(stdscr, y, x) ); /* Invisible */ | |
1772 } | |
1773 else if (on(*tp, CANINWALL)) { | |
1774 if (isrock(mvwinch(stdscr, y, x))) ch = CCHAR( winch(stdscr) ); /* As Xorn */ | |
1775 } | |
1776 } | |
1777 return ch; | |
1778 } | |
1779 | |
1780 | |
1781 /* | |
1782 * trap_at: | |
1783 * find the trap at (y,x) on screen. | |
1784 */ | |
1785 | |
1786 struct trap * | |
1787 trap_at(y, x) | |
1788 register int y, x; | |
1789 { | |
1790 register struct trap *tp, *ep; | |
1791 | |
1792 ep = &traps[ntraps]; | |
1793 for (tp = traps; tp < ep; tp++) | |
1794 if (tp->tr_pos.y == y && tp->tr_pos.x == x) | |
1795 break; | |
1796 if (tp == ep) | |
1797 debug((sprintf(prbuf, "Trap at %d,%d not in array", y, x), prbuf)); | |
1798 return tp; | |
1799 } | |
1800 | |
1801 /* | |
1802 * weap_move: | |
1803 * Calculate how many segments it will take to swing the given | |
1804 * weapon (note that the weapon may actually be a stick or | |
1805 * even something else). | |
1806 */ | |
1807 | |
1808 weap_move(wielder, weap) | |
1809 register struct thing *wielder; /* Who's wielding the weapon */ | |
1810 register struct object *weap; /* The weapon */ | |
1811 { | |
1812 register int weap_rate; | |
1813 int dexterity; | |
1814 int strength; | |
1815 | |
1816 if (weap == NULL) return(1); /* hand, claw, bite attacks are quick */ | |
1817 | |
1818 switch (weap->o_type) { | |
1819 case STICK: | |
1820 if (EQUAL(ws_type[weap->o_which], "staff")) | |
1821 weap_rate = 2; | |
1822 else weap_rate = 1; /* A wand */ | |
1823 | |
1824 when WEAPON: | |
1825 weap_rate = weaps[weap->o_which].w_rate; | |
1826 | |
1827 /* Adjust for blessed or cursed weapon */ | |
1828 if (weap->o_hplus < 0) /* Cursed */ | |
1829 weap_rate -= (weap->o_hplus - 2) / 3; | |
1830 else if (weap_rate > 0) /* Blessed */ | |
1831 weap_rate -= (2*weap->o_hplus + weap_rate - 1) / weap_rate; | |
1832 | |
1833 when RELIC: | |
1834 switch (weap->o_which) { | |
1835 case MUSTY_DAGGER: | |
1836 case HRUGGEK_MSTAR: | |
1837 case AXE_AKLAD: | |
1838 case YEENOGHU_FLAIL: | |
1839 case MING_STAFF: | |
1840 case ORCUS_WAND: | |
1841 case ASMO_ROD: | |
1842 /* These operate in the blink of an eye */ | |
1843 weap_rate = 1; | |
1844 otherwise: | |
1845 /* What is it? */ | |
1846 weap_rate = 10; | |
1847 debug("unknown weapon in weap_move()"); | |
1848 } | |
1849 otherwise: | |
1850 /* What is it? */ | |
1851 weap_rate = 10; | |
1852 debug("unknown weapon in weap_move()"); | |
1853 } | |
1854 | |
1855 /* Put in a dexterity bonus */ | |
1856 if (wielder == &player) dexterity = dex_compute(); | |
1857 else dexterity = wielder->t_stats.s_dext; | |
1858 weap_rate -= dext_plus(dexterity) / 2; | |
1859 | |
1860 /* Put in a strength bonus */ | |
1861 if (wielder == &player) strength = str_compute(); | |
1862 else strength = wielder->t_stats.s_str; | |
1863 weap_rate -= str_plus(strength) / 2; | |
1864 | |
1865 /* It can't speed you up and it must take SOME time */ | |
1866 if (weap_rate <= 0) weap_rate = 1; | |
1867 | |
1868 /* Do we need to adjust for fast/slow movement? */ | |
1869 if (on(*wielder, ISSLOW) || on(*wielder, ISDANCE)) weap_rate *= 2; | |
1870 if (on(*wielder, ISHASTE)) weap_rate /= 2; | |
1871 | |
1872 /* Return the result */ | |
1873 return(weap_rate); | |
1874 } |