578 lines
11 KiB
C
578 lines
11 KiB
C
/* $NetBSD: execute.c,v 1.9 2009/07/04 04:29:54 dholland Exp $ */
|
|
/*
|
|
* Copyright (c) 1983-2003, Regents of the University of California.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* + Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* + Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* + Neither the name of the University of California, San Francisco nor
|
|
* the names of its contributors may be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/cdefs.h>
|
|
#ifndef lint
|
|
__RCSID("$NetBSD: execute.c,v 1.9 2009/07/04 04:29:54 dholland Exp $");
|
|
#endif /* not lint */
|
|
|
|
#include <stdlib.h>
|
|
#include "hunt.h"
|
|
|
|
static void cloak(PLAYER *);
|
|
static void turn_player(PLAYER *, int);
|
|
static void fire(PLAYER *, int);
|
|
static void fire_slime(PLAYER *, int);
|
|
static void move_player(PLAYER *, int);
|
|
static void pickup(PLAYER *, int, int, int, int);
|
|
static void scan(PLAYER *);
|
|
|
|
|
|
#ifdef MONITOR
|
|
/*
|
|
* mon_execute:
|
|
* Execute a single monitor command
|
|
*/
|
|
void
|
|
mon_execute(PLAYER *pp)
|
|
{
|
|
char ch;
|
|
|
|
ch = pp->p_cbuf[pp->p_ncount++];
|
|
switch (ch) {
|
|
case CTRL('L'):
|
|
sendcom(pp, REDRAW);
|
|
break;
|
|
case 'q':
|
|
(void) strcpy(pp->p_death, "| Quit |");
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* execute:
|
|
* Execute a single command
|
|
*/
|
|
void
|
|
execute(PLAYER *pp)
|
|
{
|
|
char ch;
|
|
|
|
ch = pp->p_cbuf[pp->p_ncount++];
|
|
|
|
#ifdef FLY
|
|
if (pp->p_flying >= 0) {
|
|
switch (ch) {
|
|
case CTRL('L'):
|
|
sendcom(pp, REDRAW);
|
|
break;
|
|
case 'q':
|
|
(void) strcpy(pp->p_death, "| Quit |");
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
switch (ch) {
|
|
case CTRL('L'):
|
|
sendcom(pp, REDRAW);
|
|
break;
|
|
case 'h':
|
|
move_player(pp, LEFTS);
|
|
break;
|
|
case 'H':
|
|
turn_player(pp, LEFTS);
|
|
break;
|
|
case 'j':
|
|
move_player(pp, BELOW);
|
|
break;
|
|
case 'J':
|
|
turn_player(pp, BELOW);
|
|
break;
|
|
case 'k':
|
|
move_player(pp, ABOVE);
|
|
break;
|
|
case 'K':
|
|
turn_player(pp, ABOVE);
|
|
break;
|
|
case 'l':
|
|
move_player(pp, RIGHT);
|
|
break;
|
|
case 'L':
|
|
turn_player(pp, RIGHT);
|
|
break;
|
|
case 'f':
|
|
case '1':
|
|
fire(pp, 0); /* SHOT */
|
|
break;
|
|
case 'g':
|
|
case '2':
|
|
fire(pp, 1); /* GRENADE */
|
|
break;
|
|
case 'F':
|
|
case '3':
|
|
fire(pp, 2); /* SATCHEL */
|
|
break;
|
|
case 'G':
|
|
case '4':
|
|
fire(pp, 3); /* 7x7 BOMB */
|
|
break;
|
|
case '5':
|
|
fire(pp, 4); /* 9x9 BOMB */
|
|
break;
|
|
case '6':
|
|
fire(pp, 5); /* 11x11 BOMB */
|
|
break;
|
|
case '7':
|
|
fire(pp, 6); /* 13x13 BOMB */
|
|
break;
|
|
case '8':
|
|
fire(pp, 7); /* 15x15 BOMB */
|
|
break;
|
|
case '9':
|
|
fire(pp, 8); /* 17x17 BOMB */
|
|
break;
|
|
case '0':
|
|
fire(pp, 9); /* 19x19 BOMB */
|
|
break;
|
|
case '@':
|
|
fire(pp, 10); /* 21x21 BOMB */
|
|
break;
|
|
#ifdef OOZE
|
|
case 'o':
|
|
fire_slime(pp, 0); /* SLIME */
|
|
break;
|
|
case 'O':
|
|
fire_slime(pp, 1); /* SSLIME */
|
|
break;
|
|
case 'p':
|
|
fire_slime(pp, 2);
|
|
break;
|
|
case 'P':
|
|
fire_slime(pp, 3);
|
|
break;
|
|
#endif
|
|
case 's':
|
|
scan(pp);
|
|
break;
|
|
case 'c':
|
|
cloak(pp);
|
|
break;
|
|
case 'q':
|
|
(void) strcpy(pp->p_death, "| Quit |");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* move_player:
|
|
* Execute a move in the given direction
|
|
*/
|
|
static void
|
|
move_player(PLAYER *pp, int dir)
|
|
{
|
|
PLAYER *newp;
|
|
int x, y;
|
|
FLAG moved;
|
|
BULLET *bp;
|
|
|
|
y = pp->p_y;
|
|
x = pp->p_x;
|
|
|
|
switch (dir) {
|
|
case LEFTS:
|
|
x--;
|
|
break;
|
|
case RIGHT:
|
|
x++;
|
|
break;
|
|
case ABOVE:
|
|
y--;
|
|
break;
|
|
case BELOW:
|
|
y++;
|
|
break;
|
|
}
|
|
|
|
moved = FALSE;
|
|
switch (Maze[y][x]) {
|
|
case SPACE:
|
|
#ifdef RANDOM
|
|
case DOOR:
|
|
#endif
|
|
moved = TRUE;
|
|
break;
|
|
case WALL1:
|
|
case WALL2:
|
|
case WALL3:
|
|
#ifdef REFLECT
|
|
case WALL4:
|
|
case WALL5:
|
|
#endif
|
|
break;
|
|
case MINE:
|
|
case GMINE:
|
|
if (dir == pp->p_face)
|
|
pickup(pp, y, x, 2, Maze[y][x]);
|
|
else if (opposite(dir, pp->p_face))
|
|
pickup(pp, y, x, 95, Maze[y][x]);
|
|
else
|
|
pickup(pp, y, x, 50, Maze[y][x]);
|
|
Maze[y][x] = SPACE;
|
|
moved = TRUE;
|
|
break;
|
|
case SHOT:
|
|
case GRENADE:
|
|
case SATCHEL:
|
|
case BOMB:
|
|
#ifdef OOZE
|
|
case SLIME:
|
|
#endif
|
|
#ifdef DRONE
|
|
case DSHOT:
|
|
#endif
|
|
bp = is_bullet(y, x);
|
|
if (bp != NULL)
|
|
bp->b_expl = TRUE;
|
|
Maze[y][x] = SPACE;
|
|
moved = TRUE;
|
|
break;
|
|
case LEFTS:
|
|
case RIGHT:
|
|
case ABOVE:
|
|
case BELOW:
|
|
if (dir != pp->p_face)
|
|
sendcom(pp, BELL);
|
|
else {
|
|
newp = play_at(y, x);
|
|
checkdam(newp, pp, pp->p_ident, STABDAM, KNIFE);
|
|
}
|
|
break;
|
|
#ifdef FLY
|
|
case FLYER:
|
|
newp = play_at(y, x);
|
|
message(newp, "Oooh, there's a short guy waving at you!");
|
|
message(pp, "You couldn't quite reach him!");
|
|
break;
|
|
#endif
|
|
#ifdef BOOTS
|
|
case BOOT:
|
|
case BOOT_PAIR:
|
|
if (Maze[y][x] == BOOT)
|
|
pp->p_nboots++;
|
|
else
|
|
pp->p_nboots += 2;
|
|
for (newp = Boot; newp < &Boot[NBOOTS]; newp++) {
|
|
if (newp->p_flying < 0)
|
|
continue;
|
|
if (newp->p_y == y && newp->p_x == x) {
|
|
newp->p_flying = -1;
|
|
if (newp->p_undershot)
|
|
fixshots(y, x, newp->p_over);
|
|
}
|
|
}
|
|
if (pp->p_nboots == 2)
|
|
message(pp, "Wow! A pair of boots!");
|
|
else
|
|
message(pp, "You can hobble around on one boot.");
|
|
Maze[y][x] = SPACE;
|
|
moved = TRUE;
|
|
break;
|
|
#endif
|
|
}
|
|
if (moved) {
|
|
if (pp->p_ncshot > 0)
|
|
if (--pp->p_ncshot == MAXNCSHOT) {
|
|
cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
|
|
outstr(pp, " ok", 3);
|
|
}
|
|
if (pp->p_undershot) {
|
|
fixshots(pp->p_y, pp->p_x, pp->p_over);
|
|
pp->p_undershot = FALSE;
|
|
}
|
|
drawplayer(pp, FALSE);
|
|
pp->p_over = Maze[y][x];
|
|
pp->p_y = y;
|
|
pp->p_x = x;
|
|
drawplayer(pp, TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* turn_player:
|
|
* Change the direction the player is facing
|
|
*/
|
|
static void
|
|
turn_player(PLAYER *pp, int dir)
|
|
{
|
|
if (pp->p_face != dir) {
|
|
pp->p_face = dir;
|
|
drawplayer(pp, TRUE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* fire:
|
|
* Fire a shot of the given type in the given direction
|
|
*/
|
|
static void
|
|
fire(PLAYER *pp, int req_index)
|
|
{
|
|
if (pp == NULL)
|
|
return;
|
|
#ifdef DEBUG
|
|
if (req_index < 0 || req_index >= MAXBOMB)
|
|
message(pp, "What you do?");
|
|
#endif
|
|
while (req_index >= 0 && pp->p_ammo < shot_req[req_index])
|
|
req_index--;
|
|
if (req_index < 0) {
|
|
message(pp, "Not enough charges.");
|
|
return;
|
|
}
|
|
if (pp->p_ncshot > MAXNCSHOT)
|
|
return;
|
|
if (pp->p_ncshot++ == MAXNCSHOT) {
|
|
cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
|
|
outstr(pp, " ", 3);
|
|
}
|
|
pp->p_ammo -= shot_req[req_index];
|
|
(void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo);
|
|
cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
|
|
outstr(pp, Buf, 3);
|
|
|
|
add_shot(shot_type[req_index], pp->p_y, pp->p_x, pp->p_face,
|
|
shot_req[req_index], pp, FALSE, pp->p_face);
|
|
pp->p_undershot = TRUE;
|
|
|
|
/*
|
|
* Show the object to everyone
|
|
*/
|
|
showexpl(pp->p_y, pp->p_x, shot_type[req_index]);
|
|
for (pp = Player; pp < End_player; pp++)
|
|
sendcom(pp, REFRESH);
|
|
#ifdef MONITOR
|
|
for (pp = Monitor; pp < End_monitor; pp++)
|
|
sendcom(pp, REFRESH);
|
|
#endif
|
|
}
|
|
|
|
#ifdef OOZE
|
|
/*
|
|
* fire_slime:
|
|
* Fire a slime shot in the given direction
|
|
*/
|
|
static void
|
|
fire_slime(PLAYER *pp, int req_index)
|
|
{
|
|
if (pp == NULL)
|
|
return;
|
|
#ifdef DEBUG
|
|
if (req_index < 0 || req_index >= MAXSLIME)
|
|
message(pp, "What you do?");
|
|
#endif
|
|
while (req_index >= 0 && pp->p_ammo < slime_req[req_index])
|
|
req_index--;
|
|
if (req_index < 0) {
|
|
message(pp, "Not enough charges.");
|
|
return;
|
|
}
|
|
if (pp->p_ncshot > MAXNCSHOT)
|
|
return;
|
|
if (pp->p_ncshot++ == MAXNCSHOT) {
|
|
cgoto(pp, STAT_GUN_ROW, STAT_VALUE_COL);
|
|
outstr(pp, " ", 3);
|
|
}
|
|
pp->p_ammo -= slime_req[req_index];
|
|
(void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo);
|
|
cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
|
|
outstr(pp, Buf, 3);
|
|
|
|
add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face,
|
|
slime_req[req_index] * SLIME_FACTOR, pp, FALSE, pp->p_face);
|
|
pp->p_undershot = TRUE;
|
|
|
|
/*
|
|
* Show the object to everyone
|
|
*/
|
|
showexpl(pp->p_y, pp->p_x, SLIME);
|
|
for (pp = Player; pp < End_player; pp++)
|
|
sendcom(pp, REFRESH);
|
|
#ifdef MONITOR
|
|
for (pp = Monitor; pp < End_monitor; pp++)
|
|
sendcom(pp, REFRESH);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* add_shot:
|
|
* Create a shot with the given properties
|
|
*/
|
|
void
|
|
add_shot(int type, int y, int x, char face, int charge,
|
|
PLAYER *owner, int expl, char over)
|
|
{
|
|
BULLET *bp;
|
|
int size;
|
|
|
|
switch (type) {
|
|
case SHOT:
|
|
case MINE:
|
|
size = 1;
|
|
break;
|
|
case GRENADE:
|
|
case GMINE:
|
|
size = 2;
|
|
break;
|
|
case SATCHEL:
|
|
size = 3;
|
|
break;
|
|
case BOMB:
|
|
for (size = 3; size < MAXBOMB; size++)
|
|
if (shot_req[size] >= charge)
|
|
break;
|
|
size++;
|
|
break;
|
|
default:
|
|
size = 0;
|
|
break;
|
|
}
|
|
|
|
bp = create_shot(type, y, x, face, charge, size, owner,
|
|
(owner == NULL) ? NULL : owner->p_ident, expl, over);
|
|
bp->b_next = Bullets;
|
|
Bullets = bp;
|
|
}
|
|
|
|
BULLET *
|
|
create_shot(int type, int y, int x, char face, int charge,
|
|
int size, PLAYER *owner, IDENT *score, int expl, char over)
|
|
{
|
|
BULLET *bp;
|
|
|
|
bp = malloc(sizeof(*bp));
|
|
if (bp == NULL) {
|
|
if (owner != NULL)
|
|
message(owner, "Out of memory");
|
|
return NULL;
|
|
}
|
|
|
|
bp->b_face = face;
|
|
bp->b_x = x;
|
|
bp->b_y = y;
|
|
bp->b_charge = charge;
|
|
bp->b_owner = owner;
|
|
bp->b_score = score;
|
|
bp->b_type = type;
|
|
bp->b_size = size;
|
|
bp->b_expl = expl;
|
|
bp->b_over = over;
|
|
bp->b_next = NULL;
|
|
|
|
return bp;
|
|
}
|
|
|
|
/*
|
|
* cloak:
|
|
* Turn on or increase length of a cloak
|
|
*/
|
|
static void
|
|
cloak(PLAYER *pp)
|
|
{
|
|
if (pp->p_ammo <= 0) {
|
|
message(pp, "No more charges");
|
|
return;
|
|
}
|
|
#ifdef BOOTS
|
|
if (pp->p_nboots > 0) {
|
|
message(pp, "Boots are too noisy to cloak!");
|
|
return;
|
|
}
|
|
#endif
|
|
(void) snprintf(Buf, sizeof(Buf), "%3d", --pp->p_ammo);
|
|
cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
|
|
outstr(pp, Buf, 3);
|
|
|
|
pp->p_cloak += CLOAKLEN;
|
|
|
|
if (pp->p_scan >= 0)
|
|
pp->p_scan = -1;
|
|
|
|
showstat(pp);
|
|
}
|
|
|
|
/*
|
|
* scan:
|
|
* Turn on or increase length of a scan
|
|
*/
|
|
static void
|
|
scan(PLAYER *pp)
|
|
{
|
|
if (pp->p_ammo <= 0) {
|
|
message(pp, "No more charges");
|
|
return;
|
|
}
|
|
(void) snprintf(Buf, sizeof(Buf), "%3d", --pp->p_ammo);
|
|
cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
|
|
outstr(pp, Buf, 3);
|
|
|
|
pp->p_scan += SCANLEN;
|
|
|
|
if (pp->p_cloak >= 0)
|
|
pp->p_cloak = -1;
|
|
|
|
showstat(pp);
|
|
}
|
|
|
|
/*
|
|
* pickup:
|
|
* check whether the object blew up or whether he picked it up
|
|
*/
|
|
void
|
|
pickup(PLAYER *pp, int y, int x, int prob, int obj)
|
|
{
|
|
int req;
|
|
|
|
switch (obj) {
|
|
case MINE:
|
|
req = BULREQ;
|
|
break;
|
|
case GMINE:
|
|
req = GRENREQ;
|
|
break;
|
|
default:
|
|
abort();
|
|
}
|
|
if (rand_num(100) < prob)
|
|
add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL,
|
|
TRUE, pp->p_face);
|
|
else {
|
|
pp->p_ammo += req;
|
|
(void) snprintf(Buf, sizeof(Buf), "%3d", pp->p_ammo);
|
|
cgoto(pp, STAT_AMMO_ROW, STAT_VALUE_COL);
|
|
outstr(pp, Buf, 3);
|
|
}
|
|
}
|