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