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