nexus/io.c

1436 lines
29 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
WINDOW *mainwin;
WINDOW *gamewin;
WINDOW *msgwin;
WINDOW *statwin;
extern enum ERROR reason;
extern FILE *logfile;
extern enum OBCLASS sortorder[];
extern knowledge_t *knowledge;
extern int gamestarted;
char msgbuf[HUGEBUFLEN];
extern lifeform_t *player;
extern map_t *firstmap;
int viewx = -9999,viewy = -9999;
int vieww,viewh;
void anim(cell_t *src, cell_t *dst, char ch) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1,dir;
int x;
int y;
int maxvisrange;
int modmaxvisrange;
int xray = B_FALSE;
int wentuphill = B_FALSE;
int origheight;
int shopwall;
int x2,y2;
// just in case
if (src->map != dst->map) return;
x1 = src->x;
y1 = src->y;
x2 = dst->x;
y2 = dst->y;
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
// going nowhere
if ((deltax == 0) && (deltay == 0)) {
return;
}
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// get current cell
cell = getcellat(src->map, x, y);
// update screen
updateviewfor(cell);
drawlevelfor(player);
// draw char & cursor at its current pos...
mvwprintw(gamewin, cell->y - viewy, cell->x - viewx, "%c", ch);
wmove(gamewin, cell->y - viewy, cell->x - viewx);
wrefresh(gamewin);
usleep(ANIMDELAY);
// move to next cell
if (d < 0) {
xinc = xinc1;
yinc = yinc1;
dinc = dinc1;
} else {
xinc = xinc2;
yinc = yinc2;
dinc = dinc2;
}
d += dinc;
x += xinc;
y += yinc;
}
}
cell_t *askcoords(char *prompt) {
int finished = B_FALSE;
cell_t *c,*newcell;
c = player->cell;
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", prompt);
wrefresh(msgwin);
while (!finished) {
int dir;
char ch;
drawstatus();
updateviewfor(c);
drawlevelfor(player);
// move cursor selected position
wmove(gamewin, c->y - viewy, c->x - viewx);
redraw();
// get input
ch = getch();
if (ch == '.') {
return c;
} else if (ch == 27) { // ESC - cancel
finished = B_TRUE;
} else {
dir = chartodir(ch);
if (dir != D_NONE) {
newcell = getcellindir(c, dir);
if (newcell) c = newcell;
}
}
}
return NULL;
}
object_t *askobject(obpile_t *op, char *prompt, int *count, int opts) {
doaskobject(op, prompt, count, opts, OC_NULL);
}
object_t *askobjectofclass(obpile_t *op, char *prompt, int *count, int opts, enum OBCLASS obclass) {
doaskobject(op, prompt, count, opts, obclass);
}
object_t *doaskobject(obpile_t *op, char *prompt, int *count, int opts, enum OBCLASS obclass) {
int c,i;
object_t *mylist[MAXPILEOBS+1];
char myletters[MAXPILEOBS+1];
char numstring[BUFLEN];
int firstob = 0;
int nextpage = -1;
int lastline = SCREENH-2;
char buf[BUFLEN],buf2[BUFLEN];
int finished;
char nextlet = 'a';
int useobletters;
objectclass_t *wantoc;
flag_t *f;
reason = E_OK;
wantoc = findoc(obclass); // might be null if OC_NULL was passed.
// if picking form a player's pack, use the object's letters.
// otherwise just label them a, b, c, etc.
if (op->owner && (op->owner->controller == C_PLAYER)) {
useobletters = B_TRUE;
} else {
useobletters = B_FALSE;
}
// construct a list of objects
c = 0;
i = 0;
while (sortorder[c] != OC_NULL) {
object_t *o;
if (!wantoc || (sortorder[c] == wantoc->id)) {
// add all objects of this class
for (o = op->first ; o ; o = o->next) {
if (o->type->obclass->id == sortorder[c]) {
int ok;
// can we include this object?
ok = B_TRUE;
if ((opts & AO_ONLYEQUIPPED) && !hasflag(o->flags, F_EQUIPPED)) {
ok = B_FALSE;
}
if (ok) {
mylist[i] = o;
myletters[i] = nextlet;
if (++nextlet > 'z') nextlet = 'A';
i++;
}
}
}
}
c++;
}
mylist[i] = NULL;
// start displaying from the first one
firstob = 0;
nextpage = -1;
finished = B_FALSE;
strcpy(numstring, "");
while (!finished) {
int lastclass = OC_NULL;
int y;
int ch;
wclear(mainwin);
// list the objects
y = 2;
for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) {
if (mylist[i]->type->obclass->id != lastclass) {
objectclass_t *oc;
// print class heading
mvwprintw(mainwin, y, 0, "%s", mylist[i]->type->obclass->name);
lastclass = mylist[i]->type->obclass->id;
y++;
}
// print object name
getobname(mylist[i], buf,mylist[i]->amt);
sprintf(buf2, " %c - %s", useobletters ? mylist[i]->letter : myletters[i],
buf);
f = hasflag(mylist[i]->flags,F_EQUIPPED);
if (f) {
if (f->val[0] == BP_WEAPON) {
strcat(buf2, " (weapon)");
} else {
strcat(buf2, " (");
strcat(buf2, getbodypartequipname(f->val[0]));
strcat(buf2, " ");
strcat(buf2, getbodypartname(f->val[0]));
strcat(buf2, ")");
}
}
mvwprintw(mainwin, y, 0, buf2);
y++;
}
if (mylist[i] == NULL) {
nextpage = -1;
} else {
nextpage = i;
}
// draw prompt
if (strlen(numstring) > 0) {
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit) [%s]: ",prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
numstring);
} else {
mvwprintw(mainwin, 0, 0, "%s (%sESC to quit): ", prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "");
}
if (nextpage != -1) {
mvwprintw(mainwin, y, 0, "-- More --");
}
// update screen
wrefresh(mainwin);
// wait for keypess
ch = getch();
if (ch == 27) { // ESCAPE
finished = B_TRUE;
break;
}
// otherwise look for shift key etc..
ch = keycodetokey(ch);
// then handle input
if (ch == ' ') { // next page
if (nextpage == -1) { // go to first page
firstob = 0;
} else {
firstob = nextpage;
}
} else if (isalpha(ch) || (ch == '$')) {
object_t *o;
// describe that object
if (useobletters) {
o = findobl(op, ch);
} else {
o = NULL;
for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) {
if (myletters[i] == ch) {
o = mylist[i];
break;
}
}
}
if (o) {
// make sure count is okay...
if (count && *count > o->amt) {
*count = o->amt;
}
if (count && (*count == ALL)) {
*count = o->amt;
}
// display game windows again
clearmsg();
drawscreen();
return o;
}
} else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing
reason = E_SELNOTHING;
// display game windows again
clearmsg();
drawscreen();
return NULL;
} else if (isdigit(ch)) {
char temp[2];
temp[0] = ch;
temp[1] = '\0';
strcat(numstring, temp);
if (count) *count = atoi(numstring);
} else if (ch == 8) { // backspace
if (strlen(numstring) > 0) {
// remove last letter of number string
numstring[strlen(numstring)-1] = '\0';
if (count) *count = atoi(numstring);
}
}
// sanity check count...
if (count && (*count == 0)) {
strcpy(numstring, "");
}
}
// clear msg bar
clearmsg();
// display game windows again
drawscreen();
return NULL;
}
void centre(WINDOW *win, int y, char *format, ... ) {
int w;
char buf[BUFLEN];
va_list args;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
w = getmaxx(win);
mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf);
}
int chartodir(char c) {
switch (tolower(c)) {
case 'h': return D_W;
case 'j': return D_S;
case 'k': return D_N;
case 'l': return D_E;
case 'y': return DC_NW;
case 'u': return DC_NE;
case 'b': return DC_SW;
case 'n': return DC_SE;
}
return D_NONE;
}
void clearmsg(void) {
wclear(msgwin);
wrefresh(msgwin);
}
int cleanupgfx(void) {
curs_set(1);
endwin();
return B_FALSE;
}
void updateviewfor(cell_t *cell) {
// calculate viewport if required
if ((viewx == -9999) || (viewy == -9999)) {
// try to centre player
viewx = cell->x - (SCREENW/2);
viewy = cell->y - (SCREENH/2);
}
while ((cell->x - viewx) >= ((SCREENW / 3)*2)) {
viewx++;
}
while ((cell->y - viewy) >= ((SCREENH / 3)*2)) {
viewy++;
}
while ((cell->x - viewx) <= (SCREENW/3)) {
viewx--;
}
while ((cell->y - viewy) <= (SCREENH/3)) {
viewy--;
}
}
void drawscreen(void) {
drawstatus();
updateviewfor(player->cell);
drawlevelfor(player);
drawcursor();
redraw();
}
void describeob(object_t *o) {
char buf[BUFLEN];
int y;
material_t *m;
flag_t *f;
wclear(mainwin);
// title
getobname(o, buf,o->amt);
mvwprintw(mainwin, 0, 0, buf);
if (isknown(o)) {
mvwprintw(mainwin, 2, 0, o->type->desc);
} else {
mvwprintw(mainwin, 2, 0, o->type->obclass->desc);
}
// properties
y = 4;
mvwprintw(mainwin, y, 0, "%s made from %s.",(o->amt == 1) ? "It is" : "They are", o->material->name); y++;
if (o->amt == 1) {
mvwprintw(mainwin, y, 0, "It weighs %0.1fkg.",o->weight);
} else {
mvwprintw(mainwin, y, 0, "They weigh %0.1fkg (%0.1f each).",(o->weight * o->amt), o->weight);
}
y++;
// weapons?
if (o->type->obclass->id == OC_WEAPON) {
f = hasflag(o->flags, F_DAMTYPE);
if (f) {
int damtype;
int anydam,mindam,maxdam;
damtype = f->val[0];
getdamrange(o, &mindam, &maxdam);
f = hasflag(o->flags, F_DAM);
if (f) {
if (f->val[2] == NA) {
mvwprintw(mainwin, y, 0, "It deals %d-%d %s damage (%dd%d).",mindam,maxdam,
getdamname(damtype), f->val[0], f->val[1]);
} else {
mvwprintw(mainwin, y, 0, "It deals %d-%d %s damage (%dd%d%c%d).",mindam,maxdam,
getdamname(damtype), f->val[0], f->val[1], (f->val[2] > 0) ? '+' : '-', abs(f->val[2]));
}
y++;
} else {
mvwprintw(mainwin, y, 0, "It deals %s damage.",getdamname(damtype));
y++;
}
}
f = hasflag(o->flags, F_OBATTACKSPEED);
if (f) {
getspeedname(f->val[0], buf);
mvwprintw(mainwin, y, 0, "Its attack rate is %s.",buf);
y++;
}
}
wrefresh(mainwin);
// wait for key
getch();
}
void dodrop(obpile_t *op) {
object_t *o;
char buf[BUFLEN];
int count = ALL;
o = askobject(op, "Drop what", &count, AO_NONE);
if (o) {
getobname(o, buf, count);
o = moveob(o, op->owner->cell->obpile, count);
if (o) { // if drop was successful...
if (op->owner) {
if (op->owner->controller == C_PLAYER) {
msg("You drop %s.",buf);
}
taketime(op->owner, (SPEED_DROP * count));
}
} else {
// tell the player why!
if (op->owner->controller == C_PLAYER) {
switch (reason) {
case E_NOSPACE:
msg("There is no space here for any more objects!");
break;
default:
msg("For some reason, you cannot drop %s!");
break;
}
}
}
}
}
int dowear(obpile_t *op) {
object_t *o,*oo;
char buf[BUFLEN];
int count = ALL;
int rv;
flag_t *f;
o = askobjectofclass(op, "Wear what", NULL, AO_NONE, OC_ARMOUR);
if (o) {
wear(player, o);
} else {
rv = B_TRUE;
}
return rv;
}
int doweild(obpile_t *op) {
object_t *o,*oo;
char buf[BUFLEN];
int count = ALL;
int rv;
flag_t *f;
o = askobject(op, "Weild what", &count, AO_INCLUDENOTHING);
if (o) {
rv = weild(player, o);
} else if (reason == E_SELNOTHING) {
// ie. unweild
rv = weild(player, NULL);
} else {
rv = B_TRUE;
}
return rv;
}
void doknowledgelist(void) {
knowledge_t *k;
int y = 0;
int numfound = 0;
int c;
wclear(mainwin);
mvwprintw(mainwin, y, 0, "Current Knowledge");
y++;
y++;
for (c = 0; sortorder[c] != OC_NULL ; c++) {
int first = B_TRUE;
for (k = knowledge ; k ; k = k->next) {
if (k->known) {
objecttype_t *ot;
ot = findot(k->id);
if (ot->obclass->id == c) {
if (first) {
mvwprintw(mainwin, y, 0, "%s", ot->obclass->name);
y++;
first = B_FALSE;
}
mvwprintw(mainwin, y, 0, " %-20s (%s)",ot->name, k->hiddenname);
y++;
numfound++;
if (y >= (SCREENH-1)) {
mvwprintw(mainwin, y, 0, "--More--");
wrefresh(mainwin);
getch();
wclear(mainwin);
}
}
}
}
}
if (numfound == 0) {
mvwprintw(mainwin, y, 0, "You don't know much.");
}
wrefresh(mainwin);
getch();
clearmsg();
drawscreen();
}
int dopickup(obpile_t *op) {
int obcount;
object_t *o = NULL;
int howmany = ALL;
char buf[BUFLEN];
obcount = countobs(op);
// anything here?
if (obcount == 0) {
msg("There is nothing here to pick up!");
return B_TRUE;
} else if (obcount == 1) {
// just get it
o = op->first;
howmany = ALL;
} else {
// prompt which one to pick up
o = askobject(op, "Pick up what", &howmany, AO_NONE);
}
if (o) {
pickup(player, o, howmany);
} else {
return B_TRUE;
}
return B_FALSE;
}
void doinventory(obpile_t *op) {
object_t *o;
o = askobject(op, "Select object to describe", NULL, AO_NONE);
while (o) {
// describe it
describeob(o);
// ask for another one
o = askobject(op, "Select object to describe", NULL, AO_NONE);
}
}
void doquaff(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
// ask which object to quaff
o = askobjectofclass(op, "Quaff what", NULL, AO_NONE, OC_POTION);
if (o) {
if (isdrinkable(o)) {
quaff(player, o);
} else {
msg("You can't drink that!");
}
}
}
void doread(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
// ask which object to read
o = askobjectofclass(op, "Read what", NULL, AO_NONE, OC_SCROLL);
if (o) {
if (isreadable(o)) {
read(player, o);
} else {
msg("You can't read that!");
}
}
}
int dotakeoff(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
flag_t *f;
int rv;
// ask which object to read
o = askobjectofclass(op, "Take off what", NULL, AO_ONLYEQUIPPED, OC_ARMOUR);
if (o) {
f = hasflag(o->flags, F_EQUIPPED);
if (f) {
rv = takeoff(player, o);
} else {
msg("You are not wearing that!");
rv = B_TRUE;
}
}
return rv;
}
void dothrow(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
// ask which object to throw
o = askobject(op, "Throw what", NULL, AO_NONE);
if (o) {
cell_t *where;
getobname(o, buf, 1);
// TODO: calculate throw range
// ask where to throw it
sprintf(buf2, "Throw %s where?",buf);
where = askcoords(buf2);
if (where) {
if (haslof(player, where)) {
throwat(player, o, where);
} else {
msg("You don't have a clear line of fire to there.");
}
}
}
}
// draw a cell which we can't see
void drawunviscell(cell_t *cell, int x, int y) {
char glyph;
if (cell->type->glyph == '.') {
glyph = ' ';
} else {
glyph = cell->type->glyph;
}
mvwprintw(gamewin, y, x, "%c", glyph);
}
void drawcell(cell_t *cell, int x, int y) {
// draw ground
mvwprintw(gamewin, y, x, "%c", cell->type->glyph);
}
void drawcellwithcontents(cell_t *cell, int x, int y) {
if (cell->lf) { // lifeform here?
// draw the lf's race glyph
mvwprintw(gamewin, y, x, "%c", cell->lf->race->glyph);
} else if (countobs(cell->obpile) > 0) {
object_t *o;
int c;
int drawn = B_FALSE;
// draw highest object in sort order
c = 0;
while ((sortorder[c] != OC_NULL) && (!drawn)) {
// check each object against this ob class
// count backwards so more recently dropped objects
// appear first.
for (o = cell->obpile->last ; o ; o = o->prev) {
if (o->type->obclass->id == sortorder[c]) {
// draw it
mvwprintw(gamewin, y, x, "%c", getglyph(o));
drawn = B_TRUE;
break;
}
}
c++;
}
if (!drawn) {
// should never happen. if it does, just show the
// first object
dblog("Warn: sorted object glyph drawing matching nothing!");
mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph);
}
} else {
drawcell(cell, x, y);
}
}
void drawcursor(void) {
// move cursor to player position
wmove(gamewin, player->cell->y - viewy, player->cell->x - viewx);
wrefresh(gamewin);
}
void drawlevelfor(lifeform_t *lf) {
int x,y;
int cx,cy;
cell_t *cell;
map_t *map;
map = lf->cell->map;
wclear(gamewin);
for (y = viewy; y < viewy + viewh; y++) {
for (x = viewx; x < viewx + vieww; x++) {
cell = getcellat(map, x, y);
if (cell) {
if (haslos(lf, cell)) {
drawcellwithcontents(cell, x-viewx, y-viewy);
} else if (cell->known) {
drawunviscell(cell, x-viewx, y-viewy);
}
}
}
}
}
void initgfx(void) {
mainwin = initscr();
if (!has_colors()) {
printf("Terminal does not support colour.\n");
exit(1);
}
start_color();
noecho();
cbreak();
nodelay(mainwin, FALSE);
// determine window sizes
vieww = SCREENW;
viewh = SCREENH - 4;
// create windows
msgwin = newwin(1, vieww, 0, 0);
gamewin = newwin(viewh, vieww, 1, 0);
statwin = newwin(2, vieww, 2 + viewh,0);
redraw();
refresh();
// init message buffer
strcpy(msgbuf, "");
}
int getkey(void) {
int key_code=0;
key_code = getch();
return keycodetokey(key_code);
}
void handleinput(void) {
int ch;
ch = getkey();
switch (ch) {
// movement
case 'h':
case 'j':
case 'k':
case 'l':
case 'y':
case 'u':
case 'b':
case 'n':
trymove(player, chartodir(ch));
break;
case 'H':
case 'J':
case 'K':
case 'L':
case 'Y':
case 'U':
case 'B':
case 'N':
tryrun(player, chartodir(ch));
break;
case '.': // wait
dowait(player);
break;
// testing
case '1':
msg("Something happens.");
msg("Something else happens.");
msg("Another thing is about to happen now.");
msg("Too many things are happening!");
break;
// player commands
case 'i': // inventory
doinventory(player->pack);
break;
case '\\': // list knowledge
doknowledgelist();
break;
// object functions
case 'd': // drop
dodrop(player->pack);
break;
case 'W': // wear
dowear(player->pack);
break;
case 'w': // weild
doweild(player->pack);
break;
case 'T': // takeoff
dotakeoff(player->pack);
break;
case ',': // pickup
dopickup(player->cell->obpile);
break;
case 'r': // read
doread(player->pack);
break;
case 'q': // quaff
doquaff(player->pack);
break;
case 't': // throw
dothrow(player->pack);
break;
// GAME FUNCTIONS
case 'S': // save + quit
if (savegame()) {
msg("Save failed.");
drawmsg();
} else {
msg("Saved successfully. See you later...");
more();
drawmsg();
exit(0);
}
break;
}
}
int keycodetokey(int keycode) {
int keystroke = 0;
if (keycode == -1) return -1;
if (keycode == 27) { // an esc sequence
keycode=getch();
keystroke=keycode;
keycode=getch();
keystroke=keystroke | (keycode<<8);
keycode=getch();
keystroke=keystroke | (keycode<<16);
} else {
// regular keypress
return (int)keycode;
}
return keystroke;
}
int pickup(lifeform_t *lf, object_t *what, int howmany) {
char buf[BUFLEN];
char obname[BUFLEN];
object_t *o;
flag_t *f;
if (!what) {
return B_TRUE;
}
getobname(what, obname, howmany);
if (howmany == ALL) howmany = o->amt;
if (!canpickup(lf, what)){
// tell the player why!
if (lf->controller == C_PLAYER) {
switch (reason) {
case E_NOSPACE:
msg("Your pack is too full to fit any more objects.");
break;
default:
msg("For some reason, you cannot pick up %s!",obname);
break;
}
}
return B_TRUE;
}
// some checks first...
f = hasflag(what->flags, F_SHARP);
if (f) {
object_t *gloves;
gloves = getequippedob(lf->pack, BP_HANDS);
if (!gloves) {
char *newname;
getobname(what, buf, 1);
newname = strdup(buf);
strrep(newname, "a ", "the ");
if (lf->controller == C_PLAYER) {
msg("Ow! You cut your finger on %s.", newname);
}
taketime(lf, SPEED_PICKUP);
sprintf(buf, "stepping on %s", obname);
losehp(lf, rnd(1,2), DT_SLASH, NULL, buf);
return B_TRUE;
free(newname);
}
}
// try to move whatever was selected
o = moveob(what, lf->pack, howmany);
if (o) { // if pickup was successful...
if (lf->controller == C_PLAYER) {
msg("You pick up %c - %s.",o->letter, obname);
}
/*
taketime(lf, (SPEED_PICKUP * howmany));
*/
taketime(lf, SPEED_PICKUP);
} else {
// tell the player why!
if (lf->controller == C_PLAYER) {
switch (reason) {
case E_NOSPACE:
msg("Your pack is too full to fit any more objects.");
break;
default:
msg("For some reason, you cannot pick up %s!",obname);
break;
}
}
return B_TRUE;
}
return B_FALSE;
}
void dblog(char *format, ... ) {
char buf[HUGEBUFLEN];
va_list args;
char *p;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
/*
if (gamestarted) {
fprintf(logfile, "%s\n", buf);
fflush(logfile);
} else {
printf("%s\n", buf);
fflush(stdout);
}
*/
fprintf(logfile, "%s\n", buf);
fflush(logfile);
}
// force a '--more--' prompt
void more(void) {
msg("^");
drawmsg();
}
void msg(char *format, ... ) {
char buf[BUFLEN];
va_list args;
char *p;
int db = B_FALSE;
va_start(args, format);
vsprintf( buf, format, args );
va_end(args);
if (db) dblog("adding to msgbuf: [%s]",buf);
// Move to just after the last '^' in the message buffer...
p = strrchr(msgbuf, '^');
if (p) {
p++;
} else {
p = msgbuf;
}
// ie. can the message buffer fit:
// what is already there + 2 spaces + the new text + '--more--' ?
if (strlen(p) + 2 + strlen(buf) + strlen(MORESTRING) >= SCREENW) {
strcat(msgbuf, "^");
} else {
if (strlen(msgbuf) > 0) {
strcat(msgbuf, " ");
}
}
strcat(msgbuf, buf);
if (db) dblog(" msgbuf is now: [%s]",msgbuf);
}
void drawstatus(void) {
char buf[BUFLEN];
wclear(statwin);
sprintf(buf, "[%-12s] HP: %d/%d","Player", player->hp,player->maxhp);
mvwprintw(statwin, 0, 0, buf);
//redraw();
}
void drawmsg(void) {
char *tok,*nexttok;
int db = B_FALSE;
// no messages to display?
if (!strcmp(msgbuf, "")) {
return;
}
// TODO: if it's a monster's turn, always do a more?
nexttok = strstr(msgbuf, "^");
if (!nexttok) {
// just update msg with current text
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", msgbuf);
wrefresh(msgwin);
} else {
while (nexttok) {
char thistok[BUFLEN];
int thistoklen;
// print up to just before the "^" current token
// remember this token
thistoklen = nexttok - msgbuf;
strncpy(thistok, msgbuf, thistoklen);
thistok[thistoklen] = '\0';
if (db) dblog("drawmsg: thistok is [%s]",thistok);
// is there another token?
nexttok = strstr(msgbuf, "^");
if (nexttok) {
char *p;
nexttok++; // go forward past the ^
if (db) dblog("drawmsg: nexttok is [%s]",nexttok);
// print with '--more--' added to the end
if (db) dblog("drawmsg: displaying thistok [%s]",thistok);
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s%s", thistok,MORESTRING);
wrefresh(msgwin);
// ...wait for spacebar before showing next bit...
while (getch() != ' ');
if (db) dblog("prompting for --more--");
// now clear msgstring up to end of where
// 'thistok' appears!
strcpy(msgbuf, nexttok);
if (db) dblog(" reduced msgbuf to: [%s]",msgbuf);
} else {
if (db) dblog("drawmsg: no nexttok");
// just print this bit
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", thistok);
wrefresh(msgwin);
}
}
}
// clear message buffer
if (isplayerturn()) {
strcpy(msgbuf, "");
if (db) dblog("clearing msg buf");
}
}
void redraw(void) {
//wrefresh(msgwin);
wrefresh(statwin);
wrefresh(gamewin);
}
int savegame(void) {
map_t *m;
FILE *f;
char buf[BUFLEN];
int rv;
for (m = firstmap; m ; m = m->next) {
// save world
rv = savemap(m);
if (rv) {
msg("Could not save map '%s'",m->name);
return B_TRUE;
}
// save player + their objects
sprintf(buf, "%s/game.sav",SAVEDIR);
f = fopen(buf, "wt");
if (!f) {
msg("Could not open save file!");
return B_TRUE;
}
savelf(f, player);
saveknowledge(f);
fclose(f);
}
return B_FALSE;
}
int takeoff(lifeform_t *lf, object_t *o) {
flag_t *f;
char obname[BUFLEN];
char buf[BUFLEN];
getobname(o, obname, 1);
if (!cantakeoff(lf, o)) {
switch (reason) {
case E_NOTEQUIPPED:
if (lf->controller == C_PLAYER) {
msg("You are not wearing that!");
}
break;
default:
if (lf->controller == C_PLAYER) {
msg("For some reason, you cannot take that off!");
}
break;
}
return B_TRUE;
}
// remove the equipped flag
f = hasflag(o->flags, F_EQUIPPED);
killflag(f);
taketime(lf, getmovespeed(lf));
if (gamestarted) {
if (lf->controller == C_PLAYER) {
msg("You take off %s.", obname);
} else if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(buf);
msg("%s takes off %s.", buf, obname);
}
}
return B_FALSE;
}
void tombstone(lifeform_t *lf) {
// clear screen
wclear(mainwin);
centre(mainwin, 1, "R.I.P.\n");
//printf("%s\n",lf->name);
centre(mainwin, 2, "Player\n");// TODO: use player name here
centre(mainwin, 3, "Killed by %s.\n",lf->lastdam);
wrefresh(mainwin);
// wait for key...
getch();
// close down graphics ready to quit
// clear windows
delwin(gamewin);
delwin(statwin);
delwin(msgwin);
// clear screen
wclear(mainwin);
// close down curses
curs_set(1);
endwin();
}
int wear(lifeform_t *lf, object_t *o) {
int rv = B_FALSE;
char buf[BUFLEN],obname[BUFLEN];
flag_t *f;
int bp;
getobname(o, obname, 1);
if (!canwear(lf, o)) {
if (gamestarted) {
switch (reason) {
case E_ALREADYUSING:
if (lf->controller == C_PLAYER) {
msg("You're already wearing that!");
}
break;
case E_WEARINGSOMETHINGELSE:
f = hasflag(o->flags, F_GOESON);
if (f) {
object_t *inway;
// find what else is there
inway = getequippedob(lf->pack, f->val[0]);
getobname(inway,buf, 1);
if (lf->controller == C_PLAYER) {
msg("You need to remove your %s first!",buf);
}
} else {
// should never happen
msg("You can't wear that!");
}
break;
default:
if (lf->controller == C_PLAYER) {
msg("You can't wear that!");
}
break;
}
} // end if gamestarted
return B_TRUE;
} // end if !canwear
// wear it
f = hasflag(o->flags, F_GOESON);
bp = f->val[0];
addflag(o->flags, F_EQUIPPED, bp, -1, -1, NULL);
taketime(lf, getmovespeed(lf));
if (gamestarted) {
if (lf->controller == C_PLAYER) {
msg("You are now wearing %s.", obname);
} else if (haslos(player, lf->cell)) {
getlfname(lf, buf);
capitalise(lf);
msg("%s puts on %s.", buf, obname);
}
}
return rv;
}
int weild(lifeform_t *lf, object_t *o) {
char buf[BUFLEN];
flag_t *f;
object_t *oo;
if (o) {
getobname(o, buf, o->amt);
}
// TODO: any reason you might not be able to weild it at all?
// ie. too big, already have a cursed one, etc?
if (!canweild(lf, o)) {
if (gamestarted) {
if (lf->controller == C_PLAYER) {
switch (reason) {
case E_ALREADYUSING:
msg("You are already weilding that!");
break;
case E_NOUNARMEDATTACK:
msg("You cannot fight without a weapon!");
break;
default:
msg("For some reason, you cannot pick up %s!",buf);
break;
}
}
}
return B_TRUE;
}
// anything else weilded?
for (oo = lf->pack->first ; oo ; oo = oo->next) {
f = hasflagval(oo->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL);
if (f) {
// unweild it
killflag(f);
}
}
// if we asked to just unweild our weapon, exit now
// with no error.
if (!o) {
if (gamestarted) {
if (lf->controller == C_PLAYER) {
msg("You are now fighting unarmed.");
} else if (haslos(player, lf->cell)) {
char buf2[BUFLEN];
getlfname(lf, buf2);
msg("%s is now fighting unarmed.",buf2);
}
}
return B_FALSE;
}
// now weild this
addflag(o->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL);
taketime(lf, getmovespeed(lf));
if (gamestarted) {
if (lf->controller == C_PLAYER) {
msg("You are now weilding %c - %s.", o->letter, buf);
// warn if it won't do any damage
f = hasflag(o->flags, F_DAM);
if (!f) {
msg("You have a feeling that this weapon will not be very effective...");
}
} else if (haslos(player, lf->cell)) {
char buf2[BUFLEN];
getlfname(lf, buf2);
msg("%s weilds %s.", buf2, buf);
}
}
return B_FALSE;
}