16693db17SSascha Wildner /*-
282a5c12eSMatthew Dillon * Copyright (c) 1983-2003, Regents of the University of California.
382a5c12eSMatthew Dillon * All rights reserved.
482a5c12eSMatthew Dillon *
582a5c12eSMatthew Dillon * Redistribution and use in source and binary forms, with or without
682a5c12eSMatthew Dillon * modification, are permitted provided that the following conditions are
782a5c12eSMatthew Dillon * met:
882a5c12eSMatthew Dillon *
96693db17SSascha Wildner * 1. Redistributions of source code must retain the above copyright
1082a5c12eSMatthew Dillon * notice, this list of conditions and the following disclaimer.
116693db17SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
1282a5c12eSMatthew Dillon * notice, this list of conditions and the following disclaimer in the
1382a5c12eSMatthew Dillon * documentation and/or other materials provided with the distribution.
146693db17SSascha Wildner * 3. Neither the name of the University of California, San Francisco nor
1582a5c12eSMatthew Dillon * the names of its contributors may be used to endorse or promote
1682a5c12eSMatthew Dillon * products derived from this software without specific prior written
1782a5c12eSMatthew Dillon * permission.
1882a5c12eSMatthew Dillon *
1982a5c12eSMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
2082a5c12eSMatthew Dillon * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2182a5c12eSMatthew Dillon * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
2282a5c12eSMatthew Dillon * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2382a5c12eSMatthew Dillon * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2482a5c12eSMatthew Dillon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2582a5c12eSMatthew Dillon * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2682a5c12eSMatthew Dillon * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2782a5c12eSMatthew Dillon * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2882a5c12eSMatthew Dillon * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2982a5c12eSMatthew Dillon * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3082a5c12eSMatthew Dillon *
3182a5c12eSMatthew Dillon * $OpenBSD: execute.c,v 1.8 2004/01/16 00:13:19 espie Exp $
3282a5c12eSMatthew Dillon * $NetBSD: execute.c,v 1.2 1997/10/10 16:33:13 lukem Exp $
3382a5c12eSMatthew Dillon */
3482a5c12eSMatthew Dillon
3582a5c12eSMatthew Dillon #include <stdlib.h>
3682a5c12eSMatthew Dillon #include <string.h>
3782a5c12eSMatthew Dillon #include <syslog.h>
3882a5c12eSMatthew Dillon #include "hunt.h"
3982a5c12eSMatthew Dillon #include "conf.h"
4082a5c12eSMatthew Dillon #include "server.h"
4182a5c12eSMatthew Dillon
4282a5c12eSMatthew Dillon static void cloak(PLAYER *);
4382a5c12eSMatthew Dillon static void face(PLAYER *, int);
4482a5c12eSMatthew Dillon static void fire(PLAYER *, int);
4582a5c12eSMatthew Dillon static void fire_slime(PLAYER *, int);
4682a5c12eSMatthew Dillon static void move_player(PLAYER *, int);
4782a5c12eSMatthew Dillon static void pickup(PLAYER *, int, int, int, int);
4882a5c12eSMatthew Dillon static void scan(PLAYER *);
4982a5c12eSMatthew Dillon
5082a5c12eSMatthew Dillon
5182a5c12eSMatthew Dillon /*
5282a5c12eSMatthew Dillon * mon_execute:
5382a5c12eSMatthew Dillon * Execute a single monitor command
5482a5c12eSMatthew Dillon */
5582a5c12eSMatthew Dillon void
mon_execute(PLAYER * pp)566beb426bSSascha Wildner mon_execute(PLAYER *pp)
5782a5c12eSMatthew Dillon {
5882a5c12eSMatthew Dillon char ch;
5982a5c12eSMatthew Dillon
6082a5c12eSMatthew Dillon ch = pp->p_cbuf[pp->p_ncount++];
6182a5c12eSMatthew Dillon
6282a5c12eSMatthew Dillon switch (ch) {
6382a5c12eSMatthew Dillon case CTRL('L'):
6482a5c12eSMatthew Dillon /* Redraw messed-up screen */
6582a5c12eSMatthew Dillon sendcom(pp, REDRAW);
6682a5c12eSMatthew Dillon break;
6782a5c12eSMatthew Dillon case 'q':
6882a5c12eSMatthew Dillon /* Quit client */
69d9f85b33Szrj strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
7082a5c12eSMatthew Dillon break;
7182a5c12eSMatthew Dillon default:
7282a5c12eSMatthew Dillon /* Ignore everything else */
7382a5c12eSMatthew Dillon ;
7482a5c12eSMatthew Dillon }
7582a5c12eSMatthew Dillon }
7682a5c12eSMatthew Dillon
7782a5c12eSMatthew Dillon /*
7882a5c12eSMatthew Dillon * execute:
7982a5c12eSMatthew Dillon * Execute a single command from a player
8082a5c12eSMatthew Dillon */
8182a5c12eSMatthew Dillon void
execute(PLAYER * pp)826beb426bSSascha Wildner execute(PLAYER *pp)
8382a5c12eSMatthew Dillon {
8482a5c12eSMatthew Dillon char ch;
8582a5c12eSMatthew Dillon
8682a5c12eSMatthew Dillon ch = pp->p_cbuf[pp->p_ncount++];
8782a5c12eSMatthew Dillon
8882a5c12eSMatthew Dillon /* When flying, only allow refresh and quit. */
8982a5c12eSMatthew Dillon if (pp->p_flying >= 0) {
9082a5c12eSMatthew Dillon switch (ch) {
9182a5c12eSMatthew Dillon case CTRL('L'):
9282a5c12eSMatthew Dillon sendcom(pp, REDRAW);
9382a5c12eSMatthew Dillon break;
9482a5c12eSMatthew Dillon case 'q':
95d9f85b33Szrj strlcpy(pp->p_death, "| Quit |",
9682a5c12eSMatthew Dillon sizeof pp->p_death);
9782a5c12eSMatthew Dillon break;
9882a5c12eSMatthew Dillon }
9982a5c12eSMatthew Dillon return;
10082a5c12eSMatthew Dillon }
10182a5c12eSMatthew Dillon
10282a5c12eSMatthew Dillon /* Decode the command character: */
10382a5c12eSMatthew Dillon switch (ch) {
10482a5c12eSMatthew Dillon case CTRL('L'):
10582a5c12eSMatthew Dillon sendcom(pp, REDRAW); /* Refresh */
10682a5c12eSMatthew Dillon break;
10782a5c12eSMatthew Dillon case 'h':
10882a5c12eSMatthew Dillon move_player(pp, LEFTS); /* Move left */
10982a5c12eSMatthew Dillon break;
11082a5c12eSMatthew Dillon case 'H':
11182a5c12eSMatthew Dillon face(pp, LEFTS); /* Face left */
11282a5c12eSMatthew Dillon break;
11382a5c12eSMatthew Dillon case 'j':
11482a5c12eSMatthew Dillon move_player(pp, BELOW); /* Move down */
11582a5c12eSMatthew Dillon break;
11682a5c12eSMatthew Dillon case 'J':
11782a5c12eSMatthew Dillon face(pp, BELOW); /* Face down */
11882a5c12eSMatthew Dillon break;
11982a5c12eSMatthew Dillon case 'k':
12082a5c12eSMatthew Dillon move_player(pp, ABOVE); /* Move up */
12182a5c12eSMatthew Dillon break;
12282a5c12eSMatthew Dillon case 'K':
12382a5c12eSMatthew Dillon face(pp, ABOVE); /* Face up */
12482a5c12eSMatthew Dillon break;
12582a5c12eSMatthew Dillon case 'l':
12682a5c12eSMatthew Dillon move_player(pp, RIGHT); /* Move right */
12782a5c12eSMatthew Dillon break;
12882a5c12eSMatthew Dillon case 'L':
12982a5c12eSMatthew Dillon face(pp, RIGHT); /* Face right */
13082a5c12eSMatthew Dillon break;
13182a5c12eSMatthew Dillon case 'f':
13282a5c12eSMatthew Dillon case '1':
13382a5c12eSMatthew Dillon fire(pp, 0); /* SHOT */
13482a5c12eSMatthew Dillon break;
13582a5c12eSMatthew Dillon case 'g':
13682a5c12eSMatthew Dillon case '2':
13782a5c12eSMatthew Dillon fire(pp, 1); /* GRENADE */
13882a5c12eSMatthew Dillon break;
13982a5c12eSMatthew Dillon case 'F':
14082a5c12eSMatthew Dillon case '3':
14182a5c12eSMatthew Dillon fire(pp, 2); /* SATCHEL */
14282a5c12eSMatthew Dillon break;
14382a5c12eSMatthew Dillon case 'G':
14482a5c12eSMatthew Dillon case '4':
14582a5c12eSMatthew Dillon fire(pp, 3); /* 7x7 BOMB */
14682a5c12eSMatthew Dillon break;
14782a5c12eSMatthew Dillon case '5':
14882a5c12eSMatthew Dillon fire(pp, 4); /* 9x9 BOMB */
14982a5c12eSMatthew Dillon break;
15082a5c12eSMatthew Dillon case '6':
15182a5c12eSMatthew Dillon fire(pp, 5); /* 11x11 BOMB */
15282a5c12eSMatthew Dillon break;
15382a5c12eSMatthew Dillon case '7':
15482a5c12eSMatthew Dillon fire(pp, 6); /* 13x13 BOMB */
15582a5c12eSMatthew Dillon break;
15682a5c12eSMatthew Dillon case '8':
15782a5c12eSMatthew Dillon fire(pp, 7); /* 15x15 BOMB */
15882a5c12eSMatthew Dillon break;
15982a5c12eSMatthew Dillon case '9':
16082a5c12eSMatthew Dillon fire(pp, 8); /* 17x17 BOMB */
16182a5c12eSMatthew Dillon break;
16282a5c12eSMatthew Dillon case '0':
16382a5c12eSMatthew Dillon fire(pp, 9); /* 19x19 BOMB */
16482a5c12eSMatthew Dillon break;
16582a5c12eSMatthew Dillon case '@':
16682a5c12eSMatthew Dillon fire(pp, 10); /* 21x21 BOMB */
16782a5c12eSMatthew Dillon break;
16882a5c12eSMatthew Dillon case 'o':
16982a5c12eSMatthew Dillon fire_slime(pp, 0); /* SLIME */
17082a5c12eSMatthew Dillon break;
17182a5c12eSMatthew Dillon case 'O':
17282a5c12eSMatthew Dillon fire_slime(pp, 1); /* SSLIME */
17382a5c12eSMatthew Dillon break;
17482a5c12eSMatthew Dillon case 'p':
17582a5c12eSMatthew Dillon fire_slime(pp, 2); /* large slime */
17682a5c12eSMatthew Dillon break;
17782a5c12eSMatthew Dillon case 'P':
17882a5c12eSMatthew Dillon fire_slime(pp, 3); /* very large slime */
17982a5c12eSMatthew Dillon break;
18082a5c12eSMatthew Dillon case 's': /* start scanning */
18182a5c12eSMatthew Dillon scan(pp);
18282a5c12eSMatthew Dillon break;
18382a5c12eSMatthew Dillon case 'c': /* start cloaking */
18482a5c12eSMatthew Dillon cloak(pp);
18582a5c12eSMatthew Dillon break;
18682a5c12eSMatthew Dillon case 'q': /* quit */
187d9f85b33Szrj strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
18882a5c12eSMatthew Dillon break;
18982a5c12eSMatthew Dillon }
19082a5c12eSMatthew Dillon }
19182a5c12eSMatthew Dillon
19282a5c12eSMatthew Dillon /*
19382a5c12eSMatthew Dillon * move_player:
19482a5c12eSMatthew Dillon * Try to move player 'pp' in direction 'dir'.
19582a5c12eSMatthew Dillon */
19682a5c12eSMatthew Dillon static void
move_player(PLAYER * pp,int dir)1976beb426bSSascha Wildner move_player(PLAYER *pp, int dir)
19882a5c12eSMatthew Dillon {
19982a5c12eSMatthew Dillon PLAYER *newp;
20082a5c12eSMatthew Dillon int x, y;
20182a5c12eSMatthew Dillon FLAG moved;
20282a5c12eSMatthew Dillon BULLET *bp;
20382a5c12eSMatthew Dillon
20482a5c12eSMatthew Dillon y = pp->p_y;
20582a5c12eSMatthew Dillon x = pp->p_x;
20682a5c12eSMatthew Dillon
20782a5c12eSMatthew Dillon switch (dir) {
20882a5c12eSMatthew Dillon case LEFTS:
20982a5c12eSMatthew Dillon x--;
21082a5c12eSMatthew Dillon break;
21182a5c12eSMatthew Dillon case RIGHT:
21282a5c12eSMatthew Dillon x++;
21382a5c12eSMatthew Dillon break;
21482a5c12eSMatthew Dillon case ABOVE:
21582a5c12eSMatthew Dillon y--;
21682a5c12eSMatthew Dillon break;
21782a5c12eSMatthew Dillon case BELOW:
21882a5c12eSMatthew Dillon y++;
21982a5c12eSMatthew Dillon break;
22082a5c12eSMatthew Dillon }
22182a5c12eSMatthew Dillon
22282a5c12eSMatthew Dillon moved = FALSE;
22382a5c12eSMatthew Dillon
22482a5c12eSMatthew Dillon /* What would the player move over: */
22582a5c12eSMatthew Dillon switch (Maze[y][x]) {
22682a5c12eSMatthew Dillon /* Players can move through spaces and doors, no problem: */
22782a5c12eSMatthew Dillon case SPACE:
22882a5c12eSMatthew Dillon case DOOR:
22982a5c12eSMatthew Dillon moved = TRUE;
23082a5c12eSMatthew Dillon break;
23182a5c12eSMatthew Dillon /* Can't move through walls: */
23282a5c12eSMatthew Dillon case WALL1:
23382a5c12eSMatthew Dillon case WALL2:
23482a5c12eSMatthew Dillon case WALL3:
23582a5c12eSMatthew Dillon case WALL4:
23682a5c12eSMatthew Dillon case WALL5:
23782a5c12eSMatthew Dillon break;
23882a5c12eSMatthew Dillon /* Moving over a mine - try to pick it up: */
23982a5c12eSMatthew Dillon case MINE:
24082a5c12eSMatthew Dillon case GMINE:
24182a5c12eSMatthew Dillon if (dir == pp->p_face)
24282a5c12eSMatthew Dillon /* facing it: 2% chance of trip */
24382a5c12eSMatthew Dillon pickup(pp, y, x, conf_ptrip_face, Maze[y][x]);
24482a5c12eSMatthew Dillon else if (opposite(dir, pp->p_face))
24582a5c12eSMatthew Dillon /* facing away: 95% chance of trip */
24682a5c12eSMatthew Dillon pickup(pp, y, x, conf_ptrip_back, Maze[y][x]);
24782a5c12eSMatthew Dillon else
24882a5c12eSMatthew Dillon /* facing sideways: 50% chance of trip */
24982a5c12eSMatthew Dillon pickup(pp, y, x, conf_ptrip_side, Maze[y][x]);
25082a5c12eSMatthew Dillon /* Remove the mine: */
25182a5c12eSMatthew Dillon Maze[y][x] = SPACE;
25282a5c12eSMatthew Dillon moved = TRUE;
25382a5c12eSMatthew Dillon break;
25482a5c12eSMatthew Dillon /* Moving into a bullet: */
25582a5c12eSMatthew Dillon case SHOT:
25682a5c12eSMatthew Dillon case GRENADE:
25782a5c12eSMatthew Dillon case SATCHEL:
25882a5c12eSMatthew Dillon case BOMB:
25982a5c12eSMatthew Dillon case SLIME:
26082a5c12eSMatthew Dillon case DSHOT:
26182a5c12eSMatthew Dillon /* Find which bullet: */
26282a5c12eSMatthew Dillon bp = is_bullet(y, x);
26382a5c12eSMatthew Dillon if (bp != NULL)
26482a5c12eSMatthew Dillon /* Detonate it: */
26582a5c12eSMatthew Dillon bp->b_expl = TRUE;
26682a5c12eSMatthew Dillon /* Remove it: */
26782a5c12eSMatthew Dillon Maze[y][x] = SPACE;
26882a5c12eSMatthew Dillon moved = TRUE;
26982a5c12eSMatthew Dillon break;
27082a5c12eSMatthew Dillon /* Moving into another player: */
27182a5c12eSMatthew Dillon case LEFTS:
27282a5c12eSMatthew Dillon case RIGHT:
27382a5c12eSMatthew Dillon case ABOVE:
27482a5c12eSMatthew Dillon case BELOW:
27582a5c12eSMatthew Dillon if (dir != pp->p_face)
27682a5c12eSMatthew Dillon /* Can't walk backwards/sideways into another player: */
27782a5c12eSMatthew Dillon sendcom(pp, BELL);
27882a5c12eSMatthew Dillon else {
27982a5c12eSMatthew Dillon /* Stab the other player */
28082a5c12eSMatthew Dillon newp = play_at(y, x);
28182a5c12eSMatthew Dillon checkdam(newp, pp, pp->p_ident, conf_stabdam, KNIFE);
28282a5c12eSMatthew Dillon }
28382a5c12eSMatthew Dillon break;
28482a5c12eSMatthew Dillon /* Moving into a player flying overhead: */
28582a5c12eSMatthew Dillon case FLYER:
28682a5c12eSMatthew Dillon newp = play_at(y, x);
28782a5c12eSMatthew Dillon message(newp, "Oooh, there's a short guy waving at you!");
28882a5c12eSMatthew Dillon message(pp, "You couldn't quite reach him!");
28982a5c12eSMatthew Dillon break;
29082a5c12eSMatthew Dillon /* Picking up a boot, or two: */
29182a5c12eSMatthew Dillon case BOOT_PAIR:
29282a5c12eSMatthew Dillon pp->p_nboots++;
293*13fca3dfSzrj /* FALLTHROUGH */
29482a5c12eSMatthew Dillon case BOOT:
29582a5c12eSMatthew Dillon pp->p_nboots++;
29682a5c12eSMatthew Dillon for (newp = Boot; newp < &Boot[NBOOTS]; newp++) {
29782a5c12eSMatthew Dillon if (newp->p_flying < 0)
29882a5c12eSMatthew Dillon continue;
29982a5c12eSMatthew Dillon if (newp->p_y == y && newp->p_x == x) {
30082a5c12eSMatthew Dillon newp->p_flying = -1;
30182a5c12eSMatthew Dillon if (newp->p_undershot)
30282a5c12eSMatthew Dillon fixshots(y, x, newp->p_over);
30382a5c12eSMatthew Dillon }
30482a5c12eSMatthew Dillon }
30582a5c12eSMatthew Dillon if (pp->p_nboots == 2)
30682a5c12eSMatthew Dillon message(pp, "Wow! A pair of boots!");
30782a5c12eSMatthew Dillon else
30882a5c12eSMatthew Dillon message(pp, "You can hobble around on one boot.");
30982a5c12eSMatthew Dillon Maze[y][x] = SPACE;
31082a5c12eSMatthew Dillon moved = TRUE;
31182a5c12eSMatthew Dillon break;
31282a5c12eSMatthew Dillon }
31382a5c12eSMatthew Dillon
31482a5c12eSMatthew Dillon /* Can the player be moved? */
31582a5c12eSMatthew Dillon if (moved) {
31682a5c12eSMatthew Dillon /* Check the gun status: */
31782a5c12eSMatthew Dillon if (pp->p_ncshot > 0)
31882a5c12eSMatthew Dillon if (--pp->p_ncshot == conf_maxncshot)
31982a5c12eSMatthew Dillon outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ok");
32082a5c12eSMatthew Dillon /* Check for bullets flying past: */
32182a5c12eSMatthew Dillon if (pp->p_undershot) {
32282a5c12eSMatthew Dillon fixshots(pp->p_y, pp->p_x, pp->p_over);
32382a5c12eSMatthew Dillon pp->p_undershot = FALSE;
32482a5c12eSMatthew Dillon }
32582a5c12eSMatthew Dillon /* Erase the player: */
32682a5c12eSMatthew Dillon drawplayer(pp, FALSE);
32782a5c12eSMatthew Dillon /* Save under: */
32882a5c12eSMatthew Dillon pp->p_over = Maze[y][x];
32982a5c12eSMatthew Dillon /* Move the player: */
33082a5c12eSMatthew Dillon pp->p_y = y;
33182a5c12eSMatthew Dillon pp->p_x = x;
33282a5c12eSMatthew Dillon /* Draw the player in their new position */
33382a5c12eSMatthew Dillon drawplayer(pp, TRUE);
33482a5c12eSMatthew Dillon }
33582a5c12eSMatthew Dillon }
33682a5c12eSMatthew Dillon
33782a5c12eSMatthew Dillon /*
33882a5c12eSMatthew Dillon * face:
33982a5c12eSMatthew Dillon * Change the direction the player is facing
34082a5c12eSMatthew Dillon */
34182a5c12eSMatthew Dillon static void
face(PLAYER * pp,int dir)3426beb426bSSascha Wildner face(PLAYER *pp, int dir)
34382a5c12eSMatthew Dillon {
34482a5c12eSMatthew Dillon if (pp->p_face != dir) {
34582a5c12eSMatthew Dillon pp->p_face = dir;
34682a5c12eSMatthew Dillon drawplayer(pp, TRUE);
34782a5c12eSMatthew Dillon }
34882a5c12eSMatthew Dillon }
34982a5c12eSMatthew Dillon
35082a5c12eSMatthew Dillon /*
35182a5c12eSMatthew Dillon * fire:
35282a5c12eSMatthew Dillon * Fire a shot of the given type in the given direction
35382a5c12eSMatthew Dillon */
35482a5c12eSMatthew Dillon static void
fire(PLAYER * pp,int req_index)3556beb426bSSascha Wildner fire(PLAYER *pp, int req_index)
35682a5c12eSMatthew Dillon {
35782a5c12eSMatthew Dillon if (pp == NULL)
35882a5c12eSMatthew Dillon return;
35982a5c12eSMatthew Dillon
36082a5c12eSMatthew Dillon /* Drop the shot type down until we can afford it: */
36182a5c12eSMatthew Dillon while (req_index >= 0 && pp->p_ammo < shot_req[req_index])
36282a5c12eSMatthew Dillon req_index--;
36382a5c12eSMatthew Dillon
36482a5c12eSMatthew Dillon /* Can we shoot at all? */
36582a5c12eSMatthew Dillon if (req_index < 0) {
36682a5c12eSMatthew Dillon message(pp, "Not enough charges.");
36782a5c12eSMatthew Dillon return;
36882a5c12eSMatthew Dillon }
36982a5c12eSMatthew Dillon
37082a5c12eSMatthew Dillon /* Check if the gun is too hot: */
37182a5c12eSMatthew Dillon if (pp->p_ncshot > conf_maxncshot)
37282a5c12eSMatthew Dillon return;
37382a5c12eSMatthew Dillon
37482a5c12eSMatthew Dillon /* Heat up the gun: */
37582a5c12eSMatthew Dillon if (pp->p_ncshot++ == conf_maxncshot) {
37682a5c12eSMatthew Dillon /* The gun has overheated: */
37782a5c12eSMatthew Dillon outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ");
37882a5c12eSMatthew Dillon }
37982a5c12eSMatthew Dillon
38082a5c12eSMatthew Dillon /* Use up some ammo: */
38182a5c12eSMatthew Dillon pp->p_ammo -= shot_req[req_index];
38282a5c12eSMatthew Dillon ammo_update(pp);
38382a5c12eSMatthew Dillon
38482a5c12eSMatthew Dillon /* Start the bullet moving: */
38582a5c12eSMatthew Dillon add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face,
38682a5c12eSMatthew Dillon shot_req[req_index], pp, FALSE, pp->p_face);
38782a5c12eSMatthew Dillon pp->p_undershot = TRUE;
38882a5c12eSMatthew Dillon
38982a5c12eSMatthew Dillon /* Show the bullet to everyone: */
39082a5c12eSMatthew Dillon showexpl(pp->p_y, pp->p_x, shot_type[req_index]);
39182a5c12eSMatthew Dillon sendcom(ALL_PLAYERS, REFRESH);
39282a5c12eSMatthew Dillon }
39382a5c12eSMatthew Dillon
39482a5c12eSMatthew Dillon /*
39582a5c12eSMatthew Dillon * fire_slime:
39682a5c12eSMatthew Dillon * Fire a slime shot in the given direction
39782a5c12eSMatthew Dillon */
39882a5c12eSMatthew Dillon static void
fire_slime(PLAYER * pp,int req_index)3996beb426bSSascha Wildner fire_slime(PLAYER *pp, int req_index)
40082a5c12eSMatthew Dillon {
40182a5c12eSMatthew Dillon if (pp == NULL)
40282a5c12eSMatthew Dillon return;
40382a5c12eSMatthew Dillon
40482a5c12eSMatthew Dillon /* Check configuration: */
40582a5c12eSMatthew Dillon if (!conf_ooze)
40682a5c12eSMatthew Dillon return;
40782a5c12eSMatthew Dillon
40882a5c12eSMatthew Dillon /* Drop the slime type back util we can afford it: */
40982a5c12eSMatthew Dillon while (req_index >= 0 && pp->p_ammo < slime_req[req_index])
41082a5c12eSMatthew Dillon req_index--;
41182a5c12eSMatthew Dillon
41282a5c12eSMatthew Dillon /* Can we afford to slime at all? */
41382a5c12eSMatthew Dillon if (req_index < 0) {
41482a5c12eSMatthew Dillon message(pp, "Not enough charges.");
41582a5c12eSMatthew Dillon return;
41682a5c12eSMatthew Dillon }
41782a5c12eSMatthew Dillon
41882a5c12eSMatthew Dillon /* Is the gun too hot? */
41982a5c12eSMatthew Dillon if (pp->p_ncshot > conf_maxncshot)
42082a5c12eSMatthew Dillon return;
42182a5c12eSMatthew Dillon
42282a5c12eSMatthew Dillon /* Heat up the gun: */
42382a5c12eSMatthew Dillon if (pp->p_ncshot++ == conf_maxncshot) {
42482a5c12eSMatthew Dillon /* The gun has overheated: */
42582a5c12eSMatthew Dillon outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ");
42682a5c12eSMatthew Dillon }
42782a5c12eSMatthew Dillon
42882a5c12eSMatthew Dillon /* Use up some ammo: */
42982a5c12eSMatthew Dillon pp->p_ammo -= slime_req[req_index];
43082a5c12eSMatthew Dillon ammo_update(pp);
43182a5c12eSMatthew Dillon
43282a5c12eSMatthew Dillon /* Start the slime moving: */
43382a5c12eSMatthew Dillon add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face,
43482a5c12eSMatthew Dillon slime_req[req_index] * conf_slimefactor, pp, FALSE, pp->p_face);
43582a5c12eSMatthew Dillon pp->p_undershot = TRUE;
43682a5c12eSMatthew Dillon
43782a5c12eSMatthew Dillon /* Show the object to everyone: */
43882a5c12eSMatthew Dillon showexpl(pp->p_y, pp->p_x, SLIME);
43982a5c12eSMatthew Dillon sendcom(ALL_PLAYERS, REFRESH);
44082a5c12eSMatthew Dillon }
44182a5c12eSMatthew Dillon
44282a5c12eSMatthew Dillon /*
44382a5c12eSMatthew Dillon * add_shot:
44482a5c12eSMatthew Dillon * Create a shot with the given properties
44582a5c12eSMatthew Dillon */
44682a5c12eSMatthew Dillon void
add_shot(int type,int y,int x,char wface,int charge,PLAYER * owner,int expl,char over)4476beb426bSSascha Wildner add_shot(int type, int y, int x, char wface, int charge, PLAYER *owner,
4486beb426bSSascha Wildner int expl, char over)
44982a5c12eSMatthew Dillon {
45082a5c12eSMatthew Dillon BULLET *bp;
45182a5c12eSMatthew Dillon int size;
45282a5c12eSMatthew Dillon
45382a5c12eSMatthew Dillon /* Determine the bullet's size based on its type and charge: */
45482a5c12eSMatthew Dillon switch (type) {
45582a5c12eSMatthew Dillon case SHOT:
45682a5c12eSMatthew Dillon case MINE:
45782a5c12eSMatthew Dillon size = 1;
45882a5c12eSMatthew Dillon break;
45982a5c12eSMatthew Dillon case GRENADE:
46082a5c12eSMatthew Dillon case GMINE:
46182a5c12eSMatthew Dillon size = 2;
46282a5c12eSMatthew Dillon break;
46382a5c12eSMatthew Dillon case SATCHEL:
46482a5c12eSMatthew Dillon size = 3;
46582a5c12eSMatthew Dillon break;
46682a5c12eSMatthew Dillon case BOMB:
46782a5c12eSMatthew Dillon for (size = 3; size < MAXBOMB; size++)
46882a5c12eSMatthew Dillon if (shot_req[size] >= charge)
46982a5c12eSMatthew Dillon break;
47082a5c12eSMatthew Dillon size++;
47182a5c12eSMatthew Dillon break;
47282a5c12eSMatthew Dillon default:
47382a5c12eSMatthew Dillon size = 0;
47482a5c12eSMatthew Dillon break;
47582a5c12eSMatthew Dillon }
47682a5c12eSMatthew Dillon
47782a5c12eSMatthew Dillon /* Create the bullet: */
47882a5c12eSMatthew Dillon bp = create_shot(type, y, x, wface, charge, size, owner,
47982a5c12eSMatthew Dillon (owner == NULL) ? NULL : owner->p_ident, expl, over);
48082a5c12eSMatthew Dillon
48182a5c12eSMatthew Dillon /* Insert the bullet into the front of the bullet list: */
48282a5c12eSMatthew Dillon bp->b_next = Bullets;
48382a5c12eSMatthew Dillon Bullets = bp;
48482a5c12eSMatthew Dillon }
48582a5c12eSMatthew Dillon
48682a5c12eSMatthew Dillon /*
48782a5c12eSMatthew Dillon * create_shot:
48882a5c12eSMatthew Dillon * allocate storage for an (unlinked) bullet structure;
48982a5c12eSMatthew Dillon * initialize and return it
49082a5c12eSMatthew Dillon */
49182a5c12eSMatthew Dillon BULLET *
create_shot(int type,int y,int x,char wface,int charge,int size,PLAYER * owner,IDENT * score,int expl,char over)4926beb426bSSascha Wildner create_shot(int type, int y, int x, char wface, int charge, int size,
4936beb426bSSascha Wildner PLAYER *owner, IDENT *score, int expl, char over)
49482a5c12eSMatthew Dillon {
49582a5c12eSMatthew Dillon BULLET *bp;
49682a5c12eSMatthew Dillon
49782a5c12eSMatthew Dillon bp = (BULLET *) malloc(sizeof (BULLET)); /* NOSTRICT */
49882a5c12eSMatthew Dillon if (bp == NULL) {
49982a5c12eSMatthew Dillon logit(LOG_ERR, "malloc");
50082a5c12eSMatthew Dillon if (owner != NULL)
50182a5c12eSMatthew Dillon message(owner, "Out of memory");
50282a5c12eSMatthew Dillon return NULL;
50382a5c12eSMatthew Dillon }
50482a5c12eSMatthew Dillon
50582a5c12eSMatthew Dillon bp->b_face = wface;
50682a5c12eSMatthew Dillon bp->b_x = x;
50782a5c12eSMatthew Dillon bp->b_y = y;
50882a5c12eSMatthew Dillon bp->b_charge = charge;
50982a5c12eSMatthew Dillon bp->b_owner = owner;
51082a5c12eSMatthew Dillon bp->b_score = score;
51182a5c12eSMatthew Dillon bp->b_type = type;
51282a5c12eSMatthew Dillon bp->b_size = size;
51382a5c12eSMatthew Dillon bp->b_expl = expl;
51482a5c12eSMatthew Dillon bp->b_over = over;
51582a5c12eSMatthew Dillon bp->b_next = NULL;
51682a5c12eSMatthew Dillon
51782a5c12eSMatthew Dillon return bp;
51882a5c12eSMatthew Dillon }
51982a5c12eSMatthew Dillon
52082a5c12eSMatthew Dillon /*
52182a5c12eSMatthew Dillon * cloak:
52282a5c12eSMatthew Dillon * Turn on or increase length of a cloak
52382a5c12eSMatthew Dillon */
52482a5c12eSMatthew Dillon static void
cloak(PLAYER * pp)5256beb426bSSascha Wildner cloak(PLAYER *pp)
52682a5c12eSMatthew Dillon {
52782a5c12eSMatthew Dillon /* Check configuration: */
52882a5c12eSMatthew Dillon if (!conf_cloak)
52982a5c12eSMatthew Dillon return;
53082a5c12eSMatthew Dillon
53182a5c12eSMatthew Dillon /* Can we afford it?: */
53282a5c12eSMatthew Dillon if (pp->p_ammo <= 0) {
53382a5c12eSMatthew Dillon message(pp, "No more charges");
53482a5c12eSMatthew Dillon return;
53582a5c12eSMatthew Dillon }
53682a5c12eSMatthew Dillon
53782a5c12eSMatthew Dillon /* Can't cloak with boots: */
53882a5c12eSMatthew Dillon if (pp->p_nboots > 0) {
53982a5c12eSMatthew Dillon message(pp, "Boots are too noisy to cloak!");
54082a5c12eSMatthew Dillon return;
54182a5c12eSMatthew Dillon }
54282a5c12eSMatthew Dillon
54382a5c12eSMatthew Dillon /* Consume a unit of ammo: */
54482a5c12eSMatthew Dillon pp->p_ammo--;
54582a5c12eSMatthew Dillon ammo_update(pp);
54682a5c12eSMatthew Dillon
54782a5c12eSMatthew Dillon /* Add to the duration of a cloak: */
54882a5c12eSMatthew Dillon pp->p_cloak += conf_cloaklen;
54982a5c12eSMatthew Dillon
55082a5c12eSMatthew Dillon /* Disable scan, if enabled: */
55182a5c12eSMatthew Dillon if (pp->p_scan >= 0)
55282a5c12eSMatthew Dillon pp->p_scan = -1;
55382a5c12eSMatthew Dillon
55482a5c12eSMatthew Dillon /* Re-draw the player's scan/cloak status: */
55582a5c12eSMatthew Dillon showstat(pp);
55682a5c12eSMatthew Dillon }
55782a5c12eSMatthew Dillon
55882a5c12eSMatthew Dillon /*
55982a5c12eSMatthew Dillon * scan:
56082a5c12eSMatthew Dillon * Turn on or increase length of a scan
56182a5c12eSMatthew Dillon */
56282a5c12eSMatthew Dillon static void
scan(PLAYER * pp)5636beb426bSSascha Wildner scan(PLAYER *pp)
56482a5c12eSMatthew Dillon {
56582a5c12eSMatthew Dillon /* Check configuration: */
56682a5c12eSMatthew Dillon if (!conf_scan)
56782a5c12eSMatthew Dillon return;
56882a5c12eSMatthew Dillon
56982a5c12eSMatthew Dillon /* Can we afford it?: */
57082a5c12eSMatthew Dillon if (pp->p_ammo <= 0) {
57182a5c12eSMatthew Dillon message(pp, "No more charges");
57282a5c12eSMatthew Dillon return;
57382a5c12eSMatthew Dillon }
57482a5c12eSMatthew Dillon
57582a5c12eSMatthew Dillon /* Consume one unit of ammo: */
57682a5c12eSMatthew Dillon pp->p_ammo--;
57782a5c12eSMatthew Dillon ammo_update(pp);
57882a5c12eSMatthew Dillon
57982a5c12eSMatthew Dillon /* Increase the scan time: */
58082a5c12eSMatthew Dillon pp->p_scan += Nplayer * conf_scanlen;
58182a5c12eSMatthew Dillon
58282a5c12eSMatthew Dillon /* Disable cloak, if enabled: */
58382a5c12eSMatthew Dillon if (pp->p_cloak >= 0)
58482a5c12eSMatthew Dillon pp->p_cloak = -1;
58582a5c12eSMatthew Dillon
58682a5c12eSMatthew Dillon /* Re-draw the player's scan/cloak status: */
58782a5c12eSMatthew Dillon showstat(pp);
58882a5c12eSMatthew Dillon }
58982a5c12eSMatthew Dillon
59082a5c12eSMatthew Dillon /*
59182a5c12eSMatthew Dillon * pickup:
59282a5c12eSMatthew Dillon * pick up a mine or grenade, with some probability of it exploding
59382a5c12eSMatthew Dillon */
59482a5c12eSMatthew Dillon static void
pickup(PLAYER * pp,int y,int x,int prob,int obj)5956beb426bSSascha Wildner pickup(PLAYER *pp, int y, int x, int prob, int obj)
59682a5c12eSMatthew Dillon {
59782a5c12eSMatthew Dillon int req;
59882a5c12eSMatthew Dillon
59982a5c12eSMatthew Dillon /* Figure out how much ammo the player is trying to pick up: */
60082a5c12eSMatthew Dillon switch (obj) {
60182a5c12eSMatthew Dillon case MINE:
60282a5c12eSMatthew Dillon req = BULREQ;
60382a5c12eSMatthew Dillon break;
60482a5c12eSMatthew Dillon case GMINE:
60582a5c12eSMatthew Dillon req = GRENREQ;
60682a5c12eSMatthew Dillon break;
60782a5c12eSMatthew Dillon default:
60882a5c12eSMatthew Dillon #ifdef DIAGNOSTIC
60982a5c12eSMatthew Dillon abort();
61082a5c12eSMatthew Dillon #endif
61182a5c12eSMatthew Dillon return;
61282a5c12eSMatthew Dillon }
61382a5c12eSMatthew Dillon
61482a5c12eSMatthew Dillon /* Does it explode? */
61582a5c12eSMatthew Dillon if (rand_num(100) < prob)
61682a5c12eSMatthew Dillon /* Ooooh, unlucky: (Boom) */
6172038fb68SSascha Wildner add_shot(obj, y, x, LEFTS, req, NULL, TRUE, pp->p_face);
61882a5c12eSMatthew Dillon else {
61982a5c12eSMatthew Dillon /* Safely picked it up. Add to player's ammo: */
62082a5c12eSMatthew Dillon pp->p_ammo += req;
62182a5c12eSMatthew Dillon ammo_update(pp);
62282a5c12eSMatthew Dillon }
62382a5c12eSMatthew Dillon }
62482a5c12eSMatthew Dillon
62582a5c12eSMatthew Dillon void
ammo_update(PLAYER * pp)6266beb426bSSascha Wildner ammo_update(PLAYER *pp)
62782a5c12eSMatthew Dillon {
62882a5c12eSMatthew Dillon outyx(pp, STAT_AMMO_ROW, STAT_VALUE_COL - 1, "%4d", pp->p_ammo);
62982a5c12eSMatthew Dillon }
630