1 /*
2  * Hero movement commands
3  *
4  * move.c	1.4 (A.I. Design)	12/22/84
5  */
6 
7 #include "rogue.h"
8 #include "curses.h"
9 
10 /*
11  * Used to hold the new hero position
12  */
13 
14 coord nh;
15 
16 /*
17  * do_run:
18  *	Start the hero running
19  */
20 do_run(ch)
21 byte ch;
22 {
23     running = TRUE;
24     after = FALSE;
25     runch = ch;
26 }
27 
28 /*
29  * do_move:
30  *	Check to see that a move is legal.  If it is handle the
31  * consequences (fighting, picking up, etc.)
32  */
33 do_move(dy, dx)
34 int dy, dx;
35 {
36     register byte ch;
37     register int fl;
38 
39     firstmove = FALSE;
40     if (bailout) {
41     	bailout = 0;
42     	msg("the crack widens ... ");
43     	descend("");
44     	return ;
45     }
46     if (no_move) {
47 		no_move--;
48 		msg("you are still stuck in the bear trap");
49 		return;
50     }
51     /*
52      * Do a confused move (maybe)
53      */
54     if (on(player, ISHUH) && rnd(5) != 0)
55 		rndmove(&player,&nh);
56     else {
57 over:
58 		nh.y = hero.y + dy;
59 		nh.x = hero.x + dx;
60     }
61 
62     /*
63      * Check if he tried to move off the screen or make an illegal
64      * diagonal move, and stop him if he did.
65      * fudge it for 40/80 jll -- 2/7/84
66      */
67     if (offmap(nh.y, nh.x))
68 		goto hit_bound;
69     if (!diag_ok(&hero, &nh)) {
70 		after = FALSE;
71 		running = FALSE;
72 		return;
73     }
74     /*
75      * If you are running and the move does 
76      * not get you anywhere stop running
77      */
78     if (running && ce(hero, nh))
79 		after = running = FALSE;
80     fl = flat(nh.y, nh.x);
81     ch = winat(nh.y, nh.x);
82     /*
83      * When the hero is on the door do not allow him
84      * to run until he enters the room all the way
85      */  
86     if ((chat(hero.y,hero.x) == DOOR) && (ch == FLOOR))
87     	running = FALSE;
88     if (!(fl & F_REAL) && ch == FLOOR) {
89 		chat(nh.y, nh.x) = ch = TRAP;
90 		flat(nh.y, nh.x) |= F_REAL;
91     }
92     else if (on(player, ISHELD) && ch != 'F') {
93 		msg("you are being held");
94 		return;
95     }
96     switch (ch) {
97 	case ' ':
98 	case VWALL:
99 	case HWALL:
100 	case ULWALL:
101 	case URWALL:
102 	case LLWALL:
103 	case LRWALL:
104 hit_bound:
105 	    if (running && isgone(proom) && !on(player, ISBLIND)) {
106 			register bool	b1, b2;
107 
108 			switch (runch)
109 			{
110 		    case 'h':
111 		    case 'l':
112 				b1 = (hero.y > 1 &&
113 					((flat(hero.y - 1, hero.x) & F_PASS) || 
114 			    	  chat(hero.y - 1, hero.x) == DOOR));
115 				b2 = (hero.y < maxrow - 1 &&
116 					((flat(hero.y + 1, hero.x) & F_PASS) || 
117 					  chat(hero.y + 1, hero.x) == DOOR));
118 				if (!(b1 ^ b2))
119 				    break;
120 				if (b1) {
121 				    runch = 'k';
122 				    dy = -1;
123 				} else {
124 				    runch = 'j';
125 				    dy = 1;
126 				}
127 				dx = 0;
128 				goto over;
129 		    case 'j':
130 		    case 'k':
131 				b1 = (hero.x > 1 &&
132 					((flat(hero.y, hero.x - 1) & F_PASS)
133 					|| chat(hero.y, hero.x - 1) == DOOR));
134 				b2 = (hero.x < COLS-2 &&
135 					((flat(hero.y, hero.x + 1) & F_PASS)
136 					|| chat(hero.y, hero.x + 1) == DOOR));
137 				if (!(b1 ^ b2))
138 				    break;
139 				if (b1) {
140 				    runch = 'h';
141 				    dx = -1;
142 				} else {
143 				    runch = 'l';
144 				    dx = 1;
145 				}
146 				dy = 0;
147 				goto over;
148 			}
149 	    }
150 	    after = running = FALSE;
151 	    break;
152 	case DOOR:
153 	    running = FALSE;
154 	    if (flat(hero.y, hero.x) & F_PASS)
155 			enter_room(&nh);
156 	    goto move_stuff;
157 	case TRAP:
158 	    ch = be_trapped(&nh);
159 	    if (ch == T_DOOR || ch == T_TELEP)
160 			return;
161 	case PASSAGE:
162 	    goto move_stuff;
163 	case FLOOR:
164 	    if (!(fl & F_REAL))
165 			be_trapped(&hero);
166 	    goto move_stuff;
167 	default:
168 	    running = FALSE;
169 	    if (isupper(ch) || moat(nh.y, nh.x))
170 			fight(&nh, ch, cur_weapon, FALSE);
171 	    else {
172 			running = FALSE;
173 			if (ch != STAIRS)
174 			    take = ch;
175 move_stuff:
176 			mvaddch(hero.y, hero.x, chat(hero.y, hero.x));
177 			if ((fl & F_PASS) && (chat(oldpos.y, oldpos.x) == DOOR
178 					|| (flat(oldpos.y, oldpos.x) & F_MAZE)))
179 			    leave_room(&nh);
180 			if ((fl & F_MAZE) && (flat(oldpos.y, oldpos.x) & F_MAZE) == 0)
181 			    enter_room(&nh);
182 			bcopy(hero,nh);
183 	    }
184     }
185 }
186 
187 /*
188  * door_open:
189  *	Called to illuminate a room.  If it is dark, remove anything
190  *	that might move.
191  */
192 door_open(rp)
193 struct room *rp;
194 {
195     register int j, k;
196     register byte ch;
197     register THING *item;
198 
199     if (!(rp->r_flags & ISGONE) && !on(player, ISBLIND))
200 		for (j = rp->r_pos.y; j < rp->r_pos.y + rp->r_max.y; j++)
201 		    for (k = rp->r_pos.x; k < rp->r_pos.x + rp->r_max.x; k++) {
202 				ch = winat(j, k);
203 				/* move(j, k); Why do this,?????? */
204 				if (isupper(ch)) {
205 				    item = wake_monster(j, k);
206 				    if (item->t_oldch == ' ' && !(rp->r_flags & ISDARK)
207 						&& !on(player, ISBLIND))
208 						    item->t_oldch = chat(j, k);
209 				}
210 		    }
211 }
212 
213 /*
214  * be_trapped:
215  *	The guy stepped on a trap.... Make him pay.
216  */
217 be_trapped(tc)
218 register coord *tc;
219 {
220     register byte tr;
221     register int index;
222 
223     count = running = FALSE;
224     index = INDEX(tc->y, tc->x);
225     _level[index] = TRAP;
226     tr = _flags[index] & F_TMASK;
227     was_trapped = TRUE;
228     switch (tr) {
229 	when T_DOOR:
230 	    descend("you fell into a trap!");
231 	when T_BEAR:
232 	    no_move += BEARTIME;
233 	    msg("you are caught in a bear trap");
234 	when T_SLEEP:
235 	    no_command += SLEEPTIME;
236 	    player.t_flags &= ~ISRUN;
237 	    msg("a %smist envelops you and you fall asleep",
238 	        noterse("strange white "));
239 	when T_ARROW:
240 	    if (swing(pstats.s_lvl-1, pstats.s_arm, 1)) {
241 			pstats.s_hpt -= roll(1, 6);
242 			if (pstats.s_hpt <= 0) {
243 			    msg("an arrow killed you");
244 			    death('a');
245 			} else
246 			    msg("oh no! An arrow shot you");
247 	    }
248 	    else {
249 			THING *arrow;
250 
251 			if ((arrow = new_item()) != NULL) {
252 			    arrow->o_type = WEAPON;
253 			    arrow->o_which = ARROW;
254 			    init_weapon(arrow, ARROW);
255 			    arrow->o_count = 1;
256 			    bcopy(arrow->o_pos,hero);
257 			    fall(arrow, FALSE);
258 			}
259 			msg("an arrow shoots past you");
260 	    }
261 	when T_TELEP:
262 	    teleport();
263 	    mvaddch(tc->y, tc->x, TRAP); /* since the hero's leaving, look()
264 					    won't put it on for us */
265 	    was_trapped++;
266 	when T_DART:
267 	    if (swing(pstats.s_lvl+1, pstats.s_arm, 1)) {
268 			pstats.s_hpt -= roll(1, 4);
269 			if (pstats.s_hpt <= 0) {
270 			    msg("a poisoned dart killed you");
271 			    death('d');
272 			}
273 			if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON))
274 			    chg_str(-1);
275 			msg("a dart just hit you in the shoulder");
276 		} else
277 			msg("a dart whizzes by your ear and vanishes");
278 	}
279     flush_type();
280     return tr;
281 }
282 
283 descend(mesg)
284     char *mesg;
285 {
286     level++;
287     if (*mesg == 0)
288     	msg(" ");
289     new_level();
290     msg("");
291     msg(mesg);
292     if (!save(VS_LUCK)) {
293 		msg("you are damaged by the fall");
294 		if ((pstats.s_hpt -= roll(1,8)) <= 0)
295 			death('f');
296     }
297 }
298 
299 /*
300  * rndmove:
301  *	Move in a random direction if the monster/person is confused
302  */
303 rndmove(who,newmv)
304 THING *who;
305 coord *newmv;
306 {
307     register int x, y;
308     register byte ch;
309     register THING *obj;
310 
311     y = newmv->y = who->t_pos.y + rnd(3) - 1;
312     x = newmv->x = who->t_pos.x + rnd(3) - 1;
313     /*
314      * Now check to see if that's a legal move.  If not, don't move.
315      * (I.e., bump into the wall or whatever)
316      */
317     if (y == who->t_pos.y && x == who->t_pos.x)
318 		return ;
319     if ((y < 1 || y >= maxrow) || (x < 0 || x >= COLS))
320 		goto bad;
321     else if (!diag_ok(&who->t_pos, newmv))
322 		goto bad;
323     else {
324 		ch = winat(y, x);
325 		if (!step_ok(ch))
326 		    goto bad;
327 		if (ch == SCROLL) {
328 		    for (obj = lvl_obj; obj != NULL; obj = next(obj))
329 				if (y == obj->o_pos.y && x == obj->o_pos.x)
330 				    break;
331 		    if (obj != NULL && obj->o_which == S_SCARE)
332 				goto bad;
333 		}
334     }
335     return ;
336 
337 bad:
338     bcopy((*newmv),who->t_pos);
339     return ;
340 }
341 