#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: playit.c,v 1.25 2014/03/30 05:48:35 dholland Exp $");
#endif
#include <sys/file.h>
#include <sys/poll.h>
#include <err.h>
#include <errno.h>
#include <curses.h>
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "hunt_common.h"
#include "hunt_private.h"
#ifndef FREAD
#define FREAD 1
#endif
static int nchar_send;
#ifdef OTTO
int Otto_count;
int Otto_mode;
static int otto_y, otto_x;
static char otto_face;
#endif
#define MAX_SEND 5
static int icnt = 0;
static unsigned char ibuf[256], *iptr = ibuf;
#define GETCHR() (--icnt < 0 ? getchr() : *iptr++)
static unsigned char getchr(void);
static void send_stuff(void);
static void redraw_screen(void);
void
playit(void)
{
int ch;
int y, x;
uint32_t version;
ssize_t result;
result = read(huntsocket, &version, sizeof(version));
if (result != (ssize_t)sizeof(version)) {
bad_con();
}
if (ntohl(version) != (uint32_t)HUNT_VERSION) {
bad_ver();
}
errno = 0;
#ifdef OTTO
Otto_count = 0;
#endif
nchar_send = MAX_SEND;
while ((ch = GETCHR()) != EOF) {
#ifdef DEBUG
fputc(ch, stderr);
#endif
switch (ch & 0377) {
case MOVE:
y = GETCHR();
x = GETCHR();
move(y, x);
break;
case ADDCH:
ch = GETCHR();
#ifdef OTTO
switch (ch) {
case '<':
case '>':
case '^':
case 'v':
otto_face = ch;
getyx(stdscr, otto_y, otto_x);
break;
}
#endif
addch(ch);
break;
case CLRTOEOL:
clrtoeol();
break;
case CLEAR:
clear_the_screen();
break;
case REFRESH:
refresh();
break;
case REDRAW:
redraw_screen();
refresh();
break;
case ENDWIN:
refresh();
if ((ch = GETCHR()) == LAST_PLAYER)
Last_player = true;
ch = EOF;
goto out;
case BELL:
beep();
break;
case READY:
refresh();
if (nchar_send < 0)
tcflush(STDIN_FILENO, TCIFLUSH);
nchar_send = MAX_SEND;
#ifndef OTTO
(void) GETCHR();
#else
Otto_count -= (GETCHR() & 0xff);
if (!Am_monitor) {
#ifdef DEBUG
fputc('0' + Otto_count, stderr);
#endif
if (Otto_count == 0 && Otto_mode)
otto(otto_y, otto_x, otto_face);
}
#endif
break;
default:
#ifdef OTTO
switch (ch) {
case '<':
case '>':
case '^':
case 'v':
otto_face = ch;
getyx(stdscr, otto_y, otto_x);
break;
}
#endif
addch(ch);
break;
}
}
out:
(void) close(huntsocket);
}
static unsigned char
getchr(void)
{
struct pollfd set[2];
int nfds;
set[0].fd = huntsocket;
set[0].events = POLLIN;
set[1].fd = STDIN_FILENO;
set[1].events = POLLIN;
one_more_time:
do {
errno = 0;
nfds = poll(set, 2, INFTIM);
} while (nfds <= 0 && errno == EINTR);
if (set[1].revents && POLLIN)
send_stuff();
if (! (set[0].revents & POLLIN))
goto one_more_time;
icnt = read(huntsocket, ibuf, sizeof ibuf);
if (icnt < 0) {
bad_con();
}
if (icnt == 0)
goto one_more_time;
iptr = ibuf;
icnt--;
return *iptr++;
}
static void
send_stuff(void)
{
int count;
char *sp, *nsp;
static char inp[sizeof Buf];
count = read(STDIN_FILENO, Buf, sizeof(Buf) - 1);
if (count <= 0)
return;
if (nchar_send <= 0 && !no_beep) {
(void) beep();
return;
}
Buf[count] = '\0';
nsp = inp;
for (sp = Buf; *sp != '\0'; sp++)
if ((*nsp = map_key[(unsigned char)*sp]) == 'q')
intr(0);
else
nsp++;
count = nsp - inp;
if (count) {
#ifdef OTTO
Otto_count += count;
#endif
nchar_send -= count;
if (nchar_send < 0)
count += nchar_send;
(void) write(huntsocket, inp, count);
}
}
int
quit(int old_status)
{
bool explain;
int ch;
if (Last_player)
return Q_QUIT;
#ifdef OTTO
if (Otto_mode)
return Q_CLOAK;
#endif
move(HEIGHT, 0);
addstr("Re-enter game [ynwo]? ");
clrtoeol();
explain = false;
for (;;) {
refresh();
if (isupper(ch = getchar()))
ch = tolower(ch);
if (ch == 'y')
return old_status;
else if (ch == 'o')
break;
else if (ch == 'n') {
#ifndef INTERNET
return Q_QUIT;
#else
move(HEIGHT, 0);
addstr("Write a parting message [yn]? ");
clrtoeol();
refresh();
for (;;) {
if (isupper(ch = getchar()))
ch = tolower(ch);
if (ch == 'y')
goto get_message;
if (ch == 'n')
return Q_QUIT;
}
#endif
}
#ifdef INTERNET
else if (ch == 'w') {
static char buf[WIDTH + WIDTH % 2];
char *cp, c;
get_message:
c = ch;
move(HEIGHT, 0);
addstr("Message: ");
clrtoeol();
refresh();
cp = buf;
for (;;) {
refresh();
if ((ch = getchar()) == '\n' || ch == '\r')
break;
if (ch == erasechar()) {
if (cp > buf) {
int y, x;
getyx(stdscr, y, x);
move(y, x - 1);
cp -= 1;
clrtoeol();
}
continue;
}
else if (ch == killchar()) {
int y, x;
getyx(stdscr, y, x);
move(y, x - (cp - buf));
cp = buf;
clrtoeol();
continue;
} else if (!isprint(ch)) {
beep();
continue;
}
addch(ch);
*cp++ = ch;
if (cp + 1 >= buf + sizeof buf)
break;
}
*cp = '\0';
Send_message = buf;
return (c == 'w') ? old_status : Q_MESSAGE;
}
#endif
beep();
if (!explain) {
addstr("(Yes, No, Write message, or Options) ");
explain = true;
}
}
move(HEIGHT, 0);
#ifdef FLY
addstr("Scan, Cloak, Flying, or Quit? ");
#else
addstr("Scan, Cloak, or Quit? ");
#endif
clrtoeol();
refresh();
explain = false;
for (;;) {
if (isupper(ch = getchar()))
ch = tolower(ch);
if (ch == 's')
return Q_SCAN;
else if (ch == 'c')
return Q_CLOAK;
#ifdef FLY
else if (ch == 'f')
return Q_FLY;
#endif
else if (ch == 'q')
return Q_QUIT;
beep();
if (!explain) {
#ifdef FLY
addstr("[SCFQ] ");
#else
addstr("[SCQ] ");
#endif
explain = true;
}
refresh();
}
}
void
clear_the_screen(void)
{
clear();
move(0, 0);
refresh();
}
static void
redraw_screen(void)
{
clearok(stdscr, TRUE);
touchwin(stdscr);
}
void
do_message(void)
{
uint32_t version;
ssize_t result;
result = read(huntsocket, &version, sizeof(version));
if (result != (ssize_t)sizeof(version)) {
bad_con();
}
if (ntohl(version) != (uint32_t)HUNT_VERSION) {
bad_ver();
}
#ifdef INTERNET
if (write(huntsocket, Send_message, strlen(Send_message)) < 0) {
bad_con();
}
#endif
(void) close(huntsocket);
}