#include <sys/select.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "conf.h"
#include "hunt.h"
#include "server.h"
static void cloak(PLAYER *);
static void face(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 *);
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) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
break;
default:
;
}
}
void
execute(PLAYER *pp)
{
char ch;
ch = pp->p_cbuf[pp->p_ncount++];
if (pp->p_flying >= 0) {
switch (ch) {
case CTRL('L'):
sendcom(pp, REDRAW);
break;
case 'q':
(void) strlcpy(pp->p_death, "| Quit |",
sizeof pp->p_death);
break;
}
return;
}
switch (ch) {
case CTRL('L'):
sendcom(pp, REDRAW);
break;
case 'h':
move_player(pp, LEFTS);
break;
case 'H':
face(pp, LEFTS);
break;
case 'j':
move_player(pp, BELOW);
break;
case 'J':
face(pp, BELOW);
break;
case 'k':
move_player(pp, ABOVE);
break;
case 'K':
face(pp, ABOVE);
break;
case 'l':
move_player(pp, RIGHT);
break;
case 'L':
face(pp, RIGHT);
break;
case 'f':
case '1':
fire(pp, 0);
break;
case 'g':
case '2':
fire(pp, 1);
break;
case 'F':
case '3':
fire(pp, 2);
break;
case 'G':
case '4':
fire(pp, 3);
break;
case '5':
fire(pp, 4);
break;
case '6':
fire(pp, 5);
break;
case '7':
fire(pp, 6);
break;
case '8':
fire(pp, 7);
break;
case '9':
fire(pp, 8);
break;
case '0':
fire(pp, 9);
break;
case '@':
fire(pp, 10);
break;
case 'o':
fire_slime(pp, 0);
break;
case 'O':
fire_slime(pp, 1);
break;
case 'p':
fire_slime(pp, 2);
break;
case 'P':
fire_slime(pp, 3);
break;
case 's':
scan(pp);
break;
case 'c':
cloak(pp);
break;
case 'q':
(void) strlcpy(pp->p_death, "| Quit |", sizeof pp->p_death);
break;
}
}
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:
case DOOR:
moved = TRUE;
break;
case WALL1:
case WALL2:
case WALL3:
case WALL4:
case WALL5:
break;
case MINE:
case GMINE:
if (dir == pp->p_face)
pickup(pp, y, x, conf_ptrip_face, Maze[y][x]);
else if (opposite(dir, pp->p_face))
pickup(pp, y, x, conf_ptrip_back, Maze[y][x]);
else
pickup(pp, y, x, conf_ptrip_side, Maze[y][x]);
Maze[y][x] = SPACE;
moved = TRUE;
break;
case SHOT:
case GRENADE:
case SATCHEL:
case BOMB:
case SLIME:
case DSHOT:
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, conf_stabdam, KNIFE);
}
break;
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;
case BOOT_PAIR:
pp->p_nboots++;
case BOOT:
pp->p_nboots++;
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;
}
if (moved) {
if (pp->p_ncshot > 0)
if (--pp->p_ncshot == conf_maxncshot)
outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ok");
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);
}
}
static void
face(PLAYER *pp, int dir)
{
if (pp->p_face != dir) {
pp->p_face = dir;
drawplayer(pp, TRUE);
}
}
static void
fire(PLAYER *pp, int req_index)
{
if (pp == NULL)
return;
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 > conf_maxncshot)
return;
if (pp->p_ncshot++ == conf_maxncshot) {
outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ");
}
pp->p_ammo -= shot_req[req_index];
ammo_update(pp);
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;
showexpl(pp->p_y, pp->p_x, shot_type[req_index]);
sendcom(ALL_PLAYERS, REFRESH);
}
static void
fire_slime(PLAYER *pp, int req_index)
{
if (pp == NULL)
return;
if (!conf_ooze)
return;
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 > conf_maxncshot)
return;
if (pp->p_ncshot++ == conf_maxncshot) {
outyx(pp, STAT_GUN_ROW, STAT_VALUE_COL, " ");
}
pp->p_ammo -= slime_req[req_index];
ammo_update(pp);
add_shot(SLIME, pp->p_y, pp->p_x, pp->p_face,
slime_req[req_index] * conf_slimefactor, pp, FALSE, pp->p_face);
pp->p_undershot = TRUE;
showexpl(pp->p_y, pp->p_x, SLIME);
sendcom(ALL_PLAYERS, REFRESH);
}
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 (BULLET));
if (bp == NULL) {
logit(LOG_ERR, "malloc");
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;
}
static void
cloak(PLAYER *pp)
{
if (!conf_cloak)
return;
if (pp->p_ammo <= 0) {
message(pp, "No more charges");
return;
}
if (pp->p_nboots > 0) {
message(pp, "Boots are too noisy to cloak!");
return;
}
pp->p_ammo--;
ammo_update(pp);
pp->p_cloak += conf_cloaklen;
if (pp->p_scan >= 0)
pp->p_scan = -1;
showstat(pp);
}
static void
scan(PLAYER *pp)
{
if (!conf_scan)
return;
if (pp->p_ammo <= 0) {
message(pp, "No more charges");
return;
}
pp->p_ammo--;
ammo_update(pp);
pp->p_scan += Nplayer * conf_scanlen;
if (pp->p_cloak >= 0)
pp->p_cloak = -1;
showstat(pp);
}
static 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:
#ifdef DIAGNOSTIC
abort();
#endif
return;
}
if (rand_num(100) < prob)
add_shot(obj, y, x, LEFTS, req, (PLAYER *) NULL,
TRUE, pp->p_face);
else {
pp->p_ammo += req;
ammo_update(pp);
}
}
void
ammo_update(PLAYER *pp)
{
outyx(pp, STAT_AMMO_ROW, STAT_VALUE_COL - 1, "%4d", pp->p_ammo);
}