/*
* Various input/output functions
*
* Advanced Rogue
* Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
* All rights reserved.
*
* Based on "Rogue: Exploring the Dungeons of Doom"
* Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#include "curses.h"
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
#include "rogue.h"
void doadd(char *fmt, va_list ap);
void ministat(void);
/*
* msg:
* Display a message at the top of the screen.
*/
static char msgbuf[BUFSIZ];
static int newpos = 0;
/*VARARGS1*/
void
msg(char *fmt, ...)
{
va_list ap;
/*
* if the string is "", just clear the line
*/
if (*fmt == '\0')
{
overwrite(cw,msgw);
wmove(msgw, 0, 0);
clearok(msgw, FALSE);
draw(msgw);
mpos = 0;
return;
}
/*
* otherwise add to the message and flush it out
*/
va_start(ap,fmt);
doadd(fmt, ap);
va_end(ap);
endmsg();
}
/*
* add things to the current message
*/
void
addmsg(char *fmt, ...)
{
va_list ap;
va_start(ap,fmt);
doadd(fmt, ap);
va_end(ap);
}
/*
* Display a new msg (giving him a chance to see the previous one if it
* is up there with the --More--)
*/
void
endmsg(void)
{
strncpy(huh, msgbuf, sizeof(huh));
huh[ sizeof(huh) - 1 ] = 0;
if (mpos)
{
wmove(msgw, 0, mpos);
waddstr(msgw, morestr);
draw(cw);
draw(msgw);
wait_for(msgw,' ');
overwrite(cw,msgw);
wmove(msgw,0,0);
touchwin(cw);
}
else {
overwrite(cw,msgw);
wmove(msgw,0,0);
}
waddstr(msgw, msgbuf);
mpos = newpos;
newpos = 0;
msgbuf[0] = '\0';
draw(cw);
clearok(msgw, FALSE);
draw(msgw);
}
void
doadd(char *fmt, va_list ap)
{
/*
* Do the sprintf into newmsg and append to msgbuf
*/
vsnprintf(&msgbuf[newpos], sizeof(msgbuf)-newpos-1, fmt, ap);
newpos = strlen(msgbuf);
}
/*
* step_ok:
* returns true if it is ok for type to step on ch
* flgptr will be NULL if we don't know what the monster is yet!
*/
bool
step_ok(int y, int x, int can_on_monst, struct thing *flgptr)
{
/* can_on_monst = MONSTOK if all we care about are physical obstacles */
register struct linked_list *item;
char ch;
/* What is here? Don't check monster window if MONSTOK is set */
if (can_on_monst == MONSTOK) ch = CCHAR( mvinch(y, x) );
else ch = CCHAR( winat(y, x) );
switch (ch)
{
case ' ':
case '|':
case '-':
case SECRETDOOR:
if (flgptr && on(*flgptr, CANINWALL)) return(TRUE);
return FALSE;
when SCROLL:
if (can_on_monst == MONSTOK) return(TRUE); /* Not a real obstacle */
/*
* If it is a scroll, it might be a scare monster scroll
* so we need to look it up to see what type it is.
*/
if (flgptr && flgptr->t_ctype == C_MONSTER) {
item = find_obj(y, x);
if (item != NULL &&
(OBJPTR(item))->o_which==S_SCARE &&
(flgptr == NULL || flgptr->t_stats.s_intel < 16))
return(FALSE); /* All but smart ones are scared */
}
return(TRUE);
otherwise:
return (!isalpha(ch));
}
}
/*
* shoot_ok:
* returns true if it is ok for type to shoot over ch
*/
bool
shoot_ok(char ch)
{
switch (ch)
{
case ' ':
case '|':
case '-':
case SECRETDOOR:
case FOREST:
return FALSE;
default:
return (!isalpha(ch));
}
}
/*
* readchar:
* flushes stdout so that screen is up to date and then returns
* getchar.
*/
int
readchar(void)
{
int ch;
ch = md_readchar(cw);
if ((ch == 3) || (ch == 0))
{
quit(0);
return(27);
}
return(ch);
}
/*
* status:
* Display the important stats line. Keep the cursor where it was.
* If display is TRUE, display unconditionally
*/
void
status(bool display)
{
register struct stats *stat_ptr, *max_ptr;
register int oy = 0, ox = 0, temp;
register char *pb;
static char buf[LINELEN];
static int hpwidth = 0, s_hungry = -1;
static int s_lvl = -1, s_pur, s_hp = -1, s_str, maxs_str,
s_ac = 0;
static short s_intel, s_dext, s_wisdom, s_const, s_charisma;
static short maxs_intel, maxs_dext, maxs_wisdom, maxs_const, maxs_charisma;
static unsigned long s_exp = 0;
static int s_carry, s_pack;
bool first_line=FALSE;
/* Use a mini status version if we have a small window */
if (COLS < 80) {
ministat();
return;
}
stat_ptr = &pstats;
max_ptr = &max_stats;
/*
* If nothing has changed in the first line, then skip it
*/
if (!display &&
s_lvl == level &&
s_intel == stat_ptr->s_intel &&
s_wisdom == stat_ptr->s_wisdom &&
s_dext == dex_compute() &&
s_const == stat_ptr->s_const &&
s_charisma == stat_ptr->s_charisma &&
s_str == str_compute() &&
s_pack == stat_ptr->s_pack &&
s_carry == stat_ptr->s_carry &&
maxs_intel == max_ptr->s_intel &&
maxs_wisdom == max_ptr->s_wisdom &&
maxs_dext == max_ptr->s_dext &&
maxs_const == max_ptr->s_const &&
maxs_charisma == max_ptr->s_charisma &&
maxs_str == max_ptr->s_str ) goto line_two;
/* Display the first line */
first_line = TRUE;
getyx(cw, oy, ox);
sprintf(buf, "Int:%d(%d) Str:%d", stat_ptr->s_intel,
max_ptr->s_intel, str_compute());
/* Maximum strength */
pb = &buf[strlen(buf)];
sprintf(pb, "(%d)", max_ptr->s_str);
pb = &buf[strlen(buf)];
sprintf(pb, " Wis:%d(%d) Dxt:%d(%d) Const:%d(%d) Carry:%d(%d)",
stat_ptr->s_wisdom,max_ptr->s_wisdom,dex_compute(),max_ptr->s_dext,
stat_ptr->s_const,max_ptr->s_const,stat_ptr->s_pack/10,
stat_ptr->s_carry/10);
/* Update first line status */
s_intel = stat_ptr->s_intel;
s_wisdom = stat_ptr->s_wisdom;
s_dext = dex_compute();
s_const = stat_ptr->s_const;
s_charisma = stat_ptr->s_charisma;
s_str = str_compute();
s_pack = stat_ptr->s_pack;
s_carry = stat_ptr->s_carry;
maxs_intel = max_ptr->s_intel;
maxs_wisdom = max_ptr->s_wisdom;
maxs_dext = max_ptr->s_dext;
maxs_const = max_ptr->s_const;
maxs_charisma = max_ptr->s_charisma;
maxs_str = max_ptr->s_str;
/* Print the line */
mvwaddstr(cw, LINES - 2, 0, buf);
wclrtoeol(cw);
/*
* If nothing has changed since the last status, don't
* bother.
*/
line_two:
if (!display &&
s_hp == stat_ptr->s_hpt &&
s_exp == stat_ptr->s_exp &&
s_pur == purse &&
s_ac == ac_compute() - dext_prot(s_dext) &&
s_lvl == level &&
s_hungry == hungry_state ) return;
if (!first_line) getyx(cw, oy, ox);
if (s_hp != max_ptr->s_hpt)
{
temp = s_hp = max_ptr->s_hpt;
for (hpwidth = 0; temp; hpwidth++)
temp /= 10;
}
sprintf(buf, "Lvl:%d Au:%d Hp:%*d(%*d) Ac:%d Exp:%d/%lu %s",
level, purse, hpwidth, stat_ptr->s_hpt, hpwidth, max_ptr->s_hpt,
ac_compute() - dext_prot(s_dext),stat_ptr->s_lvl, stat_ptr->s_exp,
cnames[player.t_ctype][min(stat_ptr->s_lvl-1, 10)]);
/*
* Save old status
*/
s_lvl = level;
s_pur = purse;
s_hp = stat_ptr->s_hpt;
s_exp = stat_ptr->s_exp;
s_ac = ac_compute() - dext_prot(s_dext);
mvwaddstr(cw, LINES - 1, 0, buf);
switch (hungry_state)
{
case F_OKAY: ;
when F_HUNGRY:
waddstr(cw, " Hungry");
when F_WEAK:
waddstr(cw, " Weak");
when F_FAINT:
waddstr(cw, " Fainting");
}
wclrtoeol(cw);
s_hungry = hungry_state;
wmove(cw, oy, ox);
}
void
ministat(void)
{
register int oy, ox, temp;
static char buf[LINELEN];
static int hpwidth = 0;
static int s_lvl = -1, s_pur, s_hp = -1;
/*
* If nothing has changed since the last status, don't
* bother.
*/
if (s_hp == pstats.s_hpt && s_pur == purse && s_lvl == level)
return;
getyx(cw, oy, ox);
if (s_hp != max_stats.s_hpt)
{
temp = s_hp = max_stats.s_hpt;
for (hpwidth = 0; temp; hpwidth++)
temp /= 10;
}
sprintf(buf, "Lv: %d Au: %-5d Hp: %*d(%*d)",
level, purse, hpwidth, pstats.s_hpt, hpwidth, max_stats.s_hpt);
/*
* Save old status
*/
s_lvl = level;
s_pur = purse;
s_hp = pstats.s_hpt;
mvwaddstr(cw, LINES - 1, 0, buf);
wclrtoeol(cw);
wmove(cw, oy, ox);
}
/*
* wait_for
* Sit around until the guy types the right key
*/
void
wait_for(WINDOW *win, char ch)
{
register char c;
if (ch == '\n')
while ((c = wgetch(win)) != '\n' && c != '\r')
continue;
else
while (wgetch(win) != ch)
continue;
}
/*
* show_win:
* function used to display a window and wait before returning
*/
void
show_win(WINDOW *scr, char *message)
{
mvwaddstr(scr, 0, 0, message);
touchwin(scr);
wmove(scr, hero.y, hero.x);
draw(scr);
wait_for(scr,' ');
clearok(cw, TRUE);
touchwin(cw);
}
/*
* dbotline:
* Displays message on bottom line and waits for a space to return
*/
void
dbotline(WINDOW *scr, char *message)
{
mvwaddstr(scr,LINES-1,0,message);
draw(scr);
wait_for(scr,' ');
}
/*
* restscr:
* Restores the screen to the terminal
*/
void
restscr(WINDOW *scr)
{
clearok(scr,TRUE);
touchwin(scr);
}
/*
* netread:
* Read a byte, short, or long machine independently
* Always returns the value as an unsigned long.
*/
unsigned long
netread(int *error, int size, FILE *stream)
{
unsigned long result = 0L, /* What we read in */
partial; /* Partial value */
int nextc, /* The next byte */
i; /* To index through the result a byte at a time */
/* Be sure we have a right sized chunk */
if (size < 1 || size > 4) {
*error = 1;
return(0L);
}
for (i=0; i<size; i++) {
nextc = getc(stream);
if (nextc == EOF) {
*error = 1;
return(0L);
}
else {
partial = (unsigned long) (nextc & 0xff);
partial <<= 8*i;
result |= partial;
}
}
*error = 0;
return(result);
}
/*
* netwrite:
* Write out a byte, short, or long machine independently.
* value: What to write
* size: How much to write out
* stream: Where to write it
*/
int
netwrite(unsigned long value, int size, FILE *stream)
{
int i; /* Goes through value one byte at a time */
char outc; /* The next character to be written */
/* Be sure we have a right sized chunk */
if (size < 1 || size > 4) return(0);
for (i=0; i<size; i++) {
outc = (char) ((value >> (8 * i)) & 0xff);
putc(outc, stream);
}
return(size);
}