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