NetBSD/games/hunt/huntd/execute.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);
}
}