xref: /netbsd/games/hunt/huntd/execute.c (revision bf9ec67e)
1 /*	$NetBSD: execute.c,v 1.2 1997/10/10 16:33:13 lukem Exp $	*/
2 /*
3  *  Hunt
4  *  Copyright (c) 1985 Conrad C. Huang, Gregory S. Couch, Kenneth C.R.C. Arnold
5  *  San Francisco, California
6  */
7 
8 #include <sys/cdefs.h>
9 #ifndef lint
10 __RCSID("$NetBSD: execute.c,v 1.2 1997/10/10 16:33:13 lukem Exp $");
11 #endif /* not lint */
12 
13 # include	<stdlib.h>
14 # include	"hunt.h"
15 
16 static	void	cloak __P((PLAYER *));
17 static	void	face __P((PLAYER *, int));
18 static	void	fire __P((PLAYER *, int));
19 static	void	fire_slime __P((PLAYER *, int));
20 static	void	move_player __P((PLAYER *, int));
21 static	void	pickup __P((PLAYER *, int, int, int, int));
22 static	void	scan __P((PLAYER *));
23 
24 
25 # ifdef MONITOR
26 /*
27  * mon_execute:
28  *	Execute a single monitor command
29  */
30 void
31 mon_execute(pp)
32 	PLAYER	*pp;
33 {
34 	char	ch;
35 
36 	ch = pp->p_cbuf[pp->p_ncount++];
37 	switch (ch) {
38 	  case CTRL('L'):
39 		sendcom(pp, REDRAW);
40 		break;
41 	  case 'q':
42 		(void) strcpy(pp->p_death, "| Quit |");
43 		break;
44 	}
45 }
46 # endif
47 
48 /*
49  * execute:
50  *	Execute a single command
51  */
52 void
53 execute(pp)
54 	PLAYER	*pp;
55 {
56 	char	ch;
57 
58 	ch = pp->p_cbuf[pp->p_ncount++];
59 
60 # ifdef	FLY
61 	if (pp->p_flying >= 0) {
62 		switch (ch) {
63 		  case CTRL('L'):
64 			sendcom(pp, REDRAW);
65 			break;
66 		  case 'q':
67 			(void) strcpy(pp->p_death, "| Quit |");
68 			break;
69 		}
70 		return;
71 	}
72 # endif
73 
74 	switch (ch) {
75 	  case CTRL('L'):
76 		sendcom(pp, REDRAW);
77 		break;
78 	  case 'h':
79 		move_player(pp, LEFTS);
80 		break;
81 	  case 'H':
82 		face(pp, LEFTS);
83 		break;
84 	  case 'j':
85 		move_player(pp, BELOW);
86 		break;
87 	  case 'J':
88 		face(pp, BELOW);
89 		break;
90 	  case 'k':
91 		move_player(pp, ABOVE);
92 		break;
93 	  case 'K':
94 		face(pp, ABOVE);
95 		break;
96 	  case 'l':
97 		move_player(pp, RIGHT);
98 		break;
99 	  case 'L':
100 		face(pp, RIGHT);
101 		break;
102 	  case 'f':
103 	  case '1':
104 		fire(pp, 0);		/* SHOT */
105 		break;
106 	  case 'g':
107 	  case '2':
108 		fire(pp, 1);		/* GRENADE */
109 		break;
110 	  case 'F':
111 	  case '3':
112 		fire(pp, 2);		/* SATCHEL */
113 		break;
114 	  case 'G':
115 	  case '4':
116 		fire(pp, 3);		/* 7x7 BOMB */
117 		break;
118 	  case '5':
119 		fire(pp, 4);		/* 9x9 BOMB */
120 		break;
121 	  case '6':
122 		fire(pp, 5);		/* 11x11 BOMB */
123 		break;
124 	  case '7':
125 		fire(pp, 6);		/* 13x13 BOMB */
126 		break;
127 	  case '8':
128 		fire(pp, 7);		/* 15x15 BOMB */
129 		break;
130 	  case '9':
131 		fire(pp, 8);		/* 17x17 BOMB */
132 		break;
133 	  case '0':
134 		fire(pp, 9);		/* 19x19 BOMB */
135 		break;
136 	  case '@':
137 		fire(pp, 10);		/* 21x21 BOMB */
138 		break;
139 # ifdef	OOZE
140 	  case 'o':
141 		fire_slime(pp, 0);	/* SLIME */
142 		break;
143 	  case 'O':
144 		fire_slime(pp, 1);	/* SSLIME */
145 		break;
146 	  case 'p':
147 		fire_slime(pp, 2);
148 		break;
149 	  case 'P':
150 		fire_slime(pp, 3);
151 		break;
152 # endif
153 	  case 's':
154 		scan(pp);
155 		break;
156 	  case 'c':
157 		cloak(pp);
158 		break;
159 	  case 'q':
160 		(void) strcpy(pp->p_death, "| Quit |");
161 		break;
162 	}
163 }
164 
165 /*
166  * move_player:
167  *	Execute a move in the given direction
168  */
169 static void
170 move_player(pp, dir)
171 	PLAYER	*pp;
172 	int	dir;
173 {
174 	PLAYER	*newp;
175 	int	x, y;
176 	FLAG	moved;
177 	BULLET	*bp;
178 
179 	y = pp->p_y;
180 	x = pp->p_x;
181 
182 	switch (dir) {
183 	  case LEFTS:
184 		x--;
185 		break;
186 	  case RIGHT:
187 		x++;
188 		break;
189 	  case ABOVE:
190 		y--;
191 		break;
192 	  case BELOW:
193 		y++;
194 		break;
195 	}
196 
197 	moved = FALSE;
198 	switch (Maze[y][x]) {
199 	  case SPACE:
200 # ifdef RANDOM
201 	  case DOOR:
202 # endif
203 		moved = TRUE;
204 		break;
205 	  case WALL1:
206 	  case WALL2:
207 	  case WALL3:
208 # ifdef REFLECT
209 	  case WALL4:
210 	  case WALL5:
211 # endif
212 		break;
213 	  case MINE:
214 	  case GMINE:
215 		if (dir == pp->p_face)
216 			pickup(pp, y, x, 2, Maze[y][x]);
217 		else if (opposite(dir, pp->p_face))
218 			pickup(pp, y, x, 95, Maze[y][x]);
219 		else
220 			pickup(pp, y, x, 50, Maze[y][x]);
221 		Maze[y][x] = SPACE;
222 		moved = TRUE;
223 		break;
224 	  case SHOT:
225 	  case GRENADE:
226 	  case SATCHEL:
227 	  case BOMB:
228 # ifdef OOZE
229 	  case SLIME:
230 # endif
231 # ifdef DRONE
232 	  case DSHOT:
233 # endif
234 		bp = is_bullet(y, x);
235 		if (bp != NULL)
236 			bp->b_expl = TRUE;
237 		Maze[y][x] = SPACE;
238 		moved = TRUE;
239 		break;
240 	  case LEFTS:
241 	  case RIGHT:
242 	  case ABOVE:
243 	  case BELOW:
244 		if (dir != pp->p_face)
245 			sendcom(pp, BELL);
246 		else {
247 			newp = play_at(y, x);
248 			checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE);
249 		}
250 		break;
251 # ifdef FLY
252 	  case FLYER:
253 		newp = play_at(y, x);
254 		message(newp, "Oooh, there's a short guy waving at you!");
255 		message(pp, "You couldn't quite reach him!");
256 		break;
257 # endif
258 # ifdef BOOTS
259 	  case BOOT:
260 	  case BOOT_PAIR:
261 		if (Maze[y][x] == BOOT)
262 			pp->p_nboots++;
263 		else
264 			pp->p_nboots += 2;
265 		for (newp = Boot; newp < &Boot[NBOOTS]; newp++) {
266 			if (newp->p_flying < 0)
267 				continue;
268 			if (newp->p_y == y && newp->p_x == x) {
269 				newp->p_flying = -1;
270 				if (newp->p_undershot)
271 					fixshots(y, x, newp->p_over);
272 			}
273 		}
274 		if (pp->p_nboots == 2)
275 			message(pp, "Wow!  A pair of boots!");
276 		else
277 			message(pp, "You can hobble around on one boot.");
278 		Maze[y][x] = SPACE;
279 		moved = TRUE;
280 		break;
281 # endif
282 	}
283 	if (moved) {
284 		if (pp->p_ncshot > 0)
285 			if (--pp->p_ncshot == MAXNCSHOT) {
286 				cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
287 				outstr(pp, " ok", 3);
288 			}
289 		if (pp->p_undershot) {
290 			fixshots(pp->p_y, pp->p_x, pp->p_over);
291 			pp->p_undershot = FALSE;
292 		}
293 		drawplayer(pp, FALSE);
294 		pp->p_over = Maze[y][x];
295 		pp->p_y = y;
296 		pp->p_x = x;
297 		drawplayer(pp, TRUE);
298 	}
299 }
300 
301 /*
302  * face:
303  *	Change the direction the player is facing
304  */
305 static void
306 face(pp, dir)
307 	PLAYER	*pp;
308 	int	dir;
309 {
310 	if (pp->p_face != dir) {
311 		pp->p_face = dir;
312 		drawplayer(pp, TRUE);
313 	}
314 }
315 
316 /*
317  * fire:
318  *	Fire a shot of the given type in the given direction
319  */
320 static void
321 fire(pp, req_index)
322 	PLAYER	*pp;
323 	int	req_index;
324 {
325 	if (pp == NULL)
326 		return;
327 # ifdef DEBUG
328 	if (req_index < 0 || req_index >= MAXBOMB)
329 		message(pp, "What you do?");
330 # endif
331 	while (req_index >= 0 && pp->p_ammo < shot_req[req_index])
332 		req_index--;
333 	if (req_index < 0) {
334 		message(pp, "Not enough charges.");
335 		return;
336 	}
337 	if (pp->p_ncshot > MAXNCSHOT)
338 		return;
339 	if (pp->p_ncshot++ == MAXNCSHOT) {
340 		cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
341 		outstr(pp, "   ", 3);
342 	}
343 	pp->p_ammo -= shot_req[req_index];
344 	(void) sprintf(Buf, "%3d", pp->p_ammo);
345 	cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
346 	outstr(pp, Buf, 3);
347 
348 	add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face,
349 		shot_req[req_index], pp, FALSE, pp->p_face);
350 	pp->p_undershot = TRUE;
351 
352 	/*
353 	 * Show the object to everyone
354 	 */
355 	showexpl(pp->p_y, pp->p_x, shot_type[req_index]);
356 	for (pp = Player; pp < End_player; pp++)
357 		sendcom(pp, REFRESH);
358 # ifdef MONITOR
359 	for (pp = Monitor; pp < End_monitor; pp++)
360 		sendcom(pp, REFRESH);
361 # endif
362 }
363 
364 # ifdef	OOZE
365 /*
366  * fire_slime:
367  *	Fire a slime shot in the given direction
368  */
369 static void
370 fire_slime(pp, req_index)
371 	PLAYER	*pp;
372 	int	req_index;
373 {
374 	if (pp == NULL)
375 		return;
376 # ifdef DEBUG
377 	if (req_index < 0 || req_index >= MAXSLIME)
378 		message(pp, "What you do?");
379 # endif
380 	while (req_index >= 0 && pp->p_ammo < slime_req[req_index])
381 		req_index--;
382 	if (req_index < 0) {
383 		message(pp, "Not enough charges.");
384 		return;
385 	}
386 	if (pp->p_ncshot > MAXNCSHOT)
387 		return;
388 	if (pp->p_ncshot++ == MAXNCSHOT) {
389 		cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
390 		outstr(pp, "   ", 3);
391 	}
392 	pp->p_ammo -= slime_req[req_index];
393 	(void) sprintf(Buf, "%3d", pp->p_ammo);
394 	cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
395 	outstr(pp, Buf, 3);
396 
397 	add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face,
398 		slime_req[req_index] * SLIME_FACTOR, pp, FALSE, pp->p_face);
399 	pp->p_undershot = TRUE;
400 
401 	/*
402 	 * Show the object to everyone
403 	 */
404 	showexpl(pp->p_y, pp->p_x, SLIME);
405 	for (pp = Player; pp < End_player; pp++)
406 		sendcom(pp, REFRESH);
407 # ifdef MONITOR
408 	for (pp = Monitor; pp < End_monitor; pp++)
409 		sendcom(pp, REFRESH);
410 # endif
411 }
412 # endif
413 
414 /*
415  * add_shot:
416  *	Create a shot with the given properties
417  */
418 void
419 add_shot(type, y, x, face, charge, owner, expl, over)
420 int	type;
421 int	y, x;
422 char	face;
423 int	charge;
424 PLAYER	*owner;
425 int	expl;
426 char	over;
427 {
428 	BULLET	*bp;
429 	int	size;
430 
431 	switch (type) {
432 	  case SHOT:
433 	  case MINE:
434 		size = 1;
435 		break;
436 	  case GRENADE:
437 	  case GMINE:
438 		size = 2;
439 		break;
440 	  case SATCHEL:
441 		size = 3;
442 		break;
443 	  case BOMB:
444 		for (size = 3; size < MAXBOMB; size++)
445 			if (shot_req[size] >= charge)
446 				break;
447 		size++;
448 		break;
449 	  default:
450 		size = 0;
451 		break;
452 	}
453 
454 	bp = create_shot(type, y, x, face, charge, size, owner,
455 		(owner == NULL) ? NULL : owner->p_ident, expl, over);
456 	bp->b_next = Bullets;
457 	Bullets = bp;
458 }
459 
460 BULLET *
461 create_shot(type, y, x, face, charge, size, owner, score, expl, over)
462 	int	type;
463 	int	y, x;
464 	char	face;
465 	int	charge;
466 	int	size;
467 	PLAYER	*owner;
468 	IDENT	*score;
469 	int	expl;
470 	char	over;
471 {
472 	BULLET	*bp;
473 
474 	bp = (BULLET *) malloc(sizeof (BULLET));	/* NOSTRICT */
475 	if (bp == NULL) {
476 		if (owner != NULL)
477 			message(owner, "Out of memory");
478 		return NULL;
479 	}
480 
481 	bp->b_face = face;
482 	bp->b_x = x;
483 	bp->b_y = y;
484 	bp->b_charge = charge;
485 	bp->b_owner = owner;
486 	bp->b_score = score;
487 	bp->b_type = type;
488 	bp->b_size = size;
489 	bp->b_expl = expl;
490 	bp->b_over = over;
491 	bp->b_next = NULL;
492 
493 	return bp;
494 }
495 
496 /*
497  * cloak:
498  *	Turn on or increase length of a cloak
499  */
500 static void
501 cloak(pp)
502 	PLAYER	*pp;
503 {
504 	if (pp->p_ammo <= 0) {
505 		message(pp, "No more charges");
506 		return;
507 	}
508 # ifdef BOOTS
509 	if (pp->p_nboots > 0) {
510 		message(pp, "Boots are too noisy to cloak!");
511 		return;
512 	}
513 # endif
514 	(void) sprintf(Buf, "%3d", --pp->p_ammo);
515 	cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
516 	outstr(pp, Buf, 3);
517 
518 	pp->p_cloak += CLOAKLEN;
519 
520 	if (pp->p_scan >= 0)
521 		pp->p_scan = -1;
522 
523 	showstat(pp);
524 }
525 
526 /*
527  * scan:
528  *	Turn on or increase length of a scan
529  */
530 static void
531 scan(pp)
532 	PLAYER	*pp;
533 {
534 	if (pp->p_ammo <= 0) {
535 		message(pp, "No more charges");
536 		return;
537 	}
538 	(void) sprintf(Buf, "%3d", --pp->p_ammo);
539 	cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
540 	outstr(pp, Buf, 3);
541 
542 	pp->p_scan += SCANLEN;
543 
544 	if (pp->p_cloak >= 0)
545 		pp->p_cloak = -1;
546 
547 	showstat(pp);
548 }
549 
550 /*
551  * pickup:
552  *	check whether the object blew up or whether he picked it up
553  */
554 void
555 pickup(pp, y, x, prob, obj)
556 	PLAYER	*pp;
557 	int	y, x;
558 	int	prob;
559 	int	obj;
560 {
561 	int	req;
562 
563 	switch (obj) {
564 	  case MINE:
565 		req = BULREQ;
566 		break;
567 	  case GMINE:
568 		req = GRENREQ;
569 		break;
570 	  default:
571 		abort();
572 	}
573 	if (rand_num(100) < prob)
574 		add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL,
575 			TRUE, pp->p_face);
576 	else {
577 		pp->p_ammo += req;
578 		(void) sprintf(Buf, "%3d", pp->p_ammo);
579 		cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
580 		outstr(pp, Buf, 3);
581 	}
582 }
583