1436 lines
29 KiB
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;
|
|
}
|