nexus/io.c

11845 lines
304 KiB
C

#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <math.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <unistd.h>
#include "ai.h"
#include "attack.h"
#include "defs.h"
#include "flag.h"
#include "god.h"
#include "io.h"
#include "lf.h"
#include "map.h"
#include "move.h"
#include "nexus.h"
#include "objects.h"
#include "text.h"
#include "save.h"
#include "shops.h"
#include "spell.h"
WINDOW *mainwin;
WINDOW *gamewin;
WINDOW *msgwin;
WINDOW *statwin;
int statdirty = B_TRUE;
int inaskcoords = B_FALSE; // are we inside this function?
extern buildingusage_t buildingusage[];
extern int nbuildingusage;
int hascolour = B_TRUE;
int noredraw = B_FALSE;
int escok = B_TRUE;
extern int needredraw;
extern int numdraws;
extern int SCREENW, SCREENH;
extern enum ERROR reason;
extern char msghist[MAXHISTORY][BUFLEN];
extern int nmsghist;
extern void (*precalclos)(lifeform_t *);
extern lifeform_t *godlf[];
extern int ngodlfs;
extern race_t *firstrace;
extern prompt_t prompt;
extern object_t *retobs[MAXPILEOBS+1];
extern int retobscount[MAXPILEOBS+1];
extern int nretobs;
extern FILE *logfile;
extern enum OBCLASS sortorder[];
extern objectclass_t *objectclass;
extern knowledge_t *knowledge;
extern objecttype_t *objecttype;
extern command_t *firstcommand;
extern vault_t *firstvault;
extern skill_t *firstskill;
extern enum GAMEMODE gamemode;
extern long curtime;
char msgbuf[HUGEBUFLEN];
char lastmsgbuf[HUGEBUFLEN];
char prevmsg[HUGEBUFLEN];
int msgmulti = 1;
extern lifeform_t *player;
extern map_t *firstmap;
int gettinginput = B_FALSE;
int viewx = -9999,viewy = -9999;
int vieww,viewh;
int msgmod = B_FALSE;
void addchoice(prompt_t *p, char ch, char *text, char *desc, void *data, char *longdesc) {
assert(p->choice[p->nchoices].text == NULL);
p->choice[p->nchoices].ch = ch;
p->choice[p->nchoices].text = strdup(text);
if (desc) p->choice[p->nchoices].desc = strdup(desc);
else p->choice[p->nchoices].desc = strdup(text);
if (longdesc) p->choice[p->nchoices].longdesc = strdup(longdesc);
else p->choice[p->nchoices].longdesc = strdup("");
p->choice[p->nchoices].data = data;
p->choice[p->nchoices].heading = B_FALSE;
p->choice[p->nchoices].valid = B_TRUE;
p->nchoices++;
}
void addheading(prompt_t *p, char *text) {
p->choice[p->nchoices].ch = '\0';
p->choice[p->nchoices].text = strdup(text);
p->choice[p->nchoices].desc = strdup(text);
p->choice[p->nchoices].data = NULL;
p->choice[p->nchoices].heading = B_TRUE;
p->nchoices++;
}
void addmsghist(char *text) {
char *localtext;
int db = B_FALSE;
localtext = strdup(text);
localtext = strrep(localtext, MORESTRING, "", NULL);
if (nmsghist < MAXHISTORY) {
strcpy(msghist[nmsghist], localtext);
nmsghist++;
if (db) dblog("adding to msg hist: %s",localtext);
} else {
int i;
// shuffle everything up then replace last one
for (i = 0; i < (MAXHISTORY-1); i++) {
strcpy(msghist[i], msghist[i+1]);
}
strcpy(msghist[MAXHISTORY-1], localtext);
if (db) dblog("replacing last msg hist: %s",localtext);
}
free(localtext);
}
void addpromptq(prompt_t *p, char *q) {
if (p->q[p->nqs]) {
free(p->q[p->nqs]);
}
p->q[p->nqs] = strdup(q);
p->nqs++;
}
void anim(cell_t *src, cell_t *dst, char ch, int colour) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int xinc,yinc,dinc;
int i;
int x1,y1;
int x;
int y;
glyph_t gl;
//int maxvisrange;
//int modmaxvisrange;
//int xray = B_FALSE;
//int wentuphill = B_FALSE;
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;
gl.ch = ch;
gl.colour = colour;
// hide cursor
curs_set(0);
for (i = 0; i < numpixels ; i++) {
cell_t *cell;
// get current cell
cell = getcellat(src->map, x, y);
// update screen
if (haslos(player, cell)) {
updateviewfor(cell);
drawlevelfor(player);
// draw char & cursor at its current pos...
drawglyph(&gl, cell->x - viewx, cell->y - viewy);
//mvwprintw(gamewin, cell->y - viewy, cell->x - viewx, "%c", gl.ch);
wmove(gamewin, cell->y - viewy, cell->x - viewx);
wrefresh(gamewin);
usleep(DEF_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;
}
// show cursor
curs_set(1);
needredraw = B_TRUE;
}
void animcells(cell_t *src, cell_t **dst, int ndst, int gradual, char ch, char ch2, int colour) {
glyph_t gl;
int i;
gl.ch = ch;
gl.colour = colour;
// hide cursor
curs_set(0);
for (i = 0; i < ndst; i++) {
int n;
if ((i % 2) == 0) {
gl.ch = ch;
} else {
gl.ch = ch2;
}
if (gradual) {
// update screen each time
updateviewfor(src);
drawlevelfor(player);
}
if (gradual) {
// draw one at a time
for (n = 0; n <= i; n++) {
drawglyph(&gl, dst[n]->x - viewx, dst[n]->y - viewy);
}
} else {
drawglyph(&gl, dst[i]->x - viewx, dst[i]->y - viewy);
}
if (gradual) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
}
if (!gradual) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
// show cursor
curs_set(1);
needredraw = B_TRUE;
}
void animline(cell_t *src, cell_t *dst, int gradual, char ch, char ch2, int colour) {
glyph_t gl;
int i;
cell_t *retcell[MAXRETCELLS];
int ndst;
calcbresnham(src->map, src->x, src->y, dst->x, dst->y, retcell, &ndst);
gl.ch = ch;
gl.colour = colour;
// hide cursor
curs_set(0);
for (i = 0; i < ndst; i++) {
int n;
if ((i % 2) == 0) {
gl.ch = ch;
} else {
gl.ch = ch2;
}
if (gradual) {
// update screen each time
updateviewfor(src);
drawlevelfor(player);
}
if (gradual) {
// draw one at a time
for (n = 0; n <= i; n++) {
drawglyph(&gl, retcell[n]->x - viewx, retcell[n]->y - viewy);
}
} else {
drawglyph(&gl, retcell[i]->x - viewx, retcell[i]->y - viewy);
}
if (gradual) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
}
if (!gradual) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
// show cursor
curs_set(1);
needredraw = B_TRUE;
}
void animradial(cell_t *src, int radius, int ch,int colour, int dirtype, char *seetext, char *noseetext) {
glyph_t gl;
int i;
int x,y;
int nseen = 0;
cell_t *c;
gl.ch = ch;
gl.colour = colour;
// update screen
updateviewfor(src);
drawlevelfor(player);
// hide cursor
curs_set(0);
if (dirtype == DT_ORTH) {
for (i = 0; i <= radius; i++) {
int drawn = B_FALSE;
for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) {
c = getcellat(src->map, x, y);
if (c && haslos(player, c) && (getcelldistorth(src, c) <= i)) {
// draw char & cursor at its current pos...
//mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch);
drawglyph(&gl, c->x - viewx, c->y - viewy);
drawn = B_TRUE;
nseen++;
}
}
}
if (drawn) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
}
} else { // radial
for (i = 0; i <= radius; i++) {
int drawn = B_FALSE;
for (y = src->y - radius ; y <= src->y + radius ; y++) {
for (x = src->x - radius ; x <= src->x + radius ; x++) {
c = getcellat(src->map, x, y);
if (c && haslos(player, c) && (getcelldist(src, c) <= i)) {
// draw char & cursor at its current pos...
//mvwprintw(gamewin, c->y - viewy, c->x - viewx, "%c", ch);
drawglyph(&gl, c->x - viewx, c->y - viewy);
drawn = B_TRUE;
nseen++;
}
}
}
if (drawn) {
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
}
}
}
if (nseen) {
if (seetext && haslos(player, src)) {
msg(seetext);
more();
} else if (noseetext) {
msg(noseetext);
more();
}
}
// show cursor
curs_set(1);
needredraw = B_TRUE;
drawscreen();
}
// bolt from the sky
void animsky(cell_t *src, char ch, int colour) {
glyph_t gl;
int y;
if (!haslos(player, src)) {
return;
}
gl.ch = ch;
gl.colour = colour;
// hide cursor
curs_set(0);
// update viewpoint
updateviewfor(src);
drawlevelfor(player);
// draw bolt coming down
for (y = 0; y <= src->y - viewy; y++) {
drawglyph(&gl, src->x - viewx, y);
}
wrefresh(gamewin);
usleep(DEF_ANIMDELAY);
// show cursor
curs_set(1);
needredraw = B_TRUE;
}
char askchar(char *prompt, char *validchars, char *def, int showchars, int maycancel) {
char buf[BUFLEN];
char msghistbuf[BUFLEN];
char *p;
char temp[2];
char ch;
int valid = B_FALSE;
more();
wclear(msgwin);
if (showchars) {
snprintf(buf, BUFLEN, "%s (",prompt);
for (p = validchars ; *p ; ) {
temp[0] = *p;
temp[1] = '\0';
strcat(buf, temp);
p++;
if (*p) {
strcat(buf, "/");
}
}
strcat(buf, ")");
} else {
snprintf(buf, BUFLEN, "%s",prompt);
}
if (def) {
strcat(buf, " [");
strcat(buf, def);
strcat(buf, "]");
}
strcat(buf, "? ");
mvwprintw(msgwin, 0, 0, buf);
wrefresh(msgwin);
curs_set(1);
valid = B_FALSE;
while (!valid) {
ch = getkey(B_FALSE);
if ((ch == 27) && maycancel) {
ch = '\0';
valid = B_TRUE;
} else if (strchr(validchars, ch)) {
valid = B_TRUE;
} else if ((ch == 10) && def) { // enter = default
valid = B_TRUE;
} else {
valid = B_FALSE;
}
}
curs_set(0);
// update messaage history
sprintf(msghistbuf, "%s%c", buf, (ch == '\0') ? '-' : ch);
addmsghist(msghistbuf);
clearmsg();
if ((ch == 10) && def) {
return def[0];
}
return ch;
}
// "func" is a pointer to a function which returns an added description for a highlighted cell
cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE LOFTYPE, int wanttrail) {
static int startlf = -1;
int finished = B_FALSE;
int moved = B_FALSE;
cell_t *c,*newcell;
char buf[BUFLEN];
cell_t *target[MAX_MAPW*MAX_MAPH];
int ntargets = 0,curtarget = -1;
int x,y;
enum ATTRBRACKET iqb;
int nretflags;
flag_t *retflag[MAXCANDIDATES];
// rememebr that we're in this function. the main use for this is to ensure
// that when adding a fake corpse for lfs who are feigning death, that we don't
// do a screen update (due to adding an object in sight of the player)
inaskcoords = B_TRUE;
iqb = getattrbracket(getattr(player, A_IQ), A_IQ, NULL);
// remember previously targetted lifeforms
if (startlf > 0) {
if (!findlf(player->cell->map, startlf)) {
startlf = -1;
}
}
// build list of targets if required
if (targettype != TT_NONE) {
for (y = 0; y < player->cell->map->h; y++) {
for (x = 0; x < player->cell->map->w; x++) {
c = getcellat(player->cell->map, x, y);
if (c && haslos(player, c)) {
int valid = B_FALSE;
if ((targettype & TT_MONSTER) && haslf(c) && cansee(player, c->lf) && (c->lf->controller != C_PLAYER)) {
valid = B_TRUE;
}
if ((targettype & TT_ALLY) && haslf(c) && cansee(player, c->lf) && areallies(c->lf, player)) {
valid = B_TRUE;
}
if ((targettype & TT_PLAYER) && haslf(c) && cansee(player, c->lf) && isplayer(c->lf)) {
valid = B_TRUE;
}
if ((targettype & TT_OBJECT) && hasknownobject(c)) {
valid = B_TRUE;
}
if (targettype & TT_IMPASSABLE) {
object_t *o;
for (o = c->obpile->first ; o ; o = o->next) {
if (isimpassableob(o, player)) {
valid = B_TRUE;
break;
}
}
}
if (targettype & TT_DOOR) {
object_t *o;
o = hasobwithflag(c->obpile, F_DOOR);
if (o && !hasflag(o->flags, F_SECRET)) {
valid = B_TRUE;
}
}
if (valid) {
target[ntargets] = c;
if (curtarget == -1) curtarget = ntargets;
ntargets++;
}
}
}
}
}
// start prompting
if (curtarget == -1) {
c = player->cell;
} else {
int i;
// override curtarget based on previous target
for (i = 0; i < ntargets; i++) {
if (target[i]->lf && (target[i]->lf->id == startlf)) {
curtarget = i;
break;
}
}
c = target[curtarget];
}
// only show the question if we don't have a starting target
if (c == player->cell) {
wclear(msgwin);
mvwprintw(msgwin, 0, 0, "%s", prompt);
wrefresh(msgwin);
} else {
// force cell description to show
moved = B_TRUE;
}
while (!finished) {
int dir;
char ch;
int valid = B_TRUE;
drawstatus();
updateviewfor(c);
drawlevelfor(player);
if (moved) {
flag_t *f;
int inlof = B_TRUE, inrange = B_TRUE;
cell_t *trailtarg = NULL;
// show what we are over in msg bar
strcpy(buf, "");
// can we see the cell?
if (haslos(player, c)) {
int i;
if (c->lf) {
if (cansee(player, c->lf)) {
flag_t *f;
object_t *wep,*o;
char extrainfo[BIGBUFLEN];
strcpy(extrainfo, "");
getlfnamea(c->lf, buf);
if (lfhasflag(c->lf, F_NAME)) {
job_t *j;
// add on their job
j = getjob(c->lf);
if (j) {
strcat(buf, " the ");
strcat(buf, j->name);
}
} else if (c->lf->race->raceclass->id == RC_GOD) {
f = lfhasflag(c->lf, F_GODOF);
if (f->val[0] == B_FEMALE) {
strcat(buf, " the goddess of ");
} else {
strcat(buf, " the god of ");
}
strcat(buf, f->text);
}
// level
/*
if (lfhasflag(player, f_extrainfo) || lfhasflag(player, F_OMNIPOTENT)) {
snprintf(extrainfo, BUFLEN, "level %d, ",c->lf->level);
}
*/
switch (getallegiance(c->lf)) {
case AL_FRIENDLY:
if (!isplayer(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
if (lfhasflagval(c->lf, F_PETOF, player->id, NA, NA, NULL)) {
if (getraceclass(c->lf) == RC_ANIMAL) {
strcat(extrainfo, "pet");
} else {
strcat(extrainfo, "ally");
}
} else {
strcat(extrainfo, "friendly");
}
}
break;
case AL_PEACEFUL:
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "peaceful");
break;
case AL_HOSTILE:
break;
}
// need a certain amount of iq to recognise drunkenness
f = lfhasflag(c->lf, F_DRUNK);
if (f && (iqb >= AT_LTAVERAGE)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, getdrunktext(f));
}
if (isfleeing(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "fleeing");
}
f = lfhasflag(c->lf, F_ASLEEP);
if (f) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
if (f->val[1] == ST_MEDITATING) {
strcat(extrainfo, "meditating");
} else if (f->val[1] == ST_KO) {
strcat(extrainfo, "unconscious");
} else if (f->val[2] == NA) {
strcat(extrainfo, "sleeping");
} else {
strcat(extrainfo, "resting");
}
} else if (lfhasflag(c->lf, F_PRONE)) {
// prevent showing 'prone' and 'asleep'
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "prone");
} else if (isairborne(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
if (lfhasflag(c->lf, F_FLYING)) {
strcat(extrainfo, "flying");
} else if (lfhasflag(c->lf, F_LEVITATING)) {
strcat(extrainfo, "levitating");
} else {
strcat(extrainfo, "airbourne");
}
} else {
if (isswimming(c->lf)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "swimming");
}
}
if (lfhasflag(c->lf, F_CLIMBING)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "climbing ");
strcat(extrainfo, c->type->name);
}
f = lfhasflag(c->lf, F_ATTACHEDTO);
if (lfhasflag(c->lf, F_ATTACHEDTO)) {
lifeform_t *alf;
alf = findlf(c->map, f->val[0]);
if (alf) {
char alfname[BUFLEN];
char buf2[BUFLEN];
getlfname(alf, alfname);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
snprintf(buf2, BUFLEN, "attached to %s",alfname);
strcat(extrainfo, buf2);
}
}
o = isstuck(c->lf);
if (o) {
char obname[BUFLEN];
char buf2[BUFLEN];
real_getobname(o, obname, o->amt, B_FALSE, B_FALSE, B_TRUE, B_FALSE, B_FALSE);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
snprintf(buf2, BUFLEN, "stuck in %s",obname);
strcat(extrainfo, buf2);
}
if ((getallegiance(c->lf) == AL_HOSTILE) &&
(getlorelevel(player, c->lf->race->raceclass->id) >= PR_ADEPT)) {
char dangerbuf[BUFLEN];
float rating;
rating = comparelfs(player, c->lf);
if (rating >= 4) {
snprintf(dangerbuf, BUFLEN, "trivial");
} else if (rating >= 3) {
snprintf(dangerbuf, BUFLEN, "very easy");
} else if (rating >= 2) {
snprintf(dangerbuf, BUFLEN, "easy");
} else if (rating >= 1) {
snprintf(dangerbuf, BUFLEN, "average");
} else if (rating >= 0.5) {
snprintf(dangerbuf, BUFLEN, "challenging");
} else if (rating >= 0.25) {
snprintf(dangerbuf, BUFLEN, "formidable");
} else if (rating >= 0.125) {
snprintf(dangerbuf, BUFLEN, "dangerous");
} else {
snprintf(dangerbuf, BUFLEN, "very dangerous");
}
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, dangerbuf);
}
// hp
if (!isplayer(c->lf)) {
if (isgenius(player) || (getseenlfconditioncutoff(player) == C_HEALTHY) ||
(getlorelevel(player, c->lf->race->raceclass->id) >= PR_SKILLED)
) {
char buf2[BUFLEN];
// show actual hp
snprintf(buf2, BUFLEN, "hp %d/%d",c->lf->hp, c->lf->maxhp);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
} else {
char buf2[BUFLEN];
// show condition name
snprintf(buf2, BUFLEN, "%s",getseenlfconditionname(c->lf, player));
if (strlen(buf2)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
}
}
if (lfhasflag(c->lf, F_HOLYAURA)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "holyaura");
}
if (lfhasflag(c->lf, F_RAGE)) {
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, "enraged");
}
getflags(c->lf->flags, retflag, &nretflags, F_RETALIATE, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, f->text);
}
wep = getweapon(c->lf);
if (wep && (c->lf->race->id != R_DANCINGWEAPON)) {
object_t *secwep;
char obname[BUFLEN];
char buf2[BUFLEN];
getobname(wep, obname, wep->amt);
snprintf(buf2, BUFLEN, "weilding %s",obname);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
secwep = getequippedob(c->lf->pack, BP_SECWEAPON);
if (secwep && (secwep != wep)) {
getobname(secwep, obname, secwep->amt);
strcat(buf2, " and ");
strcat(buf2, obname);
}
strcat(extrainfo, buf2);
} else {
wep = getequippedob(c->lf->pack, BP_SECWEAPON);
if (wep) {
char obname[BUFLEN];
char buf2[BUFLEN];
getobname(wep, obname, wep->amt);
snprintf(buf2, BUFLEN, "weilding %s",obname);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
}
f = lfhasflag(c->lf, F_GRABBING);
if (f) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
char lfname2[BUFLEN];
char buf2[BUFLEN];
getlfnamea(lf2, lfname2);
snprintf(buf2, BUFLEN, "holding %s",lfname2);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
}
f = lfhasflag(c->lf, F_GRABBEDBY);
if (f) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
char lfname2[BUFLEN];
char buf2[BUFLEN];
getlfnamea(lf2, lfname2);
snprintf(buf2, BUFLEN, "held by %s",lfname2);
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
}
if (c->lf->facing != D_ALL) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, "facing %s",getdirnameshort(c->lf->facing));
if (strlen(extrainfo)) strcat(extrainfo, ", ");
strcat(extrainfo, buf2);
}
// show iextra info if lf isn't feigning death
if (strlen(extrainfo) && !lfhasflag(c->lf, F_FEIGNINGDEATH)) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, " [%s]",extrainfo);
strcat(buf, buf2);
}
} else {
void *thing;
// lf there but can't see it
if (isinscanrange(c, &thing, buf, NULL) == TT_MONSTER) {
// if scanned, show it.
} else {
// otherwise, show objects
// find top object name
gettopobname(c, buf);
}
}
} else {
// find top object name
gettopobname(c, buf);
}
} else {
// can't see this cell
void *thing;
char desc[BUFLEN];
switch (isinscanrange(c, &thing, desc, NULL)) {
case TT_MONSTER:
case TT_OBJECT:
strcpy(buf, desc);
break;
default:
break;
}
}
// dont use msg() to avoid 'more's
capitalise(buf);
if (srclf && (maxrange != UNLIMITED)) {
if (getcelldist(srclf->cell, c) > maxrange) {
inrange = B_FALSE;
strcat(buf, " ^R[too-far]^n");
valid = B_FALSE;
}
}
trailtarg = c;
if (LOFTYPE != LOF_DONTNEED) {
cell_t *newcell;
int bad = B_FALSE;
if (srclf) {
if (!haslof_real(srclf->cell, c, LOFTYPE, &newcell, srclf)) {
bad = B_TRUE;
}
} else {
if (!haslof(srclf->cell, c, LOFTYPE, &newcell)) {
bad = B_TRUE;
}
}
if (bad) {
inlof = B_FALSE;
strcat(buf, " ^B[no-lof]^n");
valid = B_FALSE;
if (newcell) trailtarg = newcell;
}
}
// throwing hitchance?
f = lfhasflag(player, F_THROWING);
if (f && valid) {
char throwbuf[BUFLEN];
makethrowaccstring(player, c, f, throwbuf);
if (strlen(throwbuf)) {
strcat(buf, throwbuf);
}
}
wclear(msgwin);
if (subprompt) {
char fullline[BUFLEN];
wmove(msgwin, 0, 0);
sprintf(fullline, "%s%s", subprompt, buf);
textwithcol(msgwin, fullline);
} else {
wmove(msgwin, 0, 0);
textwithcol(msgwin, buf);
}
wrefresh(msgwin);
// show our line of fire
if (wanttrail && inrange) {
cell_t *retcell[MAXRETCELLS];
int nretcell,i;
glyph_t screenglyph;
// calc path
calcbresnham(srclf->cell->map, srclf->cell->x, srclf->cell->y, trailtarg->x, trailtarg->y, retcell, &nretcell);
for (i = 0; i < nretcell; i++) {
int thisx,thisy;
thisx = retcell[i]->x - viewx;
thisy = retcell[i]->y - viewy;
// get screen cell;
screenglyph.ch = mvwinch(gamewin, thisy, thisx) & A_CHARTEXT;
screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, thisy, thisx) & A_COLOR);
// draw it inverse.
setcol(gamewin, screenglyph.colour);
wattron(gamewin, A_REVERSE);
mvwprintw(gamewin, thisy, thisx, "%lc", screenglyph.ch);
wattroff(gamewin, A_REVERSE);
unsetcol(gamewin, screenglyph.colour);
}
}
}
// move cursor selected position
wmove(gamewin, c->y - viewy, c->x - viewx);
curs_set(1);
redraw();
// get input
ch = getch();
if (valid && ((ch == '.') || (ch == 10))) { // 10 = enter
clearmsg();
// remember this target
if (c->lf && cansee(player, c->lf)) {
startlf = c->lf->id;
}
restoregamewindows();
inaskcoords = B_FALSE;
return c;
} else if (ch == 'v') { // view
// todo: show obpile or view lf
if (c->lf && cansee(player, c->lf) && (isplayer(c->lf) || !lfhasflag(c->lf, F_FEIGNINGDEATH))) {
showlfstats(c->lf, B_FALSE);
} else if (haslos(player, c)) {
object_t *o,*tempob = NULL;
// lf feigning death here? put down a fake corpse.
if (c->lf && lfhasflag(c->lf, F_FEIGNINGDEATH) && !isplayer(c->lf)) {
char obname[BUFLEN];
sprintf(obname, "%s corpse", c->lf->race->name);
tempob = addob(c->obpile, obname);
}
// show objects
o = doaskobject(c->obpile, "Describe which object", NULL, B_TRUE, B_FALSE, B_FALSE, '\0', AO_NONE, F_NONE);
while (o) {
describeob(o);
o = doaskobject(c->obpile, "Describe which object", NULL, B_FALSE, B_FALSE, '\0', AO_NONE, F_NONE);
}
if (tempob) killob(tempob);
}
} else if (ch == 27) { // esc - cancel
finished = B_TRUE;
} else if ((ch == '\'') && (ntargets > 0)) { // cycle targets
if (curtarget != -1) { // -1 means no targets
curtarget++;
if (curtarget >= ntargets) curtarget = 0;
c = target[curtarget];
moved = B_TRUE;
}
} else {
dir = chartodir(ch);
if (dir != D_NONE) {
newcell = getcellindir(c, dir);
if (newcell) {
c = newcell;
moved = B_TRUE;
}
}
}
}
inaskcoords = B_FALSE;
clearmsg();
restoregamewindows();
return NULL;
}
// retbuf must already be allocated
// "def" is optional
char *askstring(char *prompt, char punc, char *retbuf, int retBUFLEN, char *def) {
char buf[BUFLEN],msghistbuf[BUFLEN];
char *ending;
more();
wclear(msgwin);
snprintf(buf, BUFLEN, "%s",prompt);
if (def) {
strcat(buf, " [");
strcat(buf, def);
strcat(buf, "]");
}
curs_set(1);
asprintf(&ending, "%c ",punc);
strcat(buf, ending);
free(ending);
mvwprintw(msgwin, 0, 0, buf);
wrefresh(msgwin);
echo();
wgetnstr(msgwin, retbuf, retBUFLEN);
noecho();
clearmsg();
if (def && (strlen(retbuf) == 0)) {
strcpy(retbuf, def);
}
snprintf(msghistbuf, BUFLEN, "%s%s",buf,retbuf);
addmsghist(msghistbuf);
drawcursor();
return retbuf;
}
void announcearrival(lifeform_t *lf, map_t *newmap) {
if (isplayer(lf)) {
if (newmap->region == RG_WORLDMAP) {
if (lf->cell->map->region == RG_WORLDMAP) {
msg("You arrive in a new area.");
} else {
msg("You arrive at the surface.");
}
} else {
flag_t *f;
switch (newmap->habitat->id) {
case H_DUNGEON:
msg("You arrive %sat dungeon level %d.",
(newmap->lastplayervisit == -1) ? "" : "back ",
newmap->depth);
break;
case H_SWAMP:
msg("You arrive %sat a swamp.",
(newmap->lastplayervisit == -1) ? "" : "back ");
break;
case H_SEWER:
msg("You find yourself in a sewer.");
break;
case H_STOMACH:
f = hasflag(newmap->flags, F_STOMACHOF);
if (f) {
msg("You find yourself inside the stomach of %s!", f->text);
}
break;
default:
break;
}
}
}
}
int announceflaggain(lifeform_t *lf, flag_t *f) {
int donesomething = B_FALSE;
lifeform_t *lf2;
char lfname[BUFLEN];
char buf[BUFLEN];
char *buf2;
char *p;
if (player && isdead(player)) {
return B_FALSE;
}
if (!lf->born && !isplayer(lf)) {
return B_FALSE;
}
if (lf->race->id == R_DANCINGWEAPON) {
return B_FALSE;
}
getlfname(lf, lfname);
if (isdead(player)) return B_FALSE;
// player can't see this?
// we need to check "!isplayer(lf)" as well, otherwise
// we'll get no announcement when the player turns
// invisible and doesn't have see invisible.
if (!isplayer(lf) && !cansee(player, lf)) {
// another exception - still show when things attach to the player, even if
// the player can't see them.
if ((f->id == F_ATTACHEDTO) && (f->val[0] == player->id)) {
} else {
return B_FALSE;
}
}
switch (f->id) {
case F_ATTRMOD:
switch (f->val[0]) {
case A_STR:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "weaker" : "stronger");
break;
case A_CHA:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less attractive" : "more attractive");
break;
case A_IQ:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "more stupid" : "smarter");
break;
case A_AGI:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "sluggish" : "more agile");
break;
case A_CON:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "more frail" : "healthier");
break;
case A_WIS:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < 0) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "more foolish" : "wiser");
break;
}
donesomething = B_TRUE;
break;
case F_ATTRSET:
if (f->val[1] != real_getattr(lf, f->val[0], B_TRUE)) {
int myatt;
myatt = real_getattr(lf, f->val[0], B_TRUE);
switch (f->val[0]) {
case A_STR:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "weak" : "strong");
break;
case A_CHA:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "ugly" : "attractive");
break;
case A_IQ:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "stupid" : "smart");
break;
case A_AGI:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "sluggish" : "agile");
break;
case A_CON:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "frail" : "healthy");
break;
case A_WIS:
msg("^%c%s %s %s!",getlfcol(lf, (f->val[1] < myatt) ? CC_BAD : CC_GOOD), lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "foolish" : "wise");
break;
}
}
donesomething = B_TRUE;
break;
case F_MAGICARMOUR:
msg("%s %s forms around %s!",needan(f->text) ? "an" : "a", f->text, lfname);
donesomething = B_TRUE;
break;
case F_MAGICBOOST:
if (isplayer(lf)) {
msg("Your magical ability feels boosted!");
donesomething = B_TRUE;
}
break;
case F_ASLEEP:
if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting, not forced asleep
object_t *restob;
int meditating = B_FALSE;
if (f->val[1] == ST_MEDITATING) meditating = B_TRUE;
restob = getrestob(lf);
if (restob) {
if (restob->type->id == OT_MOTEL) {
msg("You start %s (in your motel room)...",meditating ? "meditating" : "resting");
} else {
char restobname[BUFLEN];
getobname(restob, restobname, 1);
if (restob->pile->owner == lf) {
msg("You start %s (in your %s)...",meditating ? "meditating" : "resting", noprefix(restobname));
} else {
msg("You start %s (in %s)...",meditating ? "meditating" : "resting", restobname);
}
}
} else {
msg("You start %s (on the ground)...", meditating ? "meditating" : "resting" );
}
} else {
if (f->val[1] == ST_ASLEEP) {
msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s");
} else {
msg("%s lose%s consciousness.",lfname, isplayer(lf) ? "" : "s");
}
}
donesomething = B_TRUE;
break;
case F_ATTACHEDTO:
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
msg("^%c%s %s on to %s!",isplayer(lf2) ? 'b' : 'n', lfname, isplayer(lf) ? "latch" : "latches", buf);
donesomething = B_TRUE;
}
break;
case F_BEINGSTONED:
msg("^%c%s begin%s to turn to stone!",isplayer(lf) ? 'b' : 'n', lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_AWARENESS:
if (isplayer(lf)) {
msg("You can suddenly see out the back of your head!");
}
break;
case F_BLIND:
if (isplayer(lf)) {
msg("^wYou cannot see!");
} else {
msg("%s is blinded!",lfname);
}
donesomething = B_TRUE;
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("You can now breath normally underwater.");
donesomething = B_TRUE;
}
break;
case F_CAFFEINATED:
if (isplayer(lf)) {
msg("You feel wide awake!");
donesomething = B_TRUE;
}
break;
case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters get it
objecttype_t *ot;
ot = findot(f->val[0]);
if (ot) {
enum SPELLSCHOOL school;
school = getspellschoolknown(lf, ot->id);
msg("^gYou have learned the %s '%s'.",
(school == SS_MENTAL) ? "psionic power" : "spell", ot->name);
donesomething = B_TRUE;
}
}
break;
case F_CANWILL:
if (isplayer(lf)) { // don't know if monsters get it
objecttype_t *ot;
ot = findot(f->val[0]);
if (ot && (!hasflag(ot->flags, F_NOANNOUNCE))) {
char buf[BUFLEN];
snprintf(buf, BUFLEN, "^gYou have gained the ability '%s'.", ot->name);
/*
if (f->val[2] != NA) {
char turnbuf[BUFLEN];
snprintf(turnbuf, BUFLEN, " (every %d turn%s)",f->val[2], (f->val[2] == 1) ? "" : "s");
strcat(buf, turnbuf);
}
strcat(buf, ".");
*/
msg(buf, ot->name); more();
donesomething = B_TRUE;
}
}
break;
case F_CHARMEDBY:
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
msg("%s %s now under %s%s power!",lfname, is(lf), buf,getpossessive(buf));
donesomething = B_TRUE;
}
break;
case F_CONTROL:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel very in control of yourself.");
donesomething = B_TRUE;
}
break;
case F_CONFUSED:
if (isplayer(lf)) {
msg("^wYou feel woozy...");
} else {
msg("^%c%s looks woozy...", getlfcol(lf, CC_BAD), lfname);
}
donesomething = B_TRUE;
break;
case F_DEAF:
if (isplayer(lf)) {
msg("^wYou cannot hear anything!");
}
donesomething = B_TRUE;
break;
case F_DTIMMUNE:
if (isplayer(lf)) { // don't know if monsters get it
msg("^gYou feel immune to %s!", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_DTRESIST:
if (isplayer(lf)) { // don't know if monsters get it
msg("^gYou feel resistant to %s!", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_DTVULN:
if (isplayer(lf)) { // don't know if monsters get it
msg("^bYou feel vulnerable to %s!", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_DETECTAURAS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel aware of spiritual auras around you.");
donesomething = B_TRUE;
}
break;
case F_DETECTLIFE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now detect nearby lifeforms.");
donesomething = B_TRUE;
}
break;
case F_DETECTOBS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now detect nearby objects.");
donesomething = B_TRUE;
}
break;
case F_DETECTMAGIC:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel sensitive to magical enchantments.");
donesomething = B_TRUE;
}
break;
case F_DETECTMETAL:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now detect nearby metal.");
donesomething = B_TRUE;
}
break;
case F_DODGES:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now dodge attacks.");
donesomething = B_TRUE;
}
break;
case F_HIDING:
if (isplayer(lf)) { // don't know if monsters get it
if (f->val[0] < 0) {
msg("You are now trying to hide.");
} else {
msg("You are now hiding.");
}
donesomething = B_TRUE;
}
break;
case F_ICESLIDE:
msg("Sheets of ice start forming under %s%s feet!",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_INJURY:
if (isplayer(lf) || !lfhasflag(lf, F_FEIGNINGDEATH)) {
p = readuntil(buf, f->text, '^');
msg("^%c%s%s %s!", getlfcol(lf, CC_VBAD), lfname, getpossessive(lfname), buf);
donesomething = B_TRUE;
}
break;
case F_INVISIBLE:
if (isplayer(lf)) {
if (lfhasflag(player, F_SEEINVIS)) {
msg("Your body turns transparent!");
} else {
msg("Your body turns invisible!");
}
donesomething = B_TRUE;
} else {
if (lfhasflag(player, F_SEEINVIS)) {
msg("%s turns transparent!", lfname);
donesomething = B_TRUE;
} else {
msg("%s vanishes!", lfname);
}
}
break;
case F_INVULNERABLE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel invulnerable!");
donesomething = B_TRUE;
}
break;
case F_FLAMMABLELF:
msg("%s %s covered in %s!", lfname, isplayer(lf) ? "are" : "is", f->text);
donesomething = B_TRUE;
break;
case F_FLEEFROM:
// who are they fleeing from?
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
if ((f->lifetime == PERMENANT) || (f->lifetime >= 4)) {
msg("%s turn%s to flee from %s!", lfname, isplayer(lf) ? "" : "s",
(cansee(player, lf2) || isplayer(lf2)) ? buf : "something");
} else { // jsut scared a little bit
msg("%s cower%s away from %s!", lfname, isplayer(lf) ? "" : "s",
(cansee(player, lf2) || isplayer(lf2)) ? buf : "something");
}
}
break;
case F_POISONED:
if (isplayer(lf)) {
if (streq(getpoisondesc(f->val[0]), "Sick")) {
msg("^%cYou have contracted %s.", getlfcol(lf, CC_VBAD), getpoisonname(f->val[0]));
} else {
msg("^%cYou are sick with %s.", getlfcol(lf, CC_VBAD), getpoisonname(f->val[0]));
}
} else {
msg("^%c%s looks very sick.", getlfcol(lf, CC_VBAD), lfname);
}
donesomething = B_TRUE;
break;
case F_ENHANCESEARCH:
if (isplayer(lf)) {
msg("You feel very perceptive!");
}
donesomething = B_TRUE;
break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is enhanced!");
}
donesomething = B_TRUE;
break;
case F_DISEASEIMMUNE:
if (isplayer(lf)) {
msg("Your immune system feels boosted!");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s tipsy.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_EXTRADAM:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel more dangerous!");
donesomething = B_TRUE;
}
break;
case F_EXTRAMP:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your magical power feels boosted!");
donesomething = B_TRUE;
}
break;
case F_EXTRALUCK:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel lucky!");
donesomething = B_TRUE;
}
break;
case F_FASTACT:
msg("%s %s",lfname, isplayer(lf) ? "feel accelerated!" : "looks accelerated!");
donesomething = B_TRUE;
break;
case F_FASTMETAB:
if (isplayer(lf)) { // don't know if monsters get it
msg("^bYou feel ravenous!");
donesomething = B_TRUE;
}
break;
case F_FASTMOVE:
msg("%s %s faster.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_FASTACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "feel faster and quicker!" : "looks faster and quicker.");
donesomething = B_TRUE;
break;
case F_FLYING:
msg("%s begin%s to fly!",lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_FROZEN:
// strip "frozen" out...
buf2 = strdup(lfname);
buf2 = strrep(buf2, "frozen ","",NULL);
msg("%s %s to ice!",lfname, isplayer(lf) ? "turn" : "turns");
donesomething = B_TRUE;
free(buf2);
break;
case F_GRABBEDBY:
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
msg("^%c%s %s %s!",getlfcol(lf, CC_VBAD), buf, isplayer(lf2) ? "grab" : "grabs", lfname);
donesomething = B_TRUE;
}
break;
// don't announce grabbing.
case F_GRAVBOOSTED:
msg("^%c%s %s incredibly heavy all of a sudden!",getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_GRAVLESSENED:
if (isplayer(lf)) {
msg("You feel very light all of a sudden!",lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
}
break;
case F_HOLYAURA:
msg("%s %s surrounded by a holy aura!", lfname, isplayer(lf) ? "are" : "is");
donesomething = B_TRUE;
break;
case F_LEARNBOOST:
if (isplayer(lf)) {
msg("You feel more receptive to new knowledge!");
donesomething = B_TRUE;
}
break;
case F_LEVITATING:
msg("%s begin%s to levitate in the air!",lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_MAGSHIELD:
msg("^%c%s %s surrounded by a magnetic shield!",getlfcol(lf, CC_GOOD), lfname, is(lf));
donesomething = B_TRUE;
break;
case F_MEDITATES:
if (isplayer(lf)) {
msg("You now meditate instead of sleeping.");
donesomething = B_TRUE;
}
break;
case F_NAUSEATED:
if (isplayer(lf)) {
msg("^wYou are nauseated by a disgusting stench!");
donesomething = B_TRUE;
} else {
msg("%s looks very unwell.",lfname);
donesomething = B_TRUE;
}
break;
case F_NONCORPOREAL:
msg("%s%s body becomes insubstantial!",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_PAIN:
msg("^%c%s%s skin erupts in stings and burns!",isplayer(lf) ? 'w' : 'n', lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_PARALYZED:
if (isplayer(lf)) {
msg("^wYou cannot move!");
} else {
msg("%s stops moving!",lfname);
}
donesomething = B_TRUE;
break;
case F_PHOTOMEM:
if (isplayer(lf)) { // don't know if monsters get it
msg("You will no longer forget your surroundings.");
donesomething = B_TRUE;
}
break;
case F_PRODUCESLIGHT:
msg("%s start%s producing light!", lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_RAGE:
msg("%s enter%s a berzerker rage!", lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_REFLECTION:
msg("^%cA negative gravity field forms around %s!",getlfcol(lf, CC_GOOD), lfname);
donesomething = B_TRUE;
break;
case F_RETALIATE:
msg("%s appear%s from %s%s skin.", noprefix(f->text),
(f->text[strlen(f->text)-1] == 's') ? "" : "s",
lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_REGENERATES:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your body's healing rate is enhanced!");
donesomething = B_TRUE;
}
break;
case F_RESISTMAG:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel %simmune to magic.", hasflag_real(lf->flags, F_RESISTMAG, NA, f) ? "more " : "");
donesomething = B_TRUE;
}
break;
case F_RISEASGHOST:
if (isplayer(lf)) { // don't know if monsters get it
msg("You will rise as a ghost after death.");
donesomething = B_TRUE;
}
break;
case F_SEEINVIS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You vision seems enhanced.");
donesomething = B_TRUE;
}
break;
case F_SEEINDARK:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now see in the dark.");
donesomething = B_TRUE;
}
break;
case F_SILENTMOVE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You now move silently.");
donesomething = B_TRUE;
}
break;
case F_SLOWACT:
msg("%s %s",lfname, isplayer(lf) ? "feel sluggish." : "looks sluggish.");
donesomething = B_TRUE;
break;
case F_SLOWMETAB:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your metabolism slows.");
donesomething = B_TRUE;
}
break;
case F_SLOWMOVE:
msg("%s %s slower.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_SLOWACTMOVE:
msg("^%c%s %s",getlfcol(lf, CC_VBAD), lfname, isplayer(lf) ? "feel slow and sluggish." : "looks slow and sluggish.");
donesomething = B_TRUE;
break;
case F_SPIDERCLIMB:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your skin becomes adhesive!");
donesomething = B_TRUE;
}
break;
case F_SPRINTING:
msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts");
donesomething = B_TRUE;
break;
case F_STENCH:
msg("%s start%s emitting a foul odour!",lfname, isplayer(lf) ? "" : "s" );
donesomething = B_TRUE;
break;
case F_STUNNED:
msg("%s %s stunned!",lfname, is(lf));
donesomething = B_TRUE;
break;
case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can now 'see' by sensing vibrations around you.");
donesomething = B_TRUE;
}
break;
case F_TRUESTRIKE:
if (isplayer(lf)) { // don't know if monsters get it
if (f->val[0] > 1) {
msg("Your next %d attacks will automatically hit.", f->val[0]);
} else {
msg("Your next attack will automatically hit.");
}
donesomething = B_TRUE;
}
break;
case F_WINDSHIELD:
if (isplayer(lf)) {
msg("^gYou are surrounded by a whirling cyclone!");
} else if (cansee(player, lf)) {
msg("%s is surrounded by a whirling cyclone!",lfname);
}
break;
case F_VISRANGEMOD:
if (isplayer(lf)) { // don't know if monsters get it
char fartext[BUFLEN];
if (f->val[0] > 0) {
int amt;
amt = abs(f->val[0]);
if (amt >= 7) {
strcpy(fartext, "a lot ");
} else if (amt >= 5) {
strcpy(fartext, "");
} else {
strcpy(fartext, "a little ");
}
msg("You can see %sfurther.", fartext);
} else {
int amt;
amt = abs(f->val[0]);
if (amt >= 7) {
msg("Your vision is dramatically reduced.");
} else if (amt >= 5) {
msg("Your vision is reduced.");
} else {
msg("Your vision is slightly reduced.");
}
}
donesomething = B_TRUE;
needredraw = B_TRUE;
}
break;
case F_XRAYVIS:
if (isplayer(lf)) { // don't know if monsters get it
msg("The walls around you suddenly turn transparent!");
needredraw = B_TRUE;
donesomething = B_TRUE;
}
break;
default: // no message
break;
}
if (donesomething) statdirty = B_TRUE;
//if (statdirty || needredraw) {
if (statdirty) {
drawscreen();
}
return donesomething;
}
int announceflagloss(lifeform_t *lf, flag_t *f) {
char lfname[BUFLEN];
char buf[BUFLEN];
lifeform_t *lf2;
int donesomething = B_FALSE;
if (isdead(player)) {
return B_FALSE;
}
if (!lf->born) {
return B_FALSE;
}
if (lf->race->id == R_DANCINGWEAPON) {
return B_FALSE;
}
if (isdead(lf) || isdead(player)) return B_FALSE;
getlfname(lf, lfname);
// player can't see this?
if (!cansee(player, lf) && !isplayer(lf)) {
return B_FALSE;
}
switch (f->id) {
case F_ATTRMOD:
switch (f->val[0]) {
case A_STR:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less strong" : "less weak");
break;
case A_CHA:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less attractive" : "less ugly");
break;
case A_IQ:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less smart" : "less stupid");
break;
case A_AGI:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less agile" : "less sluggish");
break;
case A_CON:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "less frail");
break;
}
donesomething = B_TRUE;
break;
case F_ATTRSET:
if (f->val[1] != real_getattr(lf, f->val[0], B_TRUE)) {
int myatt;
myatt = real_getattr(lf, f->val[0], B_TRUE);
switch (f->val[0]) {
case A_STR:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less strong" : "less weak");
break;
case A_CHA:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less attractive" : "less ugly");
break;
case A_IQ:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less smart" : "less stupid");
break;
case A_AGI:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less agile" : "less sluggish");
break;
case A_CON:
msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "less frail");
break;
}
donesomething = B_TRUE;
}
break;
case F_MAGICARMOUR:
msg("%s%s %s vanishes.",lfname,getpossessive(lfname), f->text);
donesomething = B_TRUE;
break;
case F_MAGICBOOST:
if (isplayer(lf)) {
msg("Your magical ability no longer feels boosted.");
donesomething = B_TRUE;
}
break;
case F_ATTACHEDTO:
lf2 = findlf(NULL, f->val[0]);
if (lf2 && !isdead(lf2)) {
char buf[BUFLEN];
getlfname(lf2, buf);
msg("%s %s %s!",lfname, isplayer(lf) ? "release" : "releases", buf);
donesomething = B_TRUE;
}
break;
case F_ASLEEP:
switch (f->val[1]) {
case ST_ASLEEP:
msg("%s wake%s up.",lfname, isplayer(lf) ? "" : "s");
break;
case ST_MEDITATING:
msg("%s stop%s meditating.",lfname, isplayer(lf) ? "" : "s");
break;
case ST_KO:
msg("%s regain%s consciousness.",lfname, isplayer(lf) ? "" : "s");
break;
}
donesomething = B_TRUE;
break;
case F_BEINGSTONED:
msg("The fragments of stone around %s%s body drop%s away.",lfname, getpossessive(lfname), isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_AWARENESS:
if (isplayer(lf)) {
msg("You can no longer see out the back of your head.");
}
break;
case F_BLIND:
msg("%s can see again.",lfname);
donesomething = B_TRUE;
break;
case F_BREATHWATER:
if (isplayer(lf)) {
msg("%s can no longer breath underwater.",lfname);
donesomething = B_TRUE;
}
break;
case F_CAFFEINATED:
if (isplayer(lf)) {
msg("%s caffeine high has worn off.",lfname);
donesomething = B_TRUE;
}
break;
case F_CANCAST:
if (isplayer(lf)) { // don't know if monsters lose it
objecttype_t *ot;
ot = findot(f->val[0]);
if (ot) {
msg("You have forgotten how to cast '%s'.", ot->name);
donesomething = B_TRUE;
}
}
break;
case F_CANWILL:
if (isplayer(lf)) { // don't know if monsters lose it
objecttype_t *ot;
ot = findot(f->val[0]);
if (ot && (!hasflag(ot->flags, F_NOANNOUNCE))) {
msg("You can no longer use the ability '%s'.", ot->name);
donesomething = B_TRUE;
}
}
break;
case F_CHARMEDBY:
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
char buf[BUFLEN];
getlfname(lf2, buf);
msg("%s break%s free of %s%s control!",lfname, isplayer(lf) ? "" : "s", buf,getpossessive(buf));
if (isplayer(lf2)) {
more();
}
donesomething = B_TRUE;
}
break;
case F_CONTROL:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You feel less controlled.");
donesomething = B_TRUE;
}
break;
case F_CONFUSED:
if (isplayer(lf)) {
msg("You feel more steady now.");
} else {
msg("%s looks more steady.", lfname);
}
donesomething = B_TRUE;
break;
case F_DEAF:
if (isplayer(lf)) {
msg("Your hearing returns.");
}
donesomething = B_TRUE;
break;
case F_DTIMMUNE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer immune to %s.", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_DTRESIST:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer resistant to %s.", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_DTVULN:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer vulnerable to %s.", getdamnamenoun(f->val[0]));
donesomething = B_TRUE;
}
break;
case F_ENHANCESEARCH:
if (isplayer(lf)) {
msg("You no longer feel so perceptive!");
}
donesomething = B_TRUE;
break;
case F_ENHANCESMELL:
if (isplayer(lf)) {
msg("Your sense of smell is no longer enhanced.");
}
donesomething = B_TRUE;
break;
case F_DISEASEIMMUNE:
if (isplayer(lf)) {
msg("Your immune system no longer feels boosted.");
}
donesomething = B_TRUE;
break;
case F_DRUNK:
msg("%s %s more sober now.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_EXTRADAM:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer feel more dangerous.");
donesomething = B_TRUE;
}
break;
case F_EXTRALUCK:
if (isplayer(lf)) { // don't know if monsters get it
msg("You feel less lucky.");
donesomething = B_TRUE;
}
break;
case F_EXTRAMP:
if (isplayer(lf)) { // don't know if monsters get it
msg("Your magical power no longer feels boosted.");
donesomething = B_TRUE;
}
break;
case F_FASTACT:
msg("%s %s",lfname, isplayer(lf) ? "are no longer accelerated." : "is no longer accelerated.");
donesomething = B_TRUE;
break;
case F_FASTMETAB:
case F_SLOWMETAB:
if (isplayer(lf)) { // don't know if monsters lose it
msg("Your metabolic rate has returned to normal.");
donesomething = B_TRUE;
}
break;
case F_FASTMOVE:
msg("%s %s slower.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_FASTACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "slow down back to normal speed." : "slows down to its normal speed.");
donesomething = B_TRUE;
break;
case F_FLAMMABLELF:
msg("%s %s no longer covered in %s.", isplayer(lf) ? "are" : "is", f->text);
donesomething = B_TRUE;
break;
case F_FLEEFROM:
msg("%s stop%s fleeing.", lfname, isplayer(lf) ? "" : "s");
donesomething = B_TRUE;
break;
case F_FRIENDLY:
msg("%s no longer looks quite so friendly!", lfname);
break;
case F_POISONED:
msg("%s %s less sick now.", lfname, isplayer(lf) ? "feel" : "looks");
donesomething = B_TRUE;
break;
case F_DODGES:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You can no longer dodge attacks.");
donesomething = B_TRUE;
}
break;
case F_HIDING:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You are no longer hidden.");
donesomething = B_TRUE;
}
break;
case F_ICESLIDE:
msg("%s%s feet are longer generating ice.",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_INJURY:
strcpy(buf, getinjuredbpname(f->val[1]));
msg("^%c%s%s injured %s has healed.", getlfcol(lf, CC_VGOOD), lfname, getpossessive(lfname), buf);
break;
case F_INVISIBLE:
if (isplayer(lf)) {
msg("Your are no longer invisible.");
donesomething = B_TRUE;
} else {
if (lfhasflag(player, F_SEEINVIS)) {
msg("%s is no longer transparent.", lfname);
donesomething = B_TRUE;
} else {
msg("%s appears out of nowhere!", lfname);
}
}
break;
case F_INVULNERABLE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer feel invulnerable.");
donesomething = B_TRUE;
}
break;
case F_DETECTAURAS:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You can no longer detect auras.");
donesomething = B_TRUE;
}
break;
case F_DETECTLIFE:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can no longer detect nearby lifeforms.");
donesomething = B_TRUE;
}
break;
case F_DETECTOBS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can no longer detect nearby objects.");
donesomething = B_TRUE;
}
break;
case F_DETECTMAGIC:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can no longer detect magical enchantments.");
donesomething = B_TRUE;
}
break;
case F_DETECTMETAL:
if (isplayer(lf)) { // don't know if monsters get it
msg("You can no longer detect nearby metal.");
donesomething = B_TRUE;
}
break;
case F_FLYING:
msg("%s %s flying.", lfname, isplayer(lf) ? "cease" : "stops");
donesomething = B_TRUE;
break;
case F_FROZEN:
if (isplayer(lf)) {
msg("You thaw out.");
} else {
msg("%s thaws out.", lfname);
}
donesomething = B_TRUE;
break;
case F_GRABBEDBY:
lf2 = findlf(NULL, f->val[0]);
if (lf2 && !isdead(lf2)) {
char buf[BUFLEN];
getlfname(lf2, buf);
msg("%s break%s free from %s!",lfname, isplayer(lf) ? "" : "s", buf);
donesomething = B_TRUE;
}
break;
case F_GRAVBOOSTED:
msg("%s %s no longer stuck to the floor.",lfname, is(lf));
donesomething = B_TRUE;
break;
case F_GRAVLESSENED:
if (isplayer(lf)) {
msg("Your weight returns to normal.");
donesomething = B_TRUE;
}
break;
case F_HOLYAURA:
msg("%s%s holy aura vanishes.", lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_LEARNBOOST:
if (isplayer(lf)) {
msg("You no longer feel receptive to new knowledge.");
donesomething = B_TRUE;
}
break;
case F_LEVITATING:
msg("%s %s down to the ground.", lfname, isplayer(lf) ? "float" : "floats");
donesomething = B_TRUE;
break;
case F_MAGSHIELD:
if (isplayer(lf)) { // don't know if monsters lose it
msg("Your magnetic shield vanishes.");
donesomething = B_TRUE;
}
break;
case F_MEDITATES:
if (isplayer(lf)) {
msg("You can no longer meditate instead of sleeping.");
donesomething = B_TRUE;
}
break;
case F_NAUSEATED:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer feel nauseated.");
donesomething = B_TRUE;
}
break;
case F_NONCORPOREAL:
msg("%s%s body solidifies.",lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_PAIN:
if (isplayer(lf)) { // don't konw if it expires for monsters
msg("Your skin stops hurting.");
donesomething = B_TRUE;
}
break;
case F_PARALYZED:
if (isplayer(lf)) { // don't konw if it expires for monsters
msg("You can move again.");
donesomething = B_TRUE;
}
break;
case F_PHOTOMEM:
if (isplayer(lf)) { // don't know if monsters lose it
msg("Your feel like you might forget your surroundings.");
donesomething = B_TRUE;
}
break;
case F_PRODUCESLIGHT:
msg("%s %s no longer producing light.", lfname, is(lf));
donesomething = B_TRUE;
break;
case F_RAGE:
msg("%s %s less angry now.", lfname, isplayer(lf) ? "feel" : "seems");
donesomething = B_TRUE;
break;
case F_REFLECTION:
msg("^%cThe negative gravity around %s vanishes!", lfname);
donesomething = B_TRUE;
break;
case F_RETALIATE:
msg("%s disappear%s from %s%s skin.", noprefix(f->text),
(f->text[strlen(f->text)-1] == 's') ? "" : "s",
lfname, getpossessive(lfname));
donesomething = B_TRUE;
break;
case F_REGENERATES:
if (isplayer(lf)) { // don't know if monsters lose it
msg("Your healing rate is no longer enhanced.");
donesomething = B_TRUE;
}
break;
case F_RESISTMAG:
if (isplayer(lf)) { // don't know if monsters lose it
if (hasflag_real(lf->flags, F_RESISTMAG, NA, f)) {
msg("You feel less immune to magic.");
} else {
msg("You are no longer immune to magic.");
}
donesomething = B_TRUE;
}
break;
/*
case F_RESTCOUNT:
if (isplayer(lf)) {
msg("restcount expired.");
}
break;
*/
case F_RISEASGHOST:
if (isplayer(lf)) { // don't know if monsters get it
msg("You will no longer rise as a ghost after death.");
donesomething = B_TRUE;
}
break;
case F_SEEINVIS:
if (isplayer(lf)) { // don't know if monsters get it
msg("You vision returns to normal.");
donesomething = B_TRUE;
}
break;
case F_SEEINDARK:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You can no longer see in the dark.");
donesomething = B_TRUE;
}
break;
case F_SILENTMOVE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer move silently.");
donesomething = B_TRUE;
}
break;
case F_SLOWACT:
msg("%s %s",lfname, isplayer(lf) ? "no longer feel sluggish." : "no longer looks sluggish.");
donesomething = B_TRUE;
break;
case F_SLOWMOVE:
msg("%s %s faster.",lfname, isplayer(lf) ? "feel yourself moving" : "is now moving");
donesomething = B_TRUE;
break;
case F_SLOWACTMOVE:
msg("%s %s",lfname, isplayer(lf) ? "speed back up." : "speeds back up.");
donesomething = B_TRUE;
break;
case F_SPIDERCLIMB:
if (isplayer(lf)) {
msg("Your skin is no longet adhesive.");
donesomething = B_TRUE;
}
break;
case F_SPRINTING:
if (isplayer(lf)) { // don't know if monsters lose it (but you'll see them get exhausted)
msg("You stop sprinting.");
donesomething = B_TRUE;
}
break;
case F_STENCH:
msg("%s no longer smell%s bad.",lfname, isplayer(lf) ? "" : "s" );
donesomething = B_TRUE;
break;
case F_STUNNED:
msg("%s %s no longer stunned.",lfname, is(lf));
donesomething = B_TRUE;
break;
case F_TREMORSENSE:
if (isplayer(lf)) { // don't know if monsters lose it
msg("You no longer sense vibrations around you.");
donesomething = B_TRUE;
}
break;
case F_TRUESTRIKE:
// no message when you lose this.
break;
case F_WINDSHIELD:
if (isplayer(lf) || cansee(player, lf)) {
msg("%s%s cyclonic shield vanishes.", lfname, getpossessive(lfname));
}
break;
case F_VISRANGEMOD:
if (isplayer(lf)) { // don't know if monsters get it
char fartext[BUFLEN];
if (f->val[0] < 0) {
int amt;
amt = abs(f->val[0]);
if (amt >= 7) {
strcpy(fartext, "a lot ");
} else if (amt >= 5) {
strcpy(fartext, "");
} else {
strcpy(fartext, "a little ");
}
msg("You can see %sfurther.", fartext);
} else {
int amt;
amt = abs(f->val[0]);
if (amt >= 7) {
msg("Your vision is dramatically reduced.");
} else if (amt >= 5) {
msg("Your vision is reduced.");
} else {
msg("Your vision is slightly reduced.");
}
}
donesomething = B_TRUE;
}
break;
case F_XRAYVIS:
if (isplayer(lf)) { // don't know if monsters lose it
msg("The walls around you are no longer transparent.");
donesomething = B_TRUE;
}
break;
default: // no message
break;
}
if (donesomething) statdirty = B_TRUE;
return donesomething;
}
int announceobflaggain(object_t *o, flag_t *f) {
int donesomething = B_FALSE;
char obname[BUFLEN];
char prefix[BUFLEN];
int wantpremods = B_TRUE;
cell_t *loc;
loc = getoblocation(o);
if (isdead(player)) return B_FALSE;
// player can't see?
if (!haslos(player, loc)) {
return B_FALSE;
}
if (f->id == F_ONFIRE) {
// don't want "the flaming sword catches on fire"
wantpremods = B_FALSE;
}
real_getobname(o, obname, o->amt, wantpremods, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
snprintf(prefix, BUFLEN, "Your %s",noprefix(obname));
} else {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
snprintf(prefix, BUFLEN, "%s%s %s",lfname, getpossessive(lfname), noprefix(obname));
}
} else {
snprintf(prefix, BUFLEN, "%s",obname);
}
switch (f->id) {
case F_ONFIRE:
donesomething = B_TRUE;
if (o->birthtime != curtime) msg("%s catch%s on fire.",prefix, OB1(o, "es", ""));
break;
case F_PRODUCESLIGHT:
donesomething = B_TRUE;
if (o->birthtime != curtime) msg("%s start%s glowing!",prefix, OBS1(o));
break;
default: // no message
break;
}
return donesomething;
}
void announceobflagloss(object_t *o, flag_t *f) {
char obname[BUFLEN];
char prefix[BUFLEN];
char isare[BUFLEN];
char *temp;
cell_t *loc;
loc = getoblocation(o);
if (isdead(player)) return;
// player can't see?
if (!haslos(player, loc)) {
return;
}
real_getobname(o, obname, o->amt, B_TRUE, B_FALSE, B_TRUE, B_TRUE, B_FALSE);
if (o->pile->owner) {
if (isplayer(o->pile->owner)) {
snprintf(prefix, BUFLEN, "Your %s",noprefix(obname));
} else {
char lfname[BUFLEN];
getlfname(o->pile->owner, lfname);
snprintf(prefix, BUFLEN, "%s%s %s",lfname, getpossessive(lfname), noprefix(obname));
}
} else {
snprintf(prefix, BUFLEN, "%s",obname);
}
if (o->amt == 1) {
strcpy(isare, "is");
} else {
strcpy(isare, "are");
}
switch (f->id) {
case F_ONFIRE:
// replace "the flaming xxx is no longer on fire"
// with "the xxx is no longer on fire"
temp = strdup(prefix);
temp = strrep(temp, "flaming ","",NULL);
msg("%s %s no longer on fire.",temp,isare);
free(temp);
break;
case F_PRODUCESLIGHT:
msg("%s %s no longer glowing.",prefix,isare);
break;
case F_WET:
msg("%s %s now dry.",prefix, OB1(o,"is","are"));
break;
default: // no message
break;
}
}
int confirm_badfeeling(object_t *o) {
char ch;
ch = askchar("You have a bad feeling about this. Continue?", "yn", "n", B_TRUE, B_FALSE);
if (ch == 'y') return B_TRUE;
return B_FALSE;
}
// returns true if the player wants to continue (or if there is no problem)
int confirm_injury_action(enum BODYPART bp, enum DAMTYPE dt, char *actionname) {
char ques[BUFLEN];
if (hasbleedinginjury(player, bp) && willbleedfrom(player, bp)) {
snprintf(ques, BUFLEN, "Your %s injury will cause damage if you %s - continue?",
getinjuredbpname(bp), actionname);
return warnabout(ques);
}
return B_TRUE;
}
lifeform_t *askgod(char *prompttext, int onlyprayed) {
lifeform_t *lf = NULL;
int i;
char *longdesc;
longdesc = malloc(HUGEBUFLEN * sizeof(char));
initprompt(&prompt, prompttext);
prompt.maycancel = B_TRUE;
for (i = 0 ; i < ngodlfs; i++) {
flag_t *f;
char godof[BUFLEN],buf[BUFLEN];
lf = godlf[i];
if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) {
continue;
}
real_getlfname(lf, buf, B_FALSE);
f = hasflag(lf->flags, F_GODOF);
snprintf(godof, BUFLEN, " (%s of %s)", (f->val[0] == B_FEMALE) ? "goddess" : "god", f->text);
strcat(buf, godof);
makedesc_god(lf, longdesc);
addchoice(&prompt, tolower(buf[0]), buf, NULL, lf, longdesc);
}
free(longdesc);
if (prompt.nchoices == 0) {
msg("You are not worshipping any gods.");
return NULL;
} else if (prompt.nchoices == 1) {
lf = (lifeform_t *)prompt.choice[0].data;
} else {
getchoice(&prompt);
lf = (lifeform_t *)prompt.result;
}
return lf;
}
object_t *askobject(obpile_t *op, char *prompt, int *count, char action, long opts) {
int showlong = B_TRUE;
if (op->owner && isplayer(op->owner)) {
showlong = B_FALSE;
}
return doaskobject(op, prompt, count, showlong, B_TRUE, B_FALSE, action, opts, F_NONE);
}
object_t *askobjectwithflag(obpile_t *op, char *prompt, int *count, char action, long opts, enum FLAG withflag) {
return doaskobject(op, prompt, count, B_TRUE, B_TRUE, B_FALSE, action, opts, withflag, F_NONE);
}
int contains(enum OBCLASS *array, int nargs, enum OBCLASS want) {
int i;
for (i = 0; i < nargs; i++) {
if (array[i] == want) {
return B_TRUE;
}
}
return B_FALSE;
}
void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters, int forpickup, int showpoints) {
int lastclass = OC_NULL;
int i;
int useobletters = B_TRUE;
if (myletters) {
useobletters = B_FALSE;
}
for (i = firstob ; (mylist[i] != NULL) && (*y < lastline); i++) {
char selchar;
char buf[BUFLEN];
char obname[BUFLEN];
char infobuf[BUFLEN];
char equipbuf[BUFLEN];
char pointsbuf[BUFLEN];
if (mylist[i]->type->obclass->id != lastclass) {
// print class heading
wattron(win, A_STANDOUT);
mvwprintw(win, *y, 0, "%s", mylist[i]->type->obclass->name);
(*y)++;
wattroff(win, A_STANDOUT);
lastclass = mylist[i]->type->obclass->id;
}
// print object name
getobname(mylist[i], obname,mylist[i]->amt);
if (sellist && sellist[i]) {
if ((selcount[i] == ALL) || (selcount[i] == mylist[i]->amt)) {
selchar = '*';
} else {
selchar = '#';
}
} else {
selchar = ' ';
}
if (forpickup && hasflag(mylist[i]->flags, F_NOPICKUP)) {
snprintf(buf, BUFLEN, "%c %s", selchar, obname);
} else {
snprintf(buf, BUFLEN, "%c %c - %s", selchar, useobletters ? mylist[i]->letter : myletters[i],
obname);
}
if (showpoints && (mylist[i]->type->id != OT_GOLD)) {
long points;
points = getobpoints(mylist[i]);
snprintf(pointsbuf, BUFLEN, " [%ld points]", points);
} else {
strcpy(pointsbuf, "");
}
setobcolour(win, mylist[i], B_TRUE);
getobextrainfo(mylist[i], infobuf);
getobequipinfo(mylist[i], equipbuf);
mvwprintw(win, *y, 0, "%s%s", buf, infobuf);
setobcolour(win, mylist[i], B_FALSE);
if (strlen(equipbuf)) {
setcol(win, C_BROWN);
wprintw(win, "%s", equipbuf);
unsetcol(win, C_BROWN);
}
if (strlen(pointsbuf)) {
setcol(win, C_WHITE);
wprintw(win, "%s", pointsbuf);
unsetcol(win, C_WHITE);
}
(*y)++;
}
*counter = i;
}
object_t *doaskobject(obpile_t *op, char *prompt, int *count, int showlong, int forpickup, int showpoints, char action, long opts, ...) {
int c,i;
char defchar = '\0';
static char defaults[52] = {'\0'};
static int defaultcounts[52] = { 0 };
object_t *defob = NULL;
int defcount = 0;
object_t *mylist[MAXPILEOBS+1];
char myletters[MAXPILEOBS+1];
char msghistbuf[BUFLEN],numstring[BUFLEN],fullprompt[BUFLEN];
char obname[BUFLEN];
int firstob = 0;
int nextpage = -1;
int lastline = SCREENH-4;
int finished;
char nextlet = 'a';
int useobletters;
//flag_t *f;
enum FLAG wantflag[MAXCANDIDATES];
va_list flags;
int nwantflags;
// construct list of valid obclasses
va_start(flags, opts);
nwantflags = 0;
wantflag[nwantflags] = va_arg(flags, enum FLAG);
while (wantflag[nwantflags] != F_NONE) {
nwantflags++;
wantflag[nwantflags] = va_arg(flags, enum FLAG);
}
va_end(flags);
//dblog("nwantflags is %d",nwantflags);
if (countobs(op, B_TRUE) <= 0) {
// no objects here
cls();
if (op->owner) {
mvwprintw(mainwin, 2, 0, "You have no possessions.");
} else {
mvwprintw(mainwin, 2, 0, "There is nothing here.");
}
// wait for key
centre(mainwin, C_WHITE, getmaxy(mainwin)-1, "[press any key]");
getch();
restoregamewindows();
return NULL;
}
reason = E_OK;
// if picking form a player's pack, use the object's letters.
// otherwise just label them a, b, c, etc.
if (op->owner && isplayer(op->owner)) {
useobletters = B_TRUE;
// cope with defaults...
if (action) {
// find the default obchar for this action
defchar = defaults[action - 'a'];
if (defchar) {
defob = findobl(op, defchar);
}
// got a default?
if (defob) {
defcount = defaultcounts[action - 'a'];
} else {
// remove the default
defaults[action - 'a'] = '\0';
defaultcounts[action - 'a'] = 0;
}
}
} 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)) {
//if (!nwantflags || contains(wantflag, nwantflags, sortorder[c])) {
// add all objects of this class
for (o = op->first ; o ; o = o->next) {
if (o->type->obclass->id == sortorder[c]) {
int ok;
int n;
// can we include this object?
ok = B_TRUE;
if (!canseeob(player, o)) ok = B_FALSE;
if (ok) {
// check for wanted flags
for (n = 0; n < nwantflags; n++) {
if (!hasflag(o->flags, wantflag[n])) {
ok = B_FALSE;
break;
}
}
}
if (ok) {
ok = obmatchescondition(o, opts);
}
if (ok) {
mylist[i] = o;
myletters[i] = nextlet;
if (++nextlet > 'z') nextlet = 'a';
i++;
}
} // end if ob matches sortorder
} // end for each ob
c++;
}
mylist[i] = NULL;
// start displaying from the first one
firstob = 0;
nextpage = -1;
finished = B_FALSE;
strcpy(numstring, "");
while (!finished) {
int y;
int ch;
char fullnumstring[BUFLEN];
char defobstring[BUFLEN];
if (showlong) {
cls();
// list the objects
y = 2;
listobs(mainwin, mylist, NULL, NULL, firstob, &i, lastline, &y, useobletters ? NULL : myletters , forpickup, showpoints);
}
if (mylist[i] == NULL) {
nextpage = -1;
} else {
nextpage = i;
}
// draw prompt
if (strlen(numstring) > 0) {
strcpy(fullnumstring, " [");
strcat(fullnumstring, numstring);
strcat(fullnumstring, "]");
} else {
strcpy(fullnumstring, "");
}
snprintf(fullprompt, BUFLEN, "%s (%sESC=quit%s)%s: ",prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
showlong ? "" : ",?=list",
fullnumstring);
mvwprintw(mainwin, 0, 0, "%s", fullprompt);
if (defob) {
getobname(defob, defobstring, defcount);
} else {
strcpy(defobstring, "");
}
if (strlen(defobstring)) {
int cx,cy;
// remember coords
getyx(mainwin, cy, cx);
wprintw(mainwin, "%s", defobstring);
// restore cursor pos
wmove(mainwin, cy, cx);
}
if (showlong) {
if (nextpage != -1) {
mvwprintw(mainwin, y, 0, MORESTRING);
}
}
// 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, B_TRUE);
// then handle input
if (ch == ' ') { // next page
if (nextpage == -1) { // go to first page
firstob = 0;
} else {
firstob = nextpage;
}
} else if (ch == '?') {
showlong = B_TRUE;
} else if ((ch == '\\') && (gamemode == GM_GAMESTARTED)) {
doknowledgelist();
} else if (isalpha(ch) || (ch == '$') || ((ch == 10) && defob)) { // 27 == enter
object_t *o;
// find that object
if (ch == 10) {
o = defob;
if (count) *count = defcount;
} else {
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) {
if ((*count > o->amt) || (*count == ALL) || (*count == 0)) {
*count = o->amt;
}
}
// display game windows again
clearmsg();
restoregamewindows();
getobname(o, obname, count ? *count : o->amt);
sprintf(msghistbuf, "%s%s",fullprompt,obname);
addmsghist(msghistbuf);
// update default
if (action && o->letter) {
defaults[action - 'a'] = o->letter;
if (count) {
defaultcounts[action - 'a'] = *count;
} else {
defaultcounts[action - 'a'] = 1;
}
}
return o;
}
} else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing
reason = E_SELNOTHING;
// display game windows again
restoregamewindows();
sprintf(msghistbuf, "%s-",fullprompt);
addmsghist(msghistbuf);
return NULL;
} else if (isdigit(ch) && count) {
char temp[2];
temp[0] = ch;
temp[1] = '\0';
strcat(numstring, temp);
if (count) *count = atoi(numstring);
} else if ((ch == 8) && count) { // 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, "");
}
}
sprintf(msghistbuf, "%s-",fullprompt);
addmsghist(msghistbuf);
// display game windows again
restoregamewindows();
return NULL;
}
int askobjectmulti(obpile_t *op, char *prompt, long opts) {
int c,i;
object_t *mylist[MAXPILEOBS+1];
int selected[MAXPILEOBS+1];
int selcount[MAXPILEOBS+1];
char myletters[MAXPILEOBS+1];
char msghistbuf[BUFLEN],numstring[BUFLEN];
char pbuf[BUFLEN];
int firstob = 0;
int nextpage = -1;
int lastline = SCREENH-4;
int finished;
int count = ALL;
char nextlet = 'a';
int useobletters;
objectclass_t *wantoc = NULL;
clearretobs();
if (countobs(op, B_FALSE) <= 0) {
// no objects in pack
cls();
mvwprintw(mainwin, 2, 0, "You have no possessions.");
// wait for key
centre(mainwin,C_WHITE, getmaxy(mainwin)-1, "[press any key]");
getch();
restoregamewindows();
return B_TRUE;
}
reason = E_OK;
// if picking form a player's pack, use the object's letters.
// otherwise just label them a, b, c, etc.
if (op->owner && isplayer(op->owner)) {
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?
if (!canseeob(player, o)) {
ok = B_FALSE;
} else {
ok = obmatchescondition(o, opts);
}
if (ok) {
mylist[i] = o;
myletters[i] = nextlet;
selected[i] = B_FALSE;
selcount[i] = 0;
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 y,n,ch,nselected = 0;
float selweight = 0;
cls();
// list the objects
y = 2;
listobs(mainwin, mylist, selected, selcount, firstob, &i, lastline, &y, useobletters ? NULL : myletters , B_TRUE, B_FALSE);
if (mylist[i] == NULL) {
nextpage = -1;
} else {
nextpage = i;
}
// count selected items
for (n = 0 ; (mylist[n] != NULL) ; n++) {
if (selected[n]) {
int thiscount;
nselected++;
if (selcount[n] == ALL) thiscount = mylist[n]->amt;
else thiscount = selcount[n];
selweight += (getobunitweight(mylist[n]) * thiscount);
}
}
// draw prompt
if (nextpage != -1) {
mvwprintw(mainwin, y, 0, MORESTRING);
}
if (strlen(numstring) > 0) {
snprintf(pbuf, BUFLEN,"%s (%s','=all, ESC to quit) [%s]: ",prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "",
numstring);
} else {
snprintf(pbuf, BUFLEN,"%s (%sESC to quit): ", prompt,
(opts & AO_INCLUDENOTHING) ? "- for nothing, " : "");
}
// show how many items we've picked, and how much they weigh
if (nselected) {
char wbuf[BUFLEN];
char selbuf[BUFLEN];
getweighttext(selweight, wbuf, B_TRUE);
sprintf(selbuf, " (%d ob%s, ", nselected, (nselected > 1) ? "s" : "");
strcat(selbuf, wbuf);
strcat(selbuf, ")");
strcat(pbuf, selbuf);
}
mvwprintw(mainwin, 0, 0, "%s", pbuf);
// 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, B_TRUE);
// then handle input
if (ch == ' ') { // next page
if (nextpage == -1) { // go to first page
firstob = 0;
} else {
firstob = nextpage;
}
} else if (isalpha(ch) || (ch == '$')) {
int which = -1;
// select it
if (useobletters) {
object_t *o;
o = findobl(op, ch);
// find ob in list
for (i = 0 ; (mylist[i] != NULL) ; i++) {
if (mylist[i] == o) {
which = i;
break;
}
}
} else {
for (i = 0 ; (mylist[i] != NULL) ; i++) {
if (myletters[i] == ch) {
which = i;
break;
}
}
}
if (which != -1) {
int val;
if (selected[i]) val = B_FALSE;
else val = B_TRUE;
selected[i] = val;
if (val == B_TRUE) {
selcount[i] = count;
if (selcount[i] > mylist[i]->amt) selcount[i] = mylist[i]->amt;
} else {
selcount[i] = 0;
}
// reset count
strcpy(numstring, "");
count = ALL;
}
} else if ((ch == '-') && (opts & AO_INCLUDENOTHING)) { // select nothing
reason = E_SELNOTHING;
nretobs = 0;
// display game windows again
sprintf(msghistbuf, "%s-", pbuf);
addmsghist(msghistbuf);
restoregamewindows();
return B_TRUE;
} else if (ch == ',') { // toggle all/none
int val;
if (selected[0]) { // deselect all
val = B_FALSE;
} else { // select all
val = B_TRUE;
}
for (i = 0 ; (mylist[i] != NULL) ; i++) {
if (!hasflag(mylist[i]->flags, F_NOPICKUP)) {
selected[i] = val;
selcount[i] = mylist[i]->amt;
}
}
} else if (ch == 10) { // enter
// construct list to return
nretobs = 0;
for (i = 0 ; (mylist[i] != NULL); i++) {
if (selected[i]) {
retobs[nretobs] = mylist[i];
retobscount[nretobs] = selcount[i];
nretobs++;
}
}
finished = B_TRUE;
} else if (isdigit(ch) && count) {
char temp[2];
temp[0] = ch;
temp[1] = '\0';
strcat(numstring, temp);
count = atoi(numstring);
} else if ((ch == 8) && count) { // backspace
if (strlen(numstring) > 0) {
// remove last letter of number string
numstring[strlen(numstring)-1] = '\0';
count = atoi(numstring);
}
}
/*
// sanity check count...
if (count && (*count == 0)) {
strcpy(numstring, "");
}
*/
}
// clear msg bar
clearmsg();
sprintf(msghistbuf, "%s", pbuf);
addmsghist(msghistbuf);
// display game windows again
restoregamewindows();
if (nretobs <= 0) {
return B_TRUE;
}
return B_FALSE;
}
vault_t *askvault(char *prompttext) {
vault_t *v;
// make list of all vaults
initprompt(&prompt, prompttext);
for (v = firstvault ; v ; v = v->next) {
addchoice(&prompt, 'a', v->id, NULL, v, NULL);
}
if (prompt.nchoices == 0) {
msg("error - no vaults found.");
return NULL;
}
getchoicestr(&prompt, B_FALSE, B_TRUE);
v = (vault_t *)prompt.result;
return v;
}
void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ) {
int w;
char buf[BUFLEN];
va_list args;
int startx;
int len;
char *p;
int colcount = 0;
va_start(args, format);
vsnprintf( buf, BUFLEN, format, args );
va_end(args);
for (p = buf ; *p ; p++) {
if (*p == '^') colcount++;
}
len = strlen(buf) - (colcount*2);
w = getmaxx(win);
startx = (w/2) - (len/2);
if (startx < 0) startx = 0;
if (col != C_NONE) setcol(win, col);
wmove(win, y, (w/2) - (len/2));
textwithcol(win, buf);
//mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf);
if (col != C_NONE) unsetcol(win, col);
}
int chartodir(char c) {
switch (tolower(c)) {
case CH_TURN_W: case 'h': return DC_W;
case CH_TURN_N: case 'j': return DC_S;
case CH_TURN_S: case 'k': return DC_N;
case CH_TURN_E: case 'l': return DC_E;
case CH_TURN_NW: case 'y': return DC_NW;
case CH_TURN_NE: case 'u': return DC_NE;
case CH_TURN_SW: case 'b': return DC_SW;
case CH_TURN_SE: case 'n': return DC_SE;
}
return D_NONE;
}
char checkforkey(void) {
char ch;
nodelay(mainwin, true);
ch = getch();
nodelay(mainwin, false);
if (ch == ERR) ch = '\0';
if (ch == ' ') ch = '\0';
return ch;
}
void clearmsg(void) {
real_clearmsg(B_FALSE);
}
// use forced clear msg when we have
// drawn over the whole screen, eg.
void real_clearmsg(int force) {
// remember message history
if (force || strcmp(msgbuf, "")) {
char *p;
int ok = B_FALSE;
// make sure msg contains non-whitespace characters
for (p = msgbuf; p ; p++) {
if (*p != ' ') {
ok = B_TRUE;
break;
}
}
if (ok) {
addmsghist(msgbuf);
}
strcpy(msgbuf, "");
wclear(msgwin);
wrefresh(msgwin);
}
}
int cleanupgfx(void) {
curs_set(1);
endwin();
return B_FALSE;
}
void updatestatus(void) {
wrefresh(statwin);
}
// returns true if view changed
int updateviewfor(cell_t *cell) {
int oldvx,oldvy;
int w,h;
oldvx = viewx;
oldvy = viewy;
getmaxyx(gamewin, h, w);
// calculate viewport if required
if ((viewx == -9999) || (viewy == -9999)) {
// try to centre player
viewx = cell->x - (w/2);
viewy = cell->y - (h/2);
}
while ((cell->x - viewx) >= ((w / 3)*2)) {
viewx++;
}
while ((cell->y - viewy) >= ((h / 3)*2)) {
viewy++;
}
while ((cell->x - viewx) <= (w/3)) {
viewx--;
}
while ((cell->y - viewy) <= (h/3)) {
viewy--;
}
if ((viewx != oldvx) || (viewy != oldvy)) {
return B_TRUE;
}
return B_FALSE;
}
void drawscreen(void) {
int didstatus = B_FALSE;
int didredraw = B_FALSE;
if (gamemode < GM_GAMESTARTED) {
return;
}
if (statdirty) {
drawstatus();
//wrefresh(statwin);
wnoutrefresh(statwin);
statdirty = B_FALSE;
didstatus = B_TRUE;
}
if (needredraw) {
updateviewfor(player->cell);
drawlevelfor(player);
//drawcursor(); // this will call redraw gamewin
didredraw = B_TRUE;
}
if (didstatus && !didredraw) {
doupdate();
drawcursor();
}
}
void clearretobs(void) {
int i;
for (i = 0; i < MAXPILEOBS+1; i++) {
retobs[i] = NULL;
retobscount[i] = ALL;
}
nretobs = 0;
}
// clears the screen
void cls(void) {
wclear(mainwin);
statdirty = B_TRUE;
}
void describegod(lifeform_t *god) {
char buf[BUFLEN], *buf2;
char godname[BUFLEN];
char goddesc[BUFLEN];
flag_t *f;
cls();
assert(god);
f = hasflag(god->flags, F_GODOF);
real_getlfname(god, godname, B_FALSE);
snprintf(goddesc, BUFLEN, "(%s of %s)", (f->val[0] == B_FEMALE) ? "goddess" : "god", f->text);
// title
snprintf(buf, BUFLEN, "God::%s %s",godname, goddesc);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, buf);
wattroff(mainwin, A_BOLD);
wmove(mainwin, 2, 0);
buf2 = malloc(HUGEBUFLEN * sizeof(char));
makedesc_god(god, buf2);
textwithcol(mainwin, buf2);
free(buf2);
wrefresh(mainwin);
// wait for key
getch();
real_clearmsg(B_TRUE);
restoregamewindows();
}
void describeob(object_t *o) {
char buf[BIGBUFLEN];
char *buf2;
int x,y;
cls();
// title
getobname(o, buf,o->amt);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, buf);
wattroff(mainwin, A_BOLD);
wmove(mainwin, 2, 0);
buf2 = malloc(HUGEBUFLEN * sizeof(char));
makedesc_ob(o, buf2);
//textwithcol(mainwin, buf2);
x = 0; y = 2;
getyx(mainwin, y, x);
wrapprint(mainwin, &y, &x, "%s", buf2);
free(buf2);
wrefresh(mainwin);
// wait for key
getch();
restoregamewindows();
}
void describerace(enum RACE rid) {
char buf[BUFLEN];
char *buf2;
int x,y;
race_t *r;
cls();
r = findrace(rid);
if (!r) return;
// title
snprintf(buf, BUFLEN, "Race::%s",r->name);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, "%s", buf);
wattroff(mainwin, A_BOLD);
wmove(mainwin, 2, 0);
buf2 = malloc(HUGEBUFLEN * sizeof(char));
makedesc_race(rid, buf2, B_TRUE);
//textwithcol(mainwin, buf2);
getyx(mainwin,y,x);
wrapprint(mainwin, &y, &x, "%s", buf2);
free(buf2);
wrefresh(mainwin);
// wait for key
getch();
real_clearmsg(B_TRUE);
restoregamewindows();
}
void describeskill(enum SKILL skid, enum SKILLLEVEL levhilite) {
char buf[BUFLEN];
char *buf2;
skill_t *sk;
cls();
sk = findskill(skid);
if (!sk) return;
// title
snprintf(buf, BUFLEN, "Skill::%s",sk->name);
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, 0, 0, "%s", buf);
wattroff(mainwin, A_BOLD);
wmove(mainwin, 2, 0);
buf2 = malloc(HUGEBUFLEN * sizeof(char));
makedesc_skill(skid, buf2, levhilite);
textwithcol(mainwin, buf2);
free(buf2);
wrefresh(mainwin);
// wait for key
getch();
real_clearmsg(B_TRUE);
restoregamewindows();
}
void describespell(objecttype_t *ot) {
char *buf2;
char buf[BUFLEN];
cls();
// title
snprintf(buf, BUFLEN, "%s",ot->name);
capitalise(buf);
mvwprintw(mainwin, 0, 0, buf);
wmove(mainwin, 2, 0);
buf2 = malloc(HUGEBUFLEN * sizeof(char));
makedesc_spell(ot, buf2);
textwithcol(mainwin, buf2);
free(buf2);
wrefresh(mainwin);
// wait for key
getch();
real_clearmsg(B_TRUE);
restoregamewindows();
}
void doattackcell(char dirch) {
int dir = D_NONE;
flag_t *f;
cell_t *c;
if (dirch == '\0') {
dirch = askchar("Attack in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE);
}
if (dirch == '.') {
// yourself!
c = player->cell;
}
dir = chartodir(dirch);
if (dir == D_NONE) {
msg("Cancelled.");
return;
} else {
c = getcellindir(player->cell, dir);
}
if (c) {
// update last cmd
f = hasflag(player->flags, F_LASTCMD);
if (f) {
f->val[2] = dirch;
}
if (getrelativedir(player, dir) != RD_FORWARDS) {
if (!lfhasflag(player, F_AWARENESS)) {
msg("You can't attack behind you!");
return;
}
}
attackcell(player, c, B_FALSE);
}
}
void doclose(void) {
char ch;
int failed = B_TRUE; // default is to fail
int dir;
int adjdoors;
int forcedir = D_NONE;
if (lfhasflag(player, F_RAGE)) {
msg("You are too enraged to close doors!");
return;
}
// how many doors are nearby?
adjdoors = 0;
for (dir = DC_N; dir <= DC_NW; dir++) {
cell_t *c;
c = getcellindir(player->cell, dir);
if (c && haslos(player, c)) {
object_t *door;
door = hasobwithflag(c->obpile, F_DOOR);
if (door) {
int open;
isdoor(door, &open);
if (open) {
forcedir = dir;
adjdoors++;
}
}
}
}
if (adjdoors == 0) {
msg("You can't see any open doors nearby!");
return;
} else if (adjdoors == 1) {
dir = forcedir;
} else {
ch = askchar("Close door in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE, B_TRUE);
dir = chartodir(ch);
}
if (dir == D_NONE) {
clearmsg();
return;
} else {
cell_t *c;
c = getcellindir(player->cell, dir);
if (c && haslos(player, c)) {
failed = closedoorat(player, c);
}
}
}
void docomms(lifeform_t *lf) {
cell_t *where = NULL;
int i;
char buf[BUFLEN];
char lfname[BUFLEN];
char ch;
int moneyowing = 0;
enum ATTRBRACKET iqb;
flag_t *f;
cell_t *c;
lifeform_t *lf2 = NULL;
char lfname2[BUFLEN];
char buf2[BUFLEN];
int count;
object_t *o, *givenob = NULL;
if (!lf) {
where = askcoords("Talk to who?", "Talk->", TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (where && where->lf && cansee(player, where->lf)) {
lf = where->lf;
}
}
if (!lf) {
msg("Cancelled.");
return;
}
getlfname(lf, lfname);
snprintf(buf, BUFLEN, "What will you say to %s?",lfname);
initprompt(&prompt, buf);
prompt.maycancel = B_TRUE;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// are they friendly?
if (ispetof(lf, player)) {
if ((iqb >= IQ_ANIMAL) || isundead(lf)) {
addchoice(&prompt, 'a', "Attack something", NULL, NULL, NULL);
}
if (!isadjacent(lf->cell, player->cell)) {
addchoice(&prompt, 'c', "Come here", NULL, NULL, NULL);
}
addchoice(&prompt, 'g', "Go somewhere", NULL, NULL, NULL);
if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) {
addchoice(&prompt, 't', "Trade items with me", NULL, NULL, NULL);
}
if (iqb >= IQ_ANIMAL) {
f = isresting(lf);
if (f) {
addchoice(&prompt, 'r', "Stop resting.", NULL, NULL, NULL);
} else {
addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL, NULL);
}
addchoice(&prompt, '<', "Stay close.", NULL, NULL, NULL);
addchoice(&prompt, '>', "Keep your distance.", NULL, NULL, NULL);
}
} else if (ishirable(lf) ) {
if (lfhasflag(lf, F_ISPRISONER)) {
addchoice(&prompt, 'j', "Join me, and I will help you escape.", NULL, NULL, NULL);
} else {
addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL, NULL);
}
}
if (areenemies(player, lf)) {
addchoice(&prompt, 'm', "Have mercy!", NULL, NULL, NULL);
}
// if you are allies, use 'trade items' instead
if (isadjacent(lf->cell, player->cell) && !areallies(player,lf)) {
addchoice(&prompt, 'd', "(donate an item)", NULL, NULL, NULL);
}
f = lfhasflag(lf, F_OWNSSHOP);
if (f) {
int shopid;
shopid = f->val[0];
moneyowing = getowing(player, shopid, NULL);
if (moneyowing > 0) {
snprintf(buf, BUFLEN, "(pay $%d to the shopkeeper)",moneyowing);
addchoice(&prompt, 'p', buf, NULL, NULL, NULL);
}
}
addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL, NULL);
addchoice(&prompt, 'n', "(nothing)", NULL, NULL, NULL);
ch = getchoice(&prompt);
if ((ch == 'n') || (ch == '\0')) {
msg("Cancelled.");
return;
}
switch (ch) {
case 'a':
snprintf(buf, BUFLEN, "Tell %s to attack who?",lfname);
snprintf(buf2, BUFLEN, "%s->Attack->",lfname);
c = askcoords(buf, buf2, TT_MONSTER, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && c->lf) {
lf2 = c->lf;
}
if (!lf2) {
msg("Cancelled.");
return;
}
getlfname(lf2, lfname2);
msg("You say \"Attack %s!\" to %s.",isplayer(lf2) ? "me" : lfname2, lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
if (lf == lf2) {
// won't attack itself
msg("%s looks confused at your command.", lfname);
} else {
if (!cansee(lf, lf2)) {
turntoface(lf, lf2->cell);
}
if (cansee(lf, lf2)) {
// stop attacking all current targets first...
killflagsofid(lf->flags, F_TARGETLF);
aiattack(lf, lf2, DEF_AIFOLLOWTIME);
} else {
char saybuf[BUFLEN];
getlfnamea(lf2, lfname2);
sprintf(saybuf, "I can't see %s!", lfname2);
say(lf, saybuf, SV_TALK);
}
}
break;
case 'c':
msg("You say \"Come here!\" to %s.",lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
// find adjacent cell
c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND);
if (c) {
aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME);
}
break;
case 'd': // donate
// ask what to give
snprintf(buf, BUFLEN, "What will you give to %s?",lfname);
o = askobject(player->pack, buf, &count, '\0', AO_NONE);
if (o) {
if (o->type->id == OT_GOLD) {
char countbuf[BUFLEN];
// ask how much!
snprintf(buf, BUFLEN, "How much money will you give to %s (0-%d)",
lfname, countmoney(player->pack));
askstring(buf, '?', countbuf, BUFLEN, NULL);
count = atoi(buf);
if (!count) {
msg("Cancelled.");
return;
}
getobname(o, buf, count);
givemoney(player, lf, count);
msg("You give %s to %s.", buf, lfname);
} else {
givenob = moveob(o, lf->pack, count);
if (givenob) {
getobname(givenob, buf, givenob->amt);
// successful - announce
msg("You give %s to %s.", buf, lfname);
}
}
}
if (givenob) {
if ((lf->race->id == R_BEGGAR) && (givenob->type->id == OT_GOLD)) {
// begger effects
if (!countmoney(lf->pack)) {
i = rnd(1,100);
if (i <= 5) { // attack you
sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL);
fightback(lf, player);
} else if (i <= 10) { // limited wish
// change to a god.
lf = godappears(R_GODMERCY, lf->cell);
// behold! i am me!
say(lf, "Behold mortal! It is I, Yumi!", SV_SHOUT);
say(lf, "For your selfless act, I grant you a wish.", SV_TALK);
// grant a wish.
castspell(lf, OT_S_WISHLIMITED, player, NULL, NULL, NULL, NULL);
say(lf, "Until next time, mortal!", SV_TALK);
unsummon(lf, B_TRUE);
} else if (i <= 20) { // identify
object_t *poss[MAXPILEOBS],*o;
int nposs = 0;
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
// get random unknown item from player's pack
for (o = player->pack->first ; o ; o = o->next){
if (!isknown(o)) {
poss[nposs++] = o;
}
}
if (nposs) {
char oldobname[BUFLEN];
char newobname[BUFLEN];
o = poss[rnd(0,nposs-1)];
getobname(o, oldobname, o->amt);
makeknown(o->type->id);
getobname(o, newobname, o->amt);
msg("%s points at your pack.", lfname);
msg("Hey I recognise %s %s.", OB1(o, "that", "those"), oldobname);
msg("%s %s.", OB1(o, "It's", "They're"), newobname);
}
} else { // nothing
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
}
} else {
// they already had some money
sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL);
}
pleasegodmaybe(R_GODPURITY, 10);
pleasegodmaybe(R_GODMERCY, 20);
} else {
// not giving money to a begger
enum ATTRBRACKET iqb;
iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL);
// chance of calming hostile intelligen, monsters
if ((getallegiance(lf) == AL_HOSTILE) && (iqb >= IQ_ANIMAL) && cansee(lf, player)) {
int mod = 0;
int covets = B_FALSE;
// healing object and they were bleeding?
if ((islowhp(lf) || isbleeding(lf)) && hasflag(givenob->flags, F_AIHEALITEM)) {
if (aiobok(lf, givenob, lf)) {
mod += 3;
}
}
// object which ai wants?
if (aiwants(lf, givenob, &covets)) {
if (covets) {
mod += 5;
} else {
mod += 3;
}
}
// only get speech bonus if humanoid (ie they can understand you)
if (cantalk(lf)) {
mod += getskill(player, SK_SPEECH);
}
if (skillcheckvs(player, SC_MORALE, mod, lf, SC_MORALE, 0)) {
// if humanoid+intelligent, say thanks.
if (cantalk(lf)) sayphrase(lf, SP_THANKS, SV_TALK, NA, NULL);
// calm down
makepeaceful(lf);
// chance of becoming a pet if you gave something other than
// money
if (givenob->type->id != OT_GOLD) {
f = lfhasflag(lf, F_TAMABLE);
if (f && skillcheck(lf, SC_SPEECH, f->val[0], mod)) {
petify(lf, player);
if (cantalk(lf)) {
char *p = NULL;
if (lf->race->raceclass->id == RC_HUMANOID) {
p = assignnpcname(lf);
}
sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p);
}
}
}
pleasegodmaybe(R_GODMERCY, 5);
}
}
}
} // end if givenob
break;
case 'g':
snprintf(buf, BUFLEN, "Tell %s to go where?",lfname);
snprintf(buf2, BUFLEN, "%s->Goto->",lfname);
c = askcoords(buf, buf2, TT_NONE, lf, UNLIMITED, LOF_DONTNEED, B_FALSE);
if (c && cellwalkable(lf, c, NULL) ) {
} else {
msg("Cancelled.");
return;
}
// stop attacking all current targets first...
killflagsofid(lf->flags, F_TARGETLF);
msg("You say \"Go over there!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME);
break;
case 'j':
// charisma check to see if they'll join you.
msg("You say \"Join me on my quest!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
recruit(lf);
break;
case 'm': // mercy
msg("You say \"Have mercy!\" to %s.", lfname);
if (islowhp(player) &&
cantalk(lf) &&
canhear(lf, player->cell, SV_SHOUT) &&
(getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) &&
!isundead(lf)) {
if (skillcheck(player, SC_SPEECH, 30, 0)) {
// passed!
sayphrase(lf, SP_MERCYACCEPT, SV_TALK, NA, player->race->name);
// they knock you out
msg("^%d*WHACK*^n", C_YELLOW);
fallasleep(player, ST_KO, rnd(50,100));
// they take all your stuff
/*
for (o = player->pack->first ; o ; o = nexto) {
nexto = o->next;
if (canpickup(lf, o, ALL)) {
pickup(lf, o, ALL, B_FALSE, B_FALSE);
}
}
*/
// they stop attacking you
loseaitargets(lf);
}
}
break;
case 'p':
// can we afford this?
if (givemoney(player, lf, moneyowing)) {
// can't afford it
msg("You can't afford to pay $%d.", moneyowing);
} else {
int angeramt = 0;
object_t *o;
// mark all items as paid for
for (o = player->pack->first ; o ; o = o->next) {
f = hasflag(o->flags, F_SHOPITEM);
if (f) {
killflag(f);
getobname(o, buf, o->amt);
msg("You buy %s.", buf);
angeramt += 25;
// get it identified?
if (!isknown(o) && (countmoney(player->pack) >= DEF_SHOPIDENTPRICE)) {
char buf2[BUFLEN];
char ch2;
snprintf(buf2, BUFLEN, "Pay $%d to identify %s?",(int)DEF_SHOPIDENTPRICE, buf);
ch2 = askchar(buf2, "yn","n", B_TRUE, B_FALSE);
if (ch2 == 'y') {
if (givemoney(player, lf, DEF_SHOPIDENTPRICE)) {
angeramt += 25;
identify(o);
real_getobname(o, buf, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness
msgnocap("%c - %s",o->letter, buf);
} else {
msg("You can't afford to pay $%d.", DEF_SHOPIDENTPRICE);
}
}
}
}
}
sayphrase(lf, SP_PAYTHANKS, SV_TALK, NA, NULL);
}
break;
case 'r':
msg("You say \"Get some rest.\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
f = isresting(lf);
if (f) {
stopresting(lf);
} else {
if (needstorest(lf, NULL)) {
if (safetorest(lf)) {
addflag(lf->flags, F_RESTUNTILBETTER, B_TRUE, NA, NA, NULL);
startresting(lf, B_FALSE);
} else {
msg("%s is too nervous to rest (perhaps there are monsters nearby).", lfname);
}
} else {
msg("%s doesn't need to rest at the moment.", lfname);
}
}
return;
case 't':
// ask whtehr to give/take
initprompt(&prompt, "How will you trade?");
snprintf(buf, BUFLEN, "Give items to %s",lfname);
addchoice(&prompt, 'i', buf, NULL, NULL, NULL);
snprintf(buf, BUFLEN, "Take items from %s",lfname);
addchoice(&prompt, 'o', buf, NULL, NULL, NULL);
snprintf(buf, BUFLEN, "Both");
addchoice(&prompt, 'b', buf, NULL, NULL, NULL);
snprintf(buf, BUFLEN, "Neither");
addchoice(&prompt, 'n', buf, NULL, NULL, NULL);
ch = getchoice(&prompt);
switch (ch) {
case 'i':
dodrop(player->pack, B_MULTIPLE, lf->pack);
break;
case 'o':
dopickup(lf->pack, B_TRUE);
break;
case 'b':
dodrop(player->pack, B_MULTIPLE, lf->pack);
dopickup(lf->pack, B_TRUE);
break;
case 'n':
msg("Cancelled.");
return;
}
break;
case 'y':
msg("You shout at %s!", lfname);
noise(where, player, NC_OTHER, 3, "someone shouting!", NULL);
break;
case '<':
msg("You say \"Stay close!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
setfollowdistance(lf, 1, 3);
break;
case '>':
msg("You say \"Keep your distance!\" to %s.", lfname);
if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT)) {
msg("%s doesn't respond.", lfname);
break;
}
setfollowdistance(lf, 3, 5);
break;
}
taketime(player, getactspeed(player));
}
void dodrop(obpile_t *op, int wantmulti, obpile_t *dst) {
object_t *o;
char buf[BUFLEN];
int count = ALL;
int i;
lifeform_t *tolf = NULL;
object_t *toob = NULL;
char toname[BUFLEN];
// where is destination?
if (dst->owner) {
tolf = dst->owner;
getlfname(tolf, toname);
} else if (dst->parentob) {
toob = dst->parentob;
getobname(toob, toname, toob->amt);
} else {
// on ground
}
if (tolf) {
snprintf(buf, BUFLEN, "Give what to %s",toname);
} else if (toob) {
snprintf(buf, BUFLEN, "Put what in %s",toname);
} else {
strcpy(buf, "Drop what");
}
if (wantmulti) {
askobjectmulti(op, buf, AO_NONE);
} else {
o = askobject(op, buf, &count, '\0', AO_NONE);
if (o) {
retobs[0] = o;
retobscount[0] = count;
nretobs = 1;
} else {
nretobs = 0;
}
}
if (nretobs <= 0) {
return;
}
for (i = 0; i < nretobs; i++) {
flag_t *f;
//pickup(player, retobs[i],retobscount[i]);
o = retobs[i];
count = retobscount[i];
getobname(o, buf, count);
f = hasflag(o->flags, F_EQUIPPED);
if (f) {
if (f->val[0] == BP_WEAPON) {
// first try to unweild it
if (unweild(player, o)) {
if (nretobs > 1) {
if (tolf) {
msg("Not giving %s to %s.",buf, toname); more();
} else if (toob) {
msg("Not putting %s into %s.",buf, toname); more();
} else {
msg("Not dropping %s.",buf); more();
}
}
continue;
}
} else { // armour
int ch;
char buf2[BUFLEN];
// take it off first - this takes time.
snprintf(buf2, BUFLEN, "Remove %s",buf);
ch = askchar(buf2, "yn","y", B_TRUE, B_FALSE);
if (ch == 'y') {
if (takeoff(player, o)) {
// failed to take it off - can't drop it.
if (nretobs > 1) {
if (tolf) {
msg("Not giving %s to %s.",buf, toname); more();
} else if (toob) {
msg("Not putting %s into %s.",buf, toname); more();
} else {
msg("Not dropping %s.",buf); more();
}
}
continue;
}
} else {
if (nretobs > 1) {
if (tolf) {
msg("Not giving %s to %s.",buf, toname); more();
} else if (toob) {
msg("Not putting %s into %s.",buf, toname); more();
} else {
msg("Not dropping %s.",buf); more();
}
}
continue;
}
}
}
if (count == ALL) count = o->amt;
if (tolf) {
o = moveob(o, dst, count);
if (o) {
getobname(o, buf, o->amt);
msg("%s takes %s from you.",toname, buf);
} else {
msg("%s can't carry that.",toname);
}
} else if (toob) {
o = moveob(o, dst, count);
if (o) {
getobname(o, buf, o->amt);
msg("You put %s into %s.",buf, toname);
} else {
if (reason == E_NOSPACE) {
msg("%s won't fit into %s.",buf, toname);
} else {
msg("You can't put %s into %s.",buf, toname);
}
}
} else {
drop(o, count);
}
}
}
void doeat(obpile_t *op) {
object_t *o,*eatob = NULL;
char ch;
char buf[BUFLEN];
char obname[BUFLEN];
// stuffed?
if (gethungerlevel(gethungerval(player)) <= H_STUFFED) {
msg("You couldn't eat another bite!");
return;
}
// edible objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
if (caneat(player, o)) {
getobname(o, obname, o->amt);
snprintf(buf, BUFLEN, "There %s %s here. Eat %s", OB1(o,"is","are"),
obname, OB1(o,"it","one"));
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
eatob = o;
break;
}
}
}
if (!eatob) {
if (!hasedibleob(player->pack)) {
msg("You have nothing to eat!");
return;
}
eatob = askobject(op, "Eat what", NULL, 'e', AO_EDIBLE);
}
if (eatob) {
if (isunknownbadobject(eatob) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(eatob)) {
msg("Cancelled.");
return;
}
}
eat(player, eatob);
}
}
int dowear(obpile_t *op) {
object_t *o;
int rv;
o = askobject(op, "Wear what", NULL, '\0', AO_WEARABLE);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
}
}
wear(player, o);
} else {
msg("Cancelled.");
rv = B_TRUE;
}
return rv;
}
int doweild(obpile_t *op) {
object_t *o;
int count = ALL;
int rv;
o = askobject(op, "Weild what", &count, 'w', AO_WEILDABLE | AO_INCLUDENOTHING);
if (o) {
if (isunknownbadobject(o) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(o)) {
msg("Cancelled.");
return B_TRUE;
}
}
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;
cls();
mvwprintw(mainwin, 0, 0, "Current Knowledge");
y = 2;
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;
}
if (k->known == B_KNOWN) {
mvwprintw(mainwin, y, 0, " %-25s (%s)",ot->name, k->hiddenname);
} else { // ie. tried
mvwprintw(mainwin, y, 0, " %-25s (%s)","???", k->hiddenname);
}
y++;
numfound++;
if (y >= (SCREENH-3)) {
mvwprintw(mainwin, (SCREENH-2), 0, MORESTRING);
wrefresh(mainwin);
getch();
cls();
mvwprintw(mainwin, 0, 0, "Current Knowledge");
y = 2;
}
}
}
}
}
if (numfound == 0) {
mvwprintw(mainwin, y, 0, "You don't know much.");
}
wrefresh(mainwin);
getch();
restoregamewindows();
}
void dolook(cell_t *where, int onpurpose) {
int numobs,numtrails;
char buf[BUFLEN];
char seeverb[BUFLEN];
int seensomething = B_FALSE;
object_t *o,*firstob = NULL,*secondob = NULL;
flag_t *f;
int includetrails = B_TRUE;
// first announce "there is xxx" objects
// (also count objects without this flag)
numobs = 0;
numtrails = 0;
for (o = where->obpile->first ; o ; o = o->next) {
if (!canseeob(player, o)) continue;
if (hasflag(o->flags, F_COSMETIC)) continue;
// footprints/scents only count if there are no other obs here
if (!hasflag(o->flags, F_TRAIL)) {
// found a non-trail object
includetrails = B_FALSE;
}
}
for (o = where->obpile->first ; o ; o = o->next) {
if (!canseeob(player, o)) continue;
//if (hasflag(o->flags, F_SECRET)) continue;
if (hasflag(o->flags, F_COSMETIC)) continue;
if (!includetrails && hasflag(o->flags, F_TRAIL)) continue;
f = hasflag(o->flags, F_THEREISHERE);
if (f) {
// doens't matter if you're blind
getobname(o, buf, o->amt);
msg("There %s %s here%c", OB1(o,"is","are"), buf, f->text[0]);
interrupt(player);
seensomething = B_TRUE;
} else {
if (firstob) {
if (!secondob) {
secondob = o;
}
} else {
firstob = o;
}
numobs++;
}
}
//if (isblind(player)) {
if (!haslos(player, player->cell)) {
strcpy(seeverb, "feel");
} else {
strcpy(seeverb, "see");
}
if (numobs > 0) {
if (numobs == 1) {
if (!hasflag(firstob->flags, F_THEREISHERE)) {
if (streq(seeverb, "feel")) {
f = hasflag(firstob->flags, F_FEELTEXT);
if (f) {
strcpy(buf, f->text);
} else {
getobname(firstob, buf, firstob->amt);
}
} else {
getobname(firstob, buf, firstob->amt);
}
msg("You %s %s here.", seeverb, buf);
}
} else if (numobs == 2) {
char buf2[BUFLEN];
if (streq(seeverb, "feel")) {
f = hasflag(firstob->flags, F_FEELTEXT);
if (f) {
strcpy(buf, f->text);
} else {
getobname(firstob, buf, firstob->amt);
}
f = hasflag(secondob->flags, F_FEELTEXT);
if (f) {
strcpy(buf2, f->text);
} else {
getobname(secondob, buf2, secondob->amt);
}
} else {
getobname(firstob, buf, firstob->amt);
getobname(secondob, buf2, secondob->amt);
}
if (streq(buf, buf2)) {
msg("You %s %s here.", seeverb, buf);
} else {
msg("You %s %s and %s here.", seeverb, buf, buf2);
}
} else if ((numobs >= 3) && (numobs <= 4)) {
msg("You %s a few things here.", seeverb);
} else if ((numobs >= 5) && (numobs <= 6)) {
msg("You %s some things here.", seeverb);
} else if (numobs > 6) {
msg("You %s many things here.", seeverb);
}
seensomething = B_TRUE;
}
// writing here?
if (where->writing && !isblind(player)) {
msg("There is a magical inscription here:");
msg("\"%s\"", where->writing);
seensomething = B_TRUE;
}
if (!seensomething) {
// just clear the message buffer
//clearmsg();
if (isblind(player)) {
msg("There does not seem to be anything here.");
} else {
msg("There is nothing here.");
}
}
}
char *makedesc_god(lifeform_t *god, char *retbuf) {
char thisline[BUFLEN];
char godname[BUFLEN];
flag_t *f, *retflag[MAXCANDIDATES];
int nretflags,i;
f = hasflag(god->flags, F_GODOF);
real_getlfname(god, godname, B_FALSE);
strcpy(retbuf, "");
// title
sprintf(thisline, "%s likes ", godname);
getflags(god->flags, retflag, &nretflags, F_GODLIKES, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (i == 0) {
strcat(thisline, f->text);
} else if (i == nretflags - 1) {
strcat(thisline, " and ");
strcat(thisline, f->text);
} else {
strcat(thisline, ", ");
strcat(thisline, f->text);
}
}
strcat(thisline, ".\n\n");
strncat(retbuf, thisline, HUGEBUFLEN);
sprintf(thisline, "%s dislikes ", godname);
getflags(god->flags, retflag, &nretflags, F_GODDISLIKES, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (i == 0) {
strcat(thisline, f->text);
} else if (i == nretflags - 1) {
strcat(thisline, " and ");
strcat(thisline, f->text);
} else {
strcat(thisline, ", ");
strcat(thisline, f->text);
}
}
strcat(thisline, ".\n\n");
strncat(retbuf, thisline, HUGEBUFLEN);
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_NONE);
if (nretflags == 0) {
sprintf(thisline, "%s does not accept sacrifices.\n", godname);
strncat(retbuf, thisline, HUGEBUFLEN);
} else {
int i;
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBCLASS, F_NONE);
for (i = 0; i < nretflags; i++) {
objectclass_t *oc;
oc = findoc(retflag[i]->val[0]);
sprintf(thisline, "%s accepts the sacrifice of all %s.\n",godname, oc->name);
strncat(retbuf, thisline, HUGEBUFLEN);
}
getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_NONE);
for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
if (i == 0) {
sprintf(thisline, "%s accepts the sacrifice of:\n", godname);
strncat(retbuf, thisline, HUGEBUFLEN);
}
ot = findot(retflag[i]->val[0]);
sprintf(thisline, "- %s\n", ot->name);
strncat(retbuf, thisline, HUGEBUFLEN);
}
}
return retbuf;
}
char *makedesc_ob(object_t *o, char *retbuf) {
char buf[BIGBUFLEN];
char buf2[BUFLEN];
char buf3[BUFLEN];
recipe_t *rec;
flag_t *f;
int obknown,i,throwrange;
flag_t *retflag[MAXCANDIDATES];
int nretflags;
object_t *compareob = NULL;
// do we need to compare this object with an equipped on?
if (!isequipped(o)) {
if (isweapon(o)) {
compareob = getweapon(player);
} else {
getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_GOESON) {
compareob = getequippedob(player->pack, f->val[0]);
if (compareob) {
break;
}
}
}
}
}
strcpy(retbuf, "");
obknown = isknown(o);
// description
getobdesc(o, buf);
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n\n", HUGEBUFLEN);
// extra object descriptions?
getflags(o->flags, retflag, &nretflags, F_EXTRADESC, F_NONE);
if (nretflags) {
int order;
for (order = 0; order < 5; order++) {
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if ((f->val[0] == order) ||
((f->val[0] == NA) && (order == 0))) {
snprintf(buf, BUFLEN, "%s^n\n", f->text);
strncat(retbuf, buf, BUFLEN);
}
}
}
}
if (nretflags) {
strcat(retbuf, "\n");
}
// append masterwork etc onto description
f = hasflag(o->flags, F_MASTERWORK);
if (f && f->known) {
strncat(retbuf, "It is extremely well crafted.\n", HUGEBUFLEN);
}
f = hasflag(o->flags, F_SHODDY);
if (f && f->known) {
strncat(retbuf, "It is very poorly crafted.\n", HUGEBUFLEN);
}
// weight
if (o->material->id != MT_NOTHING) {
float obw;
if (o->material->id == MT_FOOD) {
snprintf(buf, BUFLEN, "%s %s food product%s, ", OB1(o,"It is a","They are"),
getsizetext(getobsize(o)), OBNOS1(o));
} else {
snprintf(buf, BUFLEN, "%s %s sized, made from %s, ",OB1(o,"It is","They are"),
getsizetext(getobsize(o)),
o->material->name);
}
obw = getobweight(o);
if (o->amt == 1) {
char wbuf[BUFLEN];
getweighttext(obw, wbuf, B_FALSE);
snprintf(buf2, BUFLEN, "and weighs %s",wbuf);
strcat(buf, buf2);
} else {
char wbuf[BUFLEN];
char wbuf2[BUFLEN];
getweighttext(obw, wbuf, B_FALSE);
getweighttext(getobunitweight(o), wbuf2, B_FALSE);
snprintf(buf2, BUFLEN, "and weigh %s (%s each)",wbuf, wbuf2);
strcat(buf, buf2);
}
if (compareob && (o->amt == 1)) {
int diff;
float compareobw;
compareobw = getobweight(compareob);
diff = obw - compareobw;
if (diff == 0) {
strcpy(buf2, " (=)");
} else {
char wbuf[BUFLEN];
getweighttext(abs(diff), wbuf, B_FALSE);
// weighing less is better
snprintf(buf2, BUFLEN, " %s(%c%s)^n", (diff > 0) ? "^B" : "^g",
(diff > 0) ? '+' : '-', wbuf);
}
strncat(buf, buf2, HUGEBUFLEN);
}
strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, ".\n", HUGEBUFLEN);
throwrange = getmaxthrowrange(player, o);
if (throwrange >= 1) {
sprintf(buf, "@You could throw %s %d metres.", OB1(o,"it","one"), throwrange);
} else {
sprintf(buf, "@It is too heavy for you to throw.");
}
strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN);
}
f = hasflag(o->flags, F_THROWMISSILE);
if (f) {
if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) {
int dam;
dam = getthrowdam(o);
sprintf(buf, "@%s good for throwing [base damage %d].",OB1(o,"It is","They are"), dam);
} else {
sprintf(buf, "@%s good for throwing.", OB1(o,"It is","They are"));
}
strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN);
}
if ((f = hasflag(o->flags, F_IMPASSABLE)) != NULL) {
if ((f->val[0] == SZ_MIN) && (f->val[1] == SZ_MAX)) {
snprintf(buf, BUFLEN, "It is %simpassable.\n", hasflag(o->flags, F_DOOR) ? "currently " : "");
} else {
snprintf(buf, BUFLEN, "It is %simpassable for %s to %s sized creatures.\n",
hasflag(o->flags, F_DOOR) ? "currently " : "",
getsizetext(f->val[0]), getsizetext(f->val[1]));
}
strncat(retbuf, buf, HUGEBUFLEN);
}
if (isedible(o)) {
int basenutr;
basenutr = getnutritionbase(o);
sprintf(buf, "%s edible, and %s %s.\n",
OB1(o,"It is","They are"),
OB1(o,"is","are each"),
getfillingname(basenutr));
strncat(retbuf, buf, HUGEBUFLEN);
if (hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL)) {
// don't show "it will rot" if it's already rotten (and you know this)
if (isrotting(o) && ( (getattrbracket(getattr(player, A_IQ), A_IQ, NULL) >= AT_GTAVERAGE) || getskill(player, SK_COOKING)) ) {
} else {
sprintf(buf, "%s will decay and go bad over time.\n", OB1(o,"It","They"));
strncat(retbuf, buf, HUGEBUFLEN);
}
}
}
// unknown items?
if (isknown(o)) {
// weapons?
if (isfirearm(o)) {
flag_t *ff, *ff2;
sprintf(buf, "It is a %s firearm.\n", hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed");
strncat(retbuf, buf, HUGEBUFLEN);
f = hasflag(o->flags, F_ACCURACY);
if (f) {
int acc,accnum;
acc = getobaccuracy(o, NULL);
accnum = getaccuracynum(acc);
sprintf(buf, "@It has a base accuracy of %c%d (%s).\n",(accnum < 0) ? '-' : '+', abs(accnum), getaccuracyname(acc));
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_RANGE);
if (f) {
sprintf(buf, "@Its maximum range is %d.\n",f->val[0]);
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_AMMOCAPACITY);
if (f) {
sprintf(buf, "@It can hold up to %d of the following kind(s) of ammo:\n",f->val[0]);
strncat(retbuf, buf, HUGEBUFLEN);
strcpy(buf, "");
getflags(o->flags, retflag, &nretflags, F_AMMOOB, F_NONE);
for (i = 0; i < nretflags; i++) {
objecttype_t *ot;
ff = retflag[i];
ot = findot(ff->val[0]);
if (ot) {
if (streq(buf, "")) {
snprintf(buf, BUFLEN, "@@%s",ot->name);
} else {
if (strlen(buf) >= 60) {
strncat(retbuf, buf, HUGEBUFLEN);
snprintf(buf, BUFLEN, "\n@@%s",ot->name);
} else {
strcat(buf, ", ");
strcat(buf, ot->name);
}
}
}
}
if (strlen(buf)) {
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n", HUGEBUFLEN);
}
}
ff = hasflag(o->flags, F_FIRESPEED);
if (ff) {
sprintf(buf, "@It fires at a speed of %d km/h.\n",speedtokph(ff->val[0]));
strncat(retbuf, buf, HUGEBUFLEN);
}
ff2 = hasflag(o->flags, F_RELOADTURNS);
sprintf(buf, "@It takes %d turn%s to reload.\n", ff2->val[0], (ff2->val[0] == 1) ? "" : "s");
strncat(retbuf, buf, HUGEBUFLEN);
} else if (isweapon(o) && isknown(o)) {
flag_t *damflag;
int delay;
int critchance;
snprintf(buf, BUFLEN, "%s %s weapon",
(o->type->obclass->id == OC_WEAPON) ? "It is a" : "It can be used as a",
hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed");
damflag = hasflag(o->flags, F_DAM);
if (damflag) {
//int bonus = 0;
char buf2[BUFLEN];
//int mindam,maxdam;
int dr;
enum DAMTYPE damtype;
/*
f = hasflag(o->flags, F_BONUS);
if (f && f->known) {
// only tell player about bonuses if they are known.!
bonus = f->val[0];
}
*/
damtype = damflag->val[0];
dr = damflag->val[1];
/*
getdamrange(o, &mindam, &maxdam);
mindam += bonus;
maxdam += bonus;
limit(&mindam, 0, NA);
limit(&maxdam, 0, NA);
*/
/*
if (mindam == maxdam) {
snprintf(buf2, BUFLEN, ", dealing %d %s damage",maxdam, getdamname(damtype));
} else {
snprintf(buf2, BUFLEN, ", dealing %d-%d %s damage",mindam,maxdam, getdamname(damtype));
}
*/
snprintf(buf2, BUFLEN, " which deals %s damage.\n",getdamname(damtype));
strcat(buf, buf2);
//dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL);
sprintf(buf2, "@It has a base Damage Rating of %d",dr);
strcat(buf, buf2);
strncat(retbuf, buf, HUGEBUFLEN);
if (compareob) {
flag_t *comparedf;
//int comparebonus = 0,cmin,cmax,diff;
int comparedr,diff;
comparedf = hasflag(compareob->flags, F_DAM);
comparedr = comparedf->val[1];
//f = hasflag(compareob->flags, F_BONUS);
//if (f && f->known) comparebonus = f->val[0];
//getdamrange(compareob, &cmin, &cmax);
//cmin += bonus; cmax += bonus;
//limit(&cmin, 0, NA); limit(&cmax, 0, NA);
diff = dr - comparedr;
if (diff == 0) {
strcat(retbuf, " (=)");
} else {
// higher damagerating is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g",
(diff < 0) ? '-' : '+', abs(diff));
strcat(retbuf, buf2);
}
}
strcat(retbuf, ".\n");
// other extra damage or effects?
f = hasflag(o->flags, F_ONFIRE);
if (f) {
sprintf(buf,"@It also inflicts %s extra burning damage.\n", strlen(f->text) ? f->text : "1-4");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_FROZEN);
if (f) {
sprintf(buf,"@It also inflicts %s extra cold damage.\n", strlen(f->text) ? f->text : "1-4");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_ENCHANTED);
if (f) {
sprintf(buf,"@It also inflicts %s extra magical damage if the user has spare mana.\n", strlen(f->text) ? f->text : "1-2");
strncat(retbuf, buf, HUGEBUFLEN);
}
} else {
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n", HUGEBUFLEN);
}
f = hasflag(o->flags, F_ACCURACY);
if (f) {
int acc,accnum;
acc = getobaccuracy(o, NULL);
accnum = getaccuracynum(acc);
sprintf(buf, "@It has an accuracy modifier of %c%d (%s)",(accnum < 0) ? '-' : '+', abs(accnum) , getaccuracyname(acc));
if (compareob && hasflag(compareob->flags, F_ACCURACY)) {
int cacc,caccnum,diff;
cacc = getobaccuracy(compareob, NULL);
caccnum = getaccuracynum(cacc);
diff = accnum - caccnum;
if (diff == 0) {
strcat(buf, " (=)");
} else {
// higher accuracy is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g", (diff < 0) ? '-' : '+', abs(diff));
strcat(buf, buf2);
}
}
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
critchance = getcritchance(player, o, NULL);
sprintf(buf, "@You have a %d%% critical hit chance with it", critchance);
if (compareob) {
int ccritch,diff;
ccritch = getcritchance(player, compareob, NULL);
diff = critchance - ccritch;
if (diff == 0) {
strcat(buf, " (=)");
} else {
// higher crit chance is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff < 0) ? "^B" : "^g",
(diff > 0) ? '+' : '-', abs(diff));
strcat(buf, buf2);
}
}
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
f = hasflag(o->flags, F_OBATTACKDELAY);
if (f) delay = f->val[0];
else delay = 100;
sprintf(buf, "@Its attack delay is %d%%",delay - 100);
if (compareob) {
int cdelay,diff;
f = hasflag(compareob->flags, F_OBATTACKDELAY);
if (f) cdelay = f->val[0];
else cdelay = 100;
diff = delay - cdelay;
if (diff == 0) {
strcat(buf, " (=)");
} else {
// lower attack delay is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^B" : "^g",
(diff > 0) ? '+' : '-', abs(diff));
strcat(buf, buf2);
}
}
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
// damage
if (isarmour(o)) {
int thisar = 0;
flag_t *goesmulti;
goesmulti = hasflag(o->flags, F_GOESONMULTI);
/*
f = hasflag(o->flags, F_GOESON);
if (f) {
snprintf(buf, BUFLEN, "It is worn %s your %s, ",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0]));
} else {
strcpy(buf, "");
}
*/
strcpy(buf, "");
getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE);
for (i = 0; i < nretflags; i++) {
char posbuf[BUFLEN];
f = retflag[i];
makewearstringsingle(NULL, f, "the ", posbuf);
if (i == 0) {
sprintf(buf, "It is worn %s", posbuf);
} else if (i == (nretflags - 1)) {
strcat(buf, " and ");
strcat(buf, posbuf);
} else {
strcat(buf, ", ");
strcat(buf, posbuf);
}
}
if (strlen(buf)) {
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_ARMOURRATING);
if (f) {
thisar = f->val[0] + getobbonus(o, B_TRUE);
snprintf(buf, BUFLEN, "It has an Armour Rating of %d",thisar);
} else {
thisar = 0;
snprintf(buf, BUFLEN, "It provides no protection");
}
if (strlen(buf) && compareob) {
int diff,comparear = 0;
f = hasflag(compareob->flags, F_ARMOURRATING);
if (f) {
comparear = f->val[0] + getobbonus(compareob, B_TRUE);
} else {
comparear = 0;
}
diff = thisar - comparear;
if (diff == 0) {
strcpy(buf2, " (=)");
} else {
// higher AR is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B",
(diff > 0) ? '+' : '-', abs(diff));
}
strncat(buf, buf2, HUGEBUFLEN);
}
strcat(buf, ".");
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n", HUGEBUFLEN);
f = hasflag(o->flags, F_EVASION);
if (f) {
int evmod;
evmod = adjustarmourpenalty(player, f->val[0]);
if (evmod != 0) {
snprintf(buf, BUFLEN, "@When worn, it %s your evasion chance by %d%%\n.", (evmod < 0) ? "reduces" : "increases", abs(evmod));
strncat(retbuf, buf, HUGEBUFLEN);
}
}
f = hasflag(o->flags, F_ACCURACYMOD);
if (f) {
sprintf(buf, "@It will %s your evasion chance by %d%%.\n",
(f->val[0] < 0) ? "lower" : "raise", abs(f->val[0]));
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_SCARY);
if (f) {
sprintf(buf, "@It may unnerve others when worn.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
} else {
// non armour, but still wearable.
f = hasflag(o->flags, F_GOESON);
if (f) {
snprintf(buf, BUFLEN, "It is worn %s your %s.\n",getbodypartequipname(f->val[0]), getbodypartname(NULL, f->val[0]));
strncat(retbuf, buf, HUGEBUFLEN);
}
}
// critical protection chance
f = hasflag(o->flags, F_GOESON);
if (f) {
int critprotchance;
critprotchance = getcritprotection(o);
if (critprotchance == 0) {
snprintf(buf, BUFLEN, "It will not protect your %s from critical hits", getbodypartname(player, f->val[0]));
} else {
snprintf(buf, BUFLEN, "It has a %d%% chance of preventing critical hits to your %s",
critprotchance, getbodypartname(player, f->val[0]));
}
if (compareob) {
int diff,comparechance = 0;
comparechance = getcritprotection(compareob);
diff = critprotchance - comparechance;
if (diff == 0) {
strcpy(buf2, " (=)");
} else {
// higher protchance is better
snprintf(buf2, BUFLEN, " %s(%c%d)^n", (diff > 0) ? "^g" : "^B",
(diff > 0) ? '+' : '-', abs(diff));
}
strncat(buf, buf2, HUGEBUFLEN);
}
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
if (hasflag(o->flags, F_DAMAGABLE) && isarmour(o) ) {
int showfullhp = B_FALSE;
char hpbuf[BUFLEN];
f = hasflag(o->flags, F_OBHP);
if (isarmour(o) && getskill(player, SK_ARMOUR)) {
showfullhp = B_TRUE;
} else if (isshield(o) && getskill(player, SK_SHIELDS)) {
showfullhp = B_TRUE;
} else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) {
showfullhp = B_TRUE;
} else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) &&
getskill(player, SK_SEWING)) {
showfullhp = B_TRUE;
}
if (isdamaged(o)) {
snprintf(buf, BUFLEN, "It has been damaged.");
} else {
snprintf(buf, BUFLEN, "It is in perfect condition.");
}
if (showfullhp) {
int pct;
pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0);
snprintf(hpbuf, BUFLEN, " [%d%%, %d/%d hp]", pct, f->val[0], f->val[1]);
} else if (isdamaged(o)) {
int pct;
pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0);
snprintf(hpbuf, BUFLEN, " [%d%% hp]", pct);
} else {
strcpy(hpbuf, "");
}
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n", HUGEBUFLEN);
}
f = hasflag(o->flags, F_ARMOURSIZE);
if (f) {
char sizetext[BUFLEN];
switch (f->val[0]) {
case SZ_MEDIUM:
snprintf(sizetext, BUFLEN, "small");
break;
case SZ_LARGE:
snprintf(sizetext, BUFLEN, "very large");
break;
case SZ_HUMAN:
default:
snprintf(sizetext, BUFLEN, "human");
break;
}
snprintf(buf, BUFLEN, "%sIt will only fit %s sized creatures.^n\n",
(f->val[0] != getlfsize(player)) ? "^B" : "^n", sizetext);
strncat(retbuf, buf, HUGEBUFLEN);
}
// charges remaining
if (o->type->obclass->id == OC_WAND) {
if (isidentified(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has %d charges left.\n",charges);
} else {
sprintf(buf, "It has no charges left.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->obclass->id == OC_GODSTONE) {
if (isidentified(o)) {
int charges,max;
getchargeinfo(o, &charges, &max);
if (charges == max) {
sprintf(buf, "It is fully charged.\n");
} else {
sprintf(buf, "It is depleted.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
} else if (o->type->id == OT_CREDITCARD) {
if (isidentified(o)) {
int charges;
charges = getcharges(o);
if (charges) {
sprintf(buf, "It has $%d remaining until its limit.\n",charges);
} else {
sprintf(buf, "It is maxed out.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
}
}
f = hasflag(o->flags, F_PICKLOCKS);
if (f) {
sprintf(buf, "You can use it to pick locks.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_HELPSCLIMB);
if (f) {
sprintf(buf, "It can be used to assist in climbing.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_HELPSDISARM);
if (f) {
sprintf(buf, "It gives a +%d%% bonus when disarming traps.\n", f->val[0] * 5);
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_HELPSREST);
if (f) {
sprintf(buf, "It provides a %d%% bonus to health regeneration when resting.", f->val[0] * 5);
strncat(retbuf, buf, HUGEBUFLEN);
}
// skip line
strncat(retbuf, "\n", HUGEBUFLEN);
// been made invulnerable ?
if (hasflagknown(o->type->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) {
strncat(retbuf, "It is invulnerable to most damage.\n", HUGEBUFLEN);
} else {
// immunities
strcpy(buf, "");
f = hasflagval(o->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "It is immune to %s", getdamname(DT_ALL));
} else {
int first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isimmuneto(o->flags, i, B_FALSE);
if (f) {
char buf2[BUFLEN];
if (first) {
snprintf(buf2, BUFLEN, "It is immune to: %s", getdamname(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamname(i));
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
// resistances
strcpy(buf, "");
f = hasflagval(o->flags, F_DTRESIST, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "It is resistant to %s", getdamname(DT_ALL));
} else {
int first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isresistantto(o->flags, i, B_FALSE);
if (f) {
char buf2[BUFLEN];
if (first) {
snprintf(buf2, BUFLEN, "It is resistant to: %s", getdamname(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamname(i));
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
// vulnerabilities
strcpy(buf, "");
f = hasflagval(o->flags, F_DTVULN, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "It is vulnerable to %s", getdamname(DT_ALL));
} else {
int first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isvulnto(o->flags, i, B_FALSE);
if (f) {
char buf2[BUFLEN];
if (first) {
snprintf(buf2, BUFLEN, "It is vulnerable to: %s", getdamname(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamname(i));
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
} // end if isknown
// skip line
strncat(retbuf, "\n", HUGEBUFLEN);
for (f = o->flags->first ; f ; f = f->next) {
if ((f->id == F_HITCONFER) && (f->val[0] == F_POISONED) && (f->lifetime == FROMOBMOD)) {
sprintf(buf, "It has been coated with poison.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
// physical properties
f = hasflag(o->flags, F_ONFIRE);
if (f) {
sprintf(buf, "It is on fire.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
if (obproduceslight(o)) {
sprintf(buf, "It is producing light.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_RUSTED);
if (f) {
sprintf(buf, "It is rusty.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_WATERPROOF);
if (f) {
sprintf(buf, "It is waterproof.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_WET);
if (f) {
sprintf(buf, "It is wet.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_ACTIVATED);
if (f) {
sprintf(buf, "It is activated.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
// other weapon properties...
getflags(o->flags, retflag, &nretflags, F_CANBLOCK, F_NONE);
for (i = 0; i < nretflags; i++) {
char thisdt[BUFLEN];
f = retflag[i];
if (f->val[0] == DT_ALL) {
strcpy(thisdt, "melee");
} else {
sprintf(thisdt, "%s", getdamname(f->val[0]));
}
if (i == 0) {
snprintf(buf, BUFLEN, "Skilled weilders can use it to block %s", thisdt);
} else if (i == (nretflags - 1)) {
snprintf(buf, BUFLEN, " and %s", thisdt);
} else {
snprintf(buf, BUFLEN, ", %s", thisdt);
}
strncat(retbuf, buf, HUGEBUFLEN);
}
if (nretflags) {
snprintf(buf, BUFLEN, " damage.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_NEEDSSPACE);
if (f && f->known) {
sprintf(buf, "It is ineffective in confined spaces due to its length.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_ARMOURPIERCE);
if (f && f->known) {
sprintf(buf, "Armour will not reduce %s damage.\n",OB1(o,"its","their"));
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_BALANCE);
if (f && f->known) {
sprintf(buf, "It heals weaker enemies, and does extra damage to stronger ones.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_FLAMESTRIKE);
if (f && f->known) {
sprintf(buf, "It ignites fires wherever it hits.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_HEAVYBLOW);
if (f && f->known) {
sprintf(buf, "Its powerful blows knock enemies backwards.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_MERCIFUL);
if (f && f->known) {
sprintf(buf, "It will knock out enemies rather than deal lethal damage.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_REVENGE);
if (f && f->known) {
sprintf(buf, "It does more damage as your HP are lowered.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_RACESLAY);
if (f && f->known) {
raceclass_t *rc;
rc = findraceclass(f->val[0]);
sprintf(buf, "It deals 4x damage against %s.\n",rc->pluralname);
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(o->flags, F_VAMPIRIC);
if (f && f->known) {
sprintf(buf, "It drains life force from its victims into the weilder.\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
// if known, show what it confers
for (f = o->flags->first ; f ; f = f->next) {
if ((f->id == F_HOLDCONFER) || (f->id == F_EQUIPCONFER) || (f->id == F_ACTIVATECONFER)) {
if (obknown) {
objecttype_t *ot;
if (f->id == F_HOLDCONFER) strcpy(buf, "When held, it");
else if (f->id == F_ACTIVATECONFER) strcpy(buf, "When activated, it");
else if (f->id == F_HITCONFER) strcpy(buf, "When hit by it, it");
else strcpy(buf, "When equipped, it");
// conferred intrinsics
switch (f->val[0]) {
int amt,amt2;
case F_ARMOURPENALTY:
amt = adjustarmourpenalty(player, f->val[1]);
amt2 = adjustarmourpenalty(player, f->val[2]);
if (amt > 0) {
sprintf(buf2, "^B%s lowers your accuracy by %d. (Armour skill penalty)^n\n", buf, getaccuracymodnum(amt));
strncat(retbuf, buf2, HUGEBUFLEN);
}
if (amt2 > 0) {
sprintf(buf2, "^B%s lowers your evasion by %d. (Armour skill penalty)^n\n", buf, amt2);
strncat(retbuf, buf2, HUGEBUFLEN);
}
break;
case F_SHIELDPENALTY:
amt = adjustshieldpenalty(player, f->val[1]);
amt2 = adjustshieldpenalty(player, f->val[2]);
if (amt > 0) {
sprintf(buf2, "^B%s lowers your attack accuracy by %d. (Shields skill too low)^n\n", buf, getaccuracymodnum(amt));
strncat(retbuf, buf2, HUGEBUFLEN);
}
if (amt2 > 0) {
sprintf(buf2, "^B%s lowers your evasion by %d. (Shields skill penalty)^n\n", buf, amt2);
strncat(retbuf, buf2, HUGEBUFLEN);
}
break;
case F_ANONYMOUS:
sprintf(buf2, "%s obscures your identity.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_ATTRMOD:
sprintf(buf2, "%s %s your %s.\n", buf, (f->val[2] > 0) ? "increases" : "decreases", getattrname(f->val[1]));
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_ATTRSET:
sprintf(buf2, "%s modifies your %s.\n", buf, getattrname(f->val[1]));
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_AWARENESS:
sprintf(buf2, "%s grants you enhanced awareness.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_BLIND:
sprintf(buf2, "%s prevents you from seeing anything.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_BREATHWATER:
sprintf(buf2, "%s allows you to breath normally while underwater.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_CONTROL:
sprintf(buf2, "%s lets you control teleportation and polymorphic effects.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DEAF:
sprintf(buf2, "%s prevents you from hearing anything.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DETECTLIFE:
sprintf(buf2, "%s lets you detect nearby lifeforms.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DETECTOBS:
sprintf(buf2, "%s lets you detect nearby objects.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DETECTMAGIC:
sprintf(buf2, "%s will detect magical enchantments on objects.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DETECTMETAL:
sprintf(buf2, "%s will detect nearby metal.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_ENHANCESEARCH:
sprintf(buf2, "%s enhances your searching ability.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_ENHANCESMELL:
sprintf(buf2, "%s enhances your sense of smell.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DISEASEIMMUNE:
sprintf(buf2, "%s makes you immune to disease.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DTIMMUNE:
sprintf(buf2, "%s makes you immune to %s.\n", buf, getdamnamenoun(f->val[1]));
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DTRESIST:
sprintf(buf2, "%s makes you resistant to %s.\n", buf, getdamnamenoun(f->val[1]));
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DTVULN:
sprintf(buf2, "%s renders you vulnerable to %s.\n", buf, getdamnamenoun(f->val[1]));
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DRUNK:
sprintf(buf2, "%s makes you tipsy.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_EXTRAINFO:
sprintf(buf2, "%s provides enhanced knowledge to you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_EXTRADAM:
sprintf(buf2, "%s will cause you to deal more damage.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_EXTRALUCK:
sprintf(buf2, "%s will give you a bonus to all skill checks.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_EXTRAMP:
sprintf(buf2, "%s will increase your mana pool by %d%%.\n", buf, f->val[0]);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FASTACT:
sprintf(buf2, "%s will speed up your actions.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FASTMETAB:
sprintf(buf2, "%s will increase your metabolic rate.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FASTMOVE:
sprintf(buf2, "%s will speed up your movement.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FLYING:
sprintf(buf2, "%s will allow you to fly.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FREEZINGTOUCH:
sprintf(buf2, "%s will cause objects you touch to turn to ice.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_FROZEN:
sprintf(buf2, "%s turns you to ice.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_GRAVBOOSTED:
sprintf(buf2, "%s increases gravity around you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_GRAVLESSENED:
sprintf(buf2, "%s decreases gravity around you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_DODGES:
sprintf(buf2, "%s allows you to dodge attacks.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_INVISIBLE:
sprintf(buf2, "%s renders you invisible to normal sight.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_INVULNERABLE:
sprintf(buf2, "%s protects you from all physical harm.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_CANWILL:
ot = findot(f->val[1]);
if (ot) {
char sname[BUFLEN];
strcpy(sname, ot->name);
capitalise(sname);
sprintf(buf2, "%s allows you to %s '%s' at will.\n", buf,
(ot->obclass->id == OC_SPELL) ? "cast" : "use the ability",
sname);
strncat(retbuf, buf2, HUGEBUFLEN);
}
break;
case F_CAFFEINATED:
sprintf(buf2, "%s acts as a stimulant.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_CANCAST:
ot = findot(f->val[1]);
if (ot) {
char sname[BUFLEN];
strcpy(sname, ot->name);
capitalise(sname);
sprintf(buf2, "%s allows you to cast '%s'.\n", buf, sname);
strncat(retbuf, buf2, HUGEBUFLEN);
}
break;
case F_DETECTAURAS:
sprintf(buf2, "%s allows you to detect blessings or curses.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_HOLYAURA:
sprintf(buf2, "%s surrounds you with a holy aura.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_LEARNBOOST:
sprintf(buf2, "%s grants a bonus to earned experience points.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_LEVITATING:
sprintf(buf2, "%s causes you to levitate.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_MAGICBOOST:
sprintf(buf2, "%s boosts the power of your spells by %d.\n", buf, f->val[1]);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_MEDITATES:
sprintf(buf2, "%s allows you to retain awareness while resting.", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_MAGSHIELD:
sprintf(buf2, "%s surrounds you with a magnetic shield.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_NAUSEATED:
sprintf(buf2, "%s causes you to feel nauseated.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_NONCORPOREAL:
sprintf(buf2, "%s makes you non-corporeal.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_PAIN:
sprintf(buf2, "%s causes you intense pain.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_PARALYZED:
sprintf(buf2, "%s paralyzes you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_PHOTOMEM:
sprintf(buf2, "%s prevents you from forgetting your surroundings.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_STABILITY:
sprintf(buf2, "%s prevents you from slipping over.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_STENCH:
sprintf(buf2, "%s makes you smell bad.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_PRODUCESLIGHT:
sprintf(buf2, "%s produces light.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_RETALIATE:
sprintf(buf2, "%s protects you with %s.\n", buf, f->text);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_RAGE:
sprintf(buf2, "%s makes you enraged.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_REFLECTION:
sprintf(buf2, "%s reflects all projectiles back to their source.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_REGENERATES:
if (f->val[1] == 1) {
strcpy(buf3, "");
} else if (f->val[1] == 2) {
strcpy(buf3, "quickly");
} else if (f->val[1] == 3) {
strcpy(buf3, "very quickly");
} else { // >= 4
strcpy(buf3, "extremely quickly");
}
sprintf(buf2, "%s allows you to regenerate health%s.\n", buf,buf3);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_RESISTMAG:
sprintf(buf2, "%s grants you %s immunity to magic.\n", buf,
(f->val[0] >= 10) ? "strong" : "minor");
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_RISEASGHOST:
sprintf(buf2, "%s cause you to rise as a ghost after death.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SEEINVIS:
sprintf(buf2, "%s allows you to see invisible things.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SEEINDARK:
sprintf(buf2, "%s allows you to see in the dark.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SILENTMOVE:
sprintf(buf2, "%s allows you to move silently.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SLOWACT:
sprintf(buf2, "%s will slow down your actions.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SLOWMETAB:
sprintf(buf2, "%s will decrease your metabolic rate.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SLOWMOVE:
sprintf(buf2, "%s will slow down your movement.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_SPIDERCLIMB:
sprintf(buf2, "%s allows you to adhere to walls.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_TREMORSENSE:
sprintf(buf2, "%s allows you to 'see' by sensing vibrations around you.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_TRUESTRIKE:
sprintf(buf2, "%s makes your attacks automatically hit.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_WINDSHIELD:
sprintf(buf2, "%s will surround you with a cyclonic shield.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_VISRANGEMOD:
sprintf(buf2, "%s %s your vision range.\n", buf, (f->val[1] > 0) ? "increases" : "descreases");
strncat(retbuf, buf2, HUGEBUFLEN);
break;
case F_XRAYVIS:
sprintf(buf2, "%s allows you to see through walls.\n", buf);
strncat(retbuf, buf2, HUGEBUFLEN);
break;
}
}
}
}
// requirements
i = B_FALSE;
for (f = o->flags->first ; f ; f = f->next) {
if (f->id == F_ATTREQ) {
enum COLOUR col;
int pctmod;
int usable = B_TRUE;
if (!meetsattreq(player, f, o, &pctmod)) {
col = C_RED;
usable = B_FALSE;
} else {
col = C_GREY;
}
sprintf(buf, "^%dIt requires at least %d %s to use%s.^n\n", col, f->val[1], getattrname(f->val[0]),
(f->val[2] == 0) ? "" : " effectively");
strncat(retbuf, buf, HUGEBUFLEN);
if (usable && isweapon(o)) {
if (pctmod > 0) {
sprintf(buf, "^%dYour high %s will increase your %s with this weapon.^n\n", C_GREEN,
getattrname(f->val[0]),
(f->val[0] == A_AGI) ? "accuracy" : "damage");
strncat(retbuf, buf, HUGEBUFLEN);
} else if (pctmod < 0) {
sprintf(buf, "^%dYour low %s will decrease your %s with this weapon.^n\n", C_BROWN,
getattrname(f->val[0]),
(f->val[0] == A_AGI) ? "accuracy" : "damage");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
i = B_TRUE;
}
}
// blank line
strncat(retbuf, "\n", HUGEBUFLEN);
// skill type?
if (isknown(o)) {
f = hasflag(o->flags, F_USESSKILL);
if (f && (f->val[0] != SK_NONE)) {
enum SKILLLEVEL slev;
slev = getskill(player, f->val[0]);
sprintf(buf, "^nIt falls into the '%s' category (your skill: ",getskillname(f->val[0]));
strncat(retbuf, buf, HUGEBUFLEN);
sprintf(buf, "^%d%s^n).\n", getskilllevelcolour(slev), getskilllevelname(getskill(player, f->val[0])) );
strncat(retbuf, buf, HUGEBUFLEN);
}
}
if (hasflag(o->flags, F_NOBLESS)) {
sprintf(buf, "%s cannot be blessed or cursed.\n", OB1(o,"It","They") );
strncat(retbuf, buf, HUGEBUFLEN);
} else {
if (isblessknown(o)) {
if (o->blessed == B_BLESSED) {
sprintf(buf, "%s a blessing bestowed upon %s.\n",
OB1(o,"It has","They have"),
OB1(o,"it","them"));
strncat(retbuf, buf, HUGEBUFLEN);
} else if (o->blessed == B_CURSED) {
sprintf(buf, "%s cursed.\n", OB1(o,"It is","They are"));
strncat(retbuf, buf, HUGEBUFLEN);
}
} else {
sprintf(buf, "%s might be blessed or cursed.\n", OB1(o,"It","They"));
strncat(retbuf, buf, HUGEBUFLEN);
}
}
if (o->contents->first) {
object_t *oo;
int showcontents = B_TRUE;
if ((o->type->id == OT_SPELLBOOK) && !isknown(o)) {
showcontents = B_FALSE;
}
if (showcontents) {
if (o->type->id == OT_SPELLBOOK) {
sprintf(buf, "\n%s contain%s the following spells:\n", OB1(o,"It","They"), OBS1(o));
} else {
sprintf(buf, "\n%s currently contain%s:\n", OB1(o,"It","They"), OBS1(o));
}
strncat(retbuf, buf, HUGEBUFLEN);
for (oo = o->contents->first ;oo ; oo = oo->next) {
char contentname[BUFLEN];
getobname(oo, contentname, oo->amt);
sprintf(buf, " - %s", contentname);
if (o->type->id == OT_SPELLBOOK) {
char lbuf[BUFLEN];
sprintf(lbuf, " (Lv %d)%s", getspelllevel(oo->type->id),
lfhasflagval(player, F_CANCAST, oo->type->id, NA, NA, NULL) ?
" [known]" : "");
strcat(buf, lbuf);
}
strcat(buf, "\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
}
rec = findrecipefor(o->type->id);
if (rec && canmakerecipe(player, rec)) {
sprintf(buf, "\nYour cooking skill will allow you to make this using these ingredients:\n");
strncat(retbuf, buf, HUGEBUFLEN);
for (i = 0; i < rec->ningredients; i++) {
objecttype_t *inot;
int incount,inconsume;
inot = findot(rec->ingredient[i]);
incount = rec->count[i];
inconsume = rec->consume[i];
sprintf(buf, " - %d x %s", incount, inot->name);
if (!inconsume) {
strcat(buf, " (not consumed)");
}
strcat(buf, "\n");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
return retbuf;
}
char *makedesc_race(enum RACE rid, char *retbuf, int showextra) {
race_t *r;
char buf[HUGEBUFLEN];
flag_t *retflag[MAXCANDIDATES],*f;
int nretflags,i;
flagpile_t *doneflags;
doneflags = addflagpile(NULL, NULL);
strcpy(retbuf, "");
r = findrace(rid);
if (showextra) {
int a;
int curidx,donesomething;
char bonheading[BUFLEN],penheading[BUFLEN];
sprintf(bonheading, "^%dStrengths^n:\n", C_WHITE);
sprintf(penheading, "^%dWeaknesses^n:\n", C_WHITE);
// stats
snprintf(buf, HUGEBUFLEN, "HD: %-3d ", gethitdicerace(r));
strncat(retbuf, buf, HUGEBUFLEN);
for (a = 0; a < MAXATTS; a++) {
char ch[BUFLENTINY];
int col;
f = hasflagval(r->flags, F_STARTATT, a, NA, NA, NULL);
if (f) {
switch (f->val[1]) {
case AT_RANDOM: sprintf(ch, "?"); col = C_GREY; break;
case AT_EXLOW: sprintf(ch, "%-4s", "xxxx"); col = C_MAGENTA; break;
case AT_VLOW: sprintf(ch, "%-4s", "xxx"); col = C_RED; break;
case AT_LOW: sprintf(ch, "%-4s", "xx"); col = C_RED; break;
case AT_LTAVERAGE: sprintf(ch, "%-4s", "x"); col = C_RED; break;
case AT_GTAVERAGE: sprintf(ch, "%-4s", "+"); col = C_GREEN; break;
case AT_HIGH: sprintf(ch, "%-4s", "++"); col = C_GREEN; break;
case AT_VHIGH: sprintf(ch, "%-4s", "+++"); col = C_GREEN; break;
case AT_EXHIGH: sprintf(ch, "%-4s", "++++"); col = C_BOLDBLUE; break;
default:
case AT_AVERAGE: sprintf(ch, "%-4s", "-"); col = C_GREY; break;
}
} else {
sprintf(ch, "%-4s", "?");
col = C_GREY;
}
sprintf(buf, "^n%s:^%d%s ^n", getattrabbrev(a), col, ch);
strncat(retbuf, buf, HUGEBUFLEN);
}
strncat(retbuf, "\n\n", HUGEBUFLEN);
snprintf(buf, HUGEBUFLEN, "%s\n\n", r->desc);
strncat(retbuf, buf, HUGEBUFLEN);
//////////////////////////////////////////////
// bonuses
//////////////////////////////////////////////
strncat(retbuf, bonheading, HUGEBUFLEN);
// manually specified bonuses
getflags(r->flags, retflag, &nretflags, F_BONDESC, F_NONE);
curidx = 0;
if (nretflags) {
donesomething = B_TRUE;
while (donesomething) {
donesomething = B_FALSE;
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->val[0] == curidx) {
snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text);
strncat(retbuf, buf, HUGEBUFLEN);
donesomething = B_TRUE;
curidx++;
break;
}
}
}
}
// auto bonuses from flags
for (f = r->flags->first ; f ; f = f->next) {
char *p;
objecttype_t *ot;
int power;
strcpy(buf, "");
switch (f->id) {
case F_AUTOCREATEOB:
p = makeplural(f->text);
sprintf(buf, "Automatically creates %s around itself.", p);
free(p);
break;
case F_AQUATIC: strcpy(buf, "Moves normally through water"); break;
case F_AWARENESS: strcpy(buf, "Can see in all directions."); break;
case F_CANEATRAW: strcpy(buf, "Can safely digest raw meat."); break;
case F_CANWILL:
ot = findot(f->val[0]);
sprintf(buf, "%s: %s", (ot->obclass->id == OC_ABILITY) ? "Ability" : "Spell",
ot->name);
texttospellopts(f->text, "pw:", &power, NULL);
if (power) {
strcat(buf, " (power ");
strcat(buf, roman(power));
strcat(buf, ")");
}
break;
case F_DODGES: strcpy(buf, "Can dodge attacks into adjacent locations"); break;
case F_DTIMMUNE:
if (!hasflag(doneflags, F_DTIMMUNE)) {
if (f->val[0] == DT_ALL) {
sprintf(buf, "Immune to %s.", getdamname(DT_ALL));
} else {
char buf2[BUFLEN];
int first = B_TRUE,n;
strcpy(buf, "");
for (n = 0; n < MAXDAMTYPE; n++) {
if (basedamagetype(n) != n) continue;
if (isimmuneto(r->flags, n, B_FALSE)) {
if (first) {
sprintf(buf2, "Immune to: %s", getdamname(n));
first = B_FALSE;
} else {
sprintf(buf2, ", %s", getdamname(n));
}
strcat(buf, buf2);
}
}
}
addflag(doneflags, F_DTIMMUNE, B_TRUE, NA, NA, NULL);
}
break;
case F_DTRESIST:
if (!hasflag(doneflags, F_DTRESIST)) {
if (f->val[0] == DT_ALL) {
sprintf(buf, "Resistant to %s.", getdamname(DT_ALL));
} else {
char buf2[BUFLEN];
int first = B_TRUE,n;
strcpy(buf, "");
for (n = 0; n < MAXDAMTYPE; n++) {
if (basedamagetype(n) != n) continue;
if (isresistantto(r->flags, n, B_FALSE)) {
if (first) {
sprintf(buf2, "Resistant to: %s", getdamname(n));
first = B_FALSE;
} else {
sprintf(buf2, ", %s", getdamname(n));
}
strcat(buf, buf2);
}
}
}
addflag(doneflags, F_DTRESIST, B_TRUE, NA, NA, NULL);
}
break;
case F_ENHANCESMELL: sprintf(buf, "Enhanced sense of smell (range %d)", f->val[0]); break;
case F_FLYING: sprintf(buf, "Can fly at will"); break;
case F_HEAVYBLOW: sprintf(buf, "Attacks will knock enemies backwards"); break;
case F_HUMANOID: sprintf(buf, "Can use weapons and armour."); break;
case F_LEVITATING: sprintf(buf, "Can levitate at will"); break;
case F_MEDITATES: sprintf(buf, "Meditates to retain awareness while sleeping."); break;
case F_MPMOD: if (f->val[0] > 0) sprintf(buf, "+%d Mana", f->val[0]); break;
case F_NOSLEEP: sprintf(buf, "Does not sleep"); break;
case F_PACKATTACK: sprintf(buf, "Deals extra damage when in a pack."); break;
case F_PHALANX: sprintf(buf, "Gains extra defence when in a pack."); break;
case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break;
case F_QUICKBITE: sprintf(buf, "Can bite wounded enemies for extra damage"); break;
case F_REGENERATES: sprintf(buf, "Automatically regenerates health."); break;
case F_RESISTMAG: sprintf(buf, "Magic-resistant"); break;
case F_SEEINDARK: sprintf(buf, "Darkvision (range %d)", f->val[0]); break;
case F_SEEINVIS: sprintf(buf, "Can see invisible things"); break;
case F_SILENTMOVE: sprintf(buf, "Moves silently"); break;
case F_SPIDERCLIMB: sprintf(buf, "Adheres to walls"); break;
case F_STABILITY: sprintf(buf, "Will not fall on slippery ground."); break;
case F_STARTSKILL: sprintf(buf, "%s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); break;
case F_STENCH: sprintf(buf, "Emits a foul odour which affects others"); break;
case F_TREMORSENSE: sprintf(buf, "Can sense vibrations (range %d)", f->val[0]); break;
case F_VISRANGEMOD: if (f->val[0] > 0) sprintf(buf, "Enhanced vision range (+%d)", f->val[0]); break;
default:
break;
}
if (strlen(buf)) {
strncat(retbuf, "@- ", HUGEBUFLEN);
strcat(buf, "\n");
strncat(retbuf, buf, HUGEBUFLEN);
curidx++;
}
}
if (curidx == 0) {
strncat(retbuf, "^n@None.\n", HUGEBUFLEN);
}
//////////////////////////////////////////////
// penalties
//////////////////////////////////////////////
strncat(retbuf, penheading, HUGEBUFLEN);
// manually specified penalties
curidx = 0;
getflags(r->flags, retflag, &nretflags, F_PENDESC, F_NONE);
if (nretflags) {
donesomething = B_TRUE;
while (donesomething) {
donesomething = B_FALSE;
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->val[0] == curidx) {
snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text);
strncat(retbuf, buf, HUGEBUFLEN);
donesomething = B_TRUE;
curidx++;
break;
}
}
}
}
// auto penalties from flags
for (f = r->flags->first ; f ; f = f->next) {
material_t *mt;
strcpy(buf, "");
switch (f->id) {
case F_CARNIVORE: sprintf(buf, "Will only eat meat."); break;
case F_DEAF: sprintf(buf, "Deaf"); break;
case F_DIURNAL: sprintf(buf, "Sleeps at night."); break;
case F_DTVULN:
if (!hasflag(doneflags, F_DTVULN)) {
if (f->val[0] == DT_ALL) {
sprintf(buf, "Vulnerable to %s.", getdamname(DT_ALL));
} else {
char buf2[BUFLEN];
int first = B_TRUE,n;
strcpy(buf, "");
for (n = 0; n < MAXDAMTYPE; n++) {
if (basedamagetype(n) != n) continue;
if (isvulnto(r->flags, n, B_FALSE)) {
if (first) {
sprintf(buf2, "Vulnerable to: %s", getdamname(n));
first = B_FALSE;
} else {
sprintf(buf2, ", %s", getdamname(n));
}
strcat(buf, buf2);
}
}
}
addflag(doneflags, F_DTVULN, B_TRUE, NA, NA, NULL);
}
break;
case F_FASTMETAB: sprintf(buf, "Fast metabolism (needs to eat often)"); break;
case F_MATVULN:
mt = findmaterial(f->val[0]);
sprintf(buf, "Takes %d%% damage from weapons made of %s.", f->val[1], mt->name);
break;
case F_MPMOD: if (f->val[0] < 0) sprintf(buf, "%d Mana", f->val[0]); break;
case F_NEEDSWATER: sprintf(buf, "Will suffocate without water"); break;
case F_NOCTURNAL: sprintf(buf, "Sleeps during the day."); break;
case F_NOPACK: sprintf(buf, "Cannot carry objects."); break;
case F_SIZE:
if (hasflag(r->flags, F_HUMANOID) && (f->val[0] != SZ_HUMAN)) {
sprintf(buf, "Only specially sized armour will fit.");
}
break;
case F_STAYINROOM:
sprintf(buf, "Will not leave its home territory."); break;
break;
case F_TAMABLE:
sprintf(buf, "Susceptible to bribery."); break;
break;
case F_VEGETARIAN: sprintf(buf, "Will not eat meat."); break;
case F_VISRANGEMOD: if (f->val[0] < 0) sprintf(buf, "Reduced vision range (%d)", f->val[0]); break;
case F_PARTVEGETARIAN: sprintf(buf, "Will only eat meat when hungry."); break;
default:
break;
}
if (strlen(buf)) {
strncat(retbuf, "@- ", HUGEBUFLEN);
strcat(buf, "\n");
strncat(retbuf, buf, HUGEBUFLEN);
curidx++;
}
}
if (curidx == 0) {
strncat(retbuf, "^n@None.\n", HUGEBUFLEN);
}
}
free(doneflags);
return retbuf;
}
char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite) {
skill_t *sk;
enum SKILLLEVEL slev;
char buf[BUFLEN];
int i;
strcpy(retbuf, "");
sk = findskill(skid);
// title
sprintf(buf, "%s\n\n", sk->desc);
strncat(retbuf, buf, HUGEBUFLEN);
// descriptions
for (slev = PR_INEPT; slev <= PR_MASTER; slev++) {
int found = B_FALSE;
int hilitethis = B_FALSE;
if ((levhilite != PR_INEPT) && (slev == levhilite)) {
hilitethis = B_TRUE;
}
for (i = 0; i < sk->nskilldesc; i++) {
if (sk->skilldesclev[i] == slev) {
if (slev == PR_INEPT) {
// extra blank line after this one
snprintf(buf, BUFLEN, "%s\n\n",sk->skilldesctext[i]);
} else {
char atxlevel[BUFLEN];
snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(sk->skilldesclev[i]));
snprintf(buf, BUFLEN, "%s%-18s%s: %s\n", // right-align "at xx level"
hilitethis ? "^w" : "", atxlevel, hilitethis ? "^n" : "",
sk->skilldesctext[i]);
}
strncat(retbuf, buf, HUGEBUFLEN);
found = B_TRUE;
}
}
if (!found && (slev != PR_INEPT)) {
char atxlevel[BUFLEN];
snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(slev));
snprintf(buf, BUFLEN, "%s%-18s%s: %s\n", // right-align "at xx level"
hilitethis ? "^w" : "", atxlevel, hilitethis ? "^n" : "", "No special effects.");
strncat(retbuf, buf, HUGEBUFLEN);
}
}
return retbuf;
}
char *makedesc_spell(objecttype_t *ot, char *retbuf) {
char buf[BUFLEN];
flag_t *retflag[MAXCANDIDATES], *f;
int nretflags,i,power,range,stamcost;
strcpy(retbuf, "");
if (ot->obclass->id == OC_SPELL) {
power = getspellpower(player, ot->id);
} else {
power = -1;
}
range = getspellrange(player, ot->id, power);
snprintf(buf, BUFLEN, "%s\n", ot->desc);
strncat(retbuf, buf, BUFLEN);
// extra spell/abil descriptions
getflags(ot->flags, retflag, &nretflags, F_EXTRADESC, F_NONE);
if (nretflags) {
int order;
for (order = 0; order < 5; order++) {
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if ((f->val[0] == order) ||
((f->val[0] == NA) && (order == 0))) {
snprintf(buf, BUFLEN, "%s^n\n", f->text);
strncat(retbuf, buf, BUFLEN);
}
}
}
}
if (nretflags) {
strcat(retbuf, "\n");
}
// properties
f = hasflag(ot->flags, F_SPELLLEVEL);
if (f) {
char schoollist[BUFLEN];
strcpy(schoollist, "");
getflags(ot->flags, retflag, &nretflags, F_SPELLSCHOOL, F_NONE);
for (i = 0; i < nretflags; i++) {
if (streq(schoollist, "")) { // first one
strcpy(schoollist, getschoolname(retflag[i]->val[0]));
} else {
strcat(schoollist, "/");
strcat(schoollist, getschoolname(retflag[i]->val[0]));
}
}
assert(strlen(schoollist));
sprintf(buf, "It is a level %d %s spell.\n",f->val[0], schoollist);
strncat(retbuf, buf, BUFLEN);
}
if (getmpcost(player, ot->id) == 0) {
sprintf(buf, "You can use this %s at will.\n", (ot->obclass->id == OC_ABILITY) ? "ability" : "spell");
strncat(retbuf, buf, BUFLEN);
} else {
i = getmpcost(NULL, ot->id);
if (i > 0) {
if (hasflag(ot->flags, F_ONGOING)) {
sprintf(buf, "It takes ^%c%d MP^n to keep active - this is an ongoing cost.\n",(player->mp >= i) ? 'g' : 'b', i);
} else {
sprintf(buf, "It costs ^%c%d MP^n to cast.\n",(player->mp >= i) ? 'g' : 'b', i);
}
strncat(retbuf, buf, BUFLEN);
}
}
stamcost = getstamcost(player, ot->id);
if (stamcost > 0) {
sprintf(buf, "It costs %d stamina to use.\n",stamcost);
strncat(retbuf, buf, HUGEBUFLEN);
}
f = hasflag(ot->flags, F_CASTINGTIME);
if (f) {
sprintf(buf, "It takes %d turns to cast.\n",f->val[0]);
} else {
sprintf(buf, "It takes effect instantly.\n");
}
strncat(retbuf, buf, HUGEBUFLEN);
strncat(retbuf, "\n", HUGEBUFLEN);
if (ot->obclass->id == OC_SPELL) {
if (power > 0) {
sprintf(buf, "^gYou can cast it at power level %d (maximum %d).\n",power, getspellmaxpower(ot->id));
} else {
sprintf(buf, "^BIt is too powerful for you to cast (maximum power %d).\n", getspellmaxpower(ot->id));
}
strncat(retbuf, buf, BUFLEN);
if (range != UNLIMITED) {
sprintf(buf, "At this power, it has a range of %d cell%s.\n",range, (range == 1) ? "" : "s");
strncat(retbuf, buf, BUFLEN);
}
}
return retbuf;
}
// if wantunknown is set, lsit spells we DONT know.
// otherwise list spells we DO know.
// only include spells which cost <= mpcutoff
void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2, enum SPELLSCHOOL wantschool, int wantunknown, int wantlowmp, int wanttoohard, int mpcutoff) {
char ch;
flag_t *f;
char buf[BUFLEN];
char buf2[BUFLEN];
char costbuf[BUFLEN];
enum OBTYPE poss[MAXCANDIDATES];
int mpcost[MAXCANDIDATES];
char mpdesc[MAXCANDIDATES][BUFLEN];
int validspell[MAXCANDIDATES];
int err[MAXCANDIDATES]; // will be E_OK, e_notready, e_toopowerful, e_nomp
int deactspell[MAXCANDIDATES];
int nposs = 0;
int i,n,lev;
enum SPELLSCHOOL lastschool;
objecttype_t *ot;
nposs = 0;
for (i = SS_NONE+1; i < SS_LAST; i++) {
// school doesn't match the one we're asking for?
if ((wantschool != SS_NONE) && (i != wantschool)) {
continue;
}
// only god gets divine ones
if ((i == SS_DIVINE) && !hasjob(lf, J_GOD)) {
continue;
}
for (lev = 0; lev <= MAXSPELLLEV; lev++) {
// get list of spells/abilities we can cast at will
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) || (ot->obclass->id == OC_ABILITY)) {
// matches the current level?
if (getspelllevel(ot->id) == lev) {
f = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL);
if (!wantunknown && f) {
if (hasflagval(ot->flags, F_SPELLSCHOOL, i, NA, NA, NULL)) {
// make sure we don't already have it.
int found = B_FALSE;
for (n = 0; n < nposs; n++) {
if (poss[n] == ot->id) {
found = B_TRUE;
break;
}
}
if (!found) {
// add to list
poss[nposs] = ot->id;
deactspell[nposs] = B_FALSE; // default
mpcost[nposs] = -1;
if (f->val[2] == NA) {
snprintf(mpdesc[nposs], BUFLEN, "(ready)");
validspell[nposs] = B_TRUE;
err[nposs] = E_OK;
} else {
if (f->val[1] == f->val[2]) {
snprintf(mpdesc[nposs], BUFLEN, "(ready)");
validspell[nposs] = B_TRUE;
err[nposs] = E_OK;
} else {
snprintf(mpdesc[nposs], BUFLEN, "(%d/%d)",f->val[1],f->val[2]);
validspell[nposs] = B_FALSE;
err[nposs] = E_NOTREADY;
}
}
nposs++;
}
}
}
} // end if level ok
} // end if spell/ability
} // end foreach objecttype
// if we can't cast spells from this school, then just go to next spell.
if (getschoolskill(i) != SK_NONE) {
if (!getskill(lf, getschoolskill(i))) {
continue;
}
}
if (!lfhasflag(lf, F_NOSPELLS)) {
// get list of spells we can cast using mp
for (ot = objecttype ; ot ; ot = ot->next) {
if ((ot->obclass->id == OC_SPELL) && (getspelllevel(ot->id) == lev)) { // is it a spell?
if (hasflagval(ot->flags, F_SPELLSCHOOL, i, NA, NA, NULL)) { // from the current school?
// not using 'cancast' here because we want to list spells
// even if we don't have enough mp
f = lfhasflagval(lf, F_CANCAST, ot->id, NA, NA, NULL);
if ((f && !wantunknown) || (!f && wantunknown)) {
int cost;
int found = B_FALSE;
cost = getmpcost(lf, ot->id);
for (n = 0; n < nposs; n++) {
if (poss[n] == ot->id) {
found = B_TRUE;
break;
}
}
if (!found) {
int power;
// add to list
poss[nposs] = ot->id;
mpcost[nposs] = cost;
deactspell[nposs] = B_FALSE; // default
power = getspellpower(lf, ot->id);
if (power > 0) {
if (hasactivespell(lf, ot->id)) {
cost = 0;
mpcost[nposs] = 0;
strcpy(mpdesc[nposs], "(Deactivate, at will)");
deactspell[nposs] = B_TRUE;
} else {
getspellcosttext(lf, ot->id, power, mpdesc[nposs]);
}
if (mpcost[nposs] <= mpcutoff) {
validspell[nposs] = B_TRUE;
err[nposs] = E_OK;
} else {
validspell[nposs] = B_FALSE;
err[nposs] = E_NOMP;
}
} else {
snprintf(mpdesc[nposs], BUFLEN, "(too hard)");
validspell[nposs] = B_FALSE;
err[nposs] = E_TOOPOWERFUL;
}
nposs++;
}
}
}
} // end if is_a_spell and level_matches
} // end forech ob type
} // end if we can cast spells
} // end foreach spell level
} // end foreach spell school
if (lfhasflag(lf, F_NOSPELLS) && (nposs == 0)) {
msg("%ss cannot use magic!", lf->race->name);
return;
}
// list player's magic...
ch = 'a';
initprompt(pr, ques);
prompt.maycancel = B_TRUE;
addpromptq(pr, ques2);
lastschool = SS_LAST;
for (i = 0; i < nposs; i++) {
int addit = B_FALSE;
int power;
enum SPELLSCHOOL thisschool = SS_NONE;
ot = findot(poss[i]);
assert(ot);
power = getspellpower(lf, poss[i]);
// heading
thisschool = getspellschoolknown(lf, poss[i]);
if (thisschool != lastschool) {
lastschool = thisschool;
addheading(pr, getschoolname(lastschool));
}
getspellname(ot->id, player, buf2);
if (deactspell[i]) {
strcat(buf2, "/deact");
}
if (validspell[i]) {
strcpy(costbuf, "");
} else {
sprintf(costbuf, "(NOT %s) ", (ot->obclass->id == OC_SPELL) ? "CASTABLE" : "USABLE");
}
strcat(costbuf, mpdesc[i]);
snprintf(buf, BUFLEN, "%-30s%s", buf2, costbuf);
if (validspell[i]) {
addit = B_TRUE;
} else if ((err[i] == E_NOMP) && wantlowmp) {
addit = B_TRUE;
} else if ((err[i] == E_TOOPOWERFUL) && wanttoohard) {
addit = B_TRUE;
} else if (err[i] == E_NOTREADY) {
addit = B_TRUE;
}
if (addit) {
char *longdesc;
// letter doesn't matter
longdesc = malloc(HUGEBUFLEN * sizeof(char));
makedesc_spell(ot, longdesc);
addchoice(pr, 'a', buf2, buf, ot, longdesc);
free(longdesc);
}
}
}
void domagic(enum OBTYPE spellid, int cellx, int celly) {
flag_t *f;
objecttype_t *ot = NULL;
int finished;
if (lfhasflag(player, F_RAGE)) {
msg("You are too enraged to use magic or abilities!");
return;
}
// init the prompt if required.
if (spellid == OT_NONE) {
makespellchoicelist(&prompt, player, "Use which spell/ability:","Describe which spell/ability:", SS_NONE, B_FALSE, B_TRUE, B_FALSE, player->mp);
}
finished = B_FALSE;
while (!finished) {
// ask for spell if required
if (spellid == OT_NONE) {
if (prompt.nchoices > 0) {
getchoicestr(&prompt, B_TRUE, B_FALSE);
ot = prompt.result;
if (ot) {
spellid = ot->id;
}
} else {
msg("You don't have any spells or abilities!");
return;
}
} // end if spellid == NONE
// if still no spell, finish.
if (spellid == OT_NONE) {
clearmsg();
msg("Cancelled.");
return;
} else { // otherwise either cast the spell or describe it
cell_t *targcell = NULL;
lifeform_t *targlf = NULL;
if (prompt.whichq == 0) { // cast the spell
// update lastcmd
f = hasflag(player->flags, F_LASTCMD);
if (f) {
f->val[2] = spellid;
}
// try to cast it
ot = findot(spellid);
// specified x/y coords from a repeated cmd?
if (cellx == NA) {
targcell = NULL;
targlf = NULL;
} else {
targcell = getcellat(player->cell->map, cellx, celly);
targlf = haslf(targcell);
}
// should always work...
if (ot->obclass->id == OC_SPELL) {
castspell(player, spellid, targlf, NULL, targcell, NULL, NULL);
} else {
useability(player, spellid, targlf, targcell);
}
finished = B_TRUE;
} else { // describe it
describespell(ot);
// prompt again!
spellid = OT_NONE;
}
} // end cast/describe test
} // end while not finished
}
void domemmagic(void) {
char ch;
int slot;
objecttype_t *ot;
makespellchoicelist(&prompt, player, "Memorise which spell/ability:","Describe which spell/ability",SS_NONE, B_FALSE, B_TRUE, B_TRUE, player->maxmp);
if (prompt.nchoices <= 0) {
msg("You don't have any spells or abilities!");
return;
}
ch = askchar("Memorise in which slot (0-9, n to cancel)", "1234567890n","", B_FALSE, B_TRUE);
if (!isdigit(ch)) {
return;
}
slot = ch - '0';
getchoicestr(&prompt, B_FALSE, B_FALSE);
ot = (objecttype_t *)prompt.result;
if (ot) {
flag_t *f;
f = lfhasflagval(player, F_SHORTCUT, slot, NA, NA, NULL);
if (f) {
killflag(f);
}
addflag(player->flags, F_SHORTCUT, slot, NA, NA, ot->name);
msg("Shortcut %d set to '%s'",slot,ot->name);
}
}
void domsghist(void) {
int i;
int y;
cls();
mvwprintw(mainwin, 0, 0, "MESSAGE HISTORY:");
y = 1;
for (i = 0; i < nmsghist; i++) {
wmove(mainwin, y, 0);
textwithcol(mainwin, msghist[i]);
y++;
}
wrefresh(mainwin);
getch();
// restore screen
restoregamewindows();
}
void dooperate(obpile_t *op) {
object_t *o;
// operable objects here?
for (o = player->cell->obpile->first; o ; o = o->next) {
//if (isoperable(o) && canpickup(player, o, 1)) {
if (isoperable(o)) {
char obname[BUFLEN],buf[BUFLEN];
char verb[BUFLEN];
int ch;
getobname(o, obname, o->amt);
strcpy(verb, getoperateverb(o));
capitalise(verb);
snprintf(buf, BUFLEN, "There %s %s here. %s %s",
OB1(o,"is","are"),
obname, verb,
OB1(o,"it","one"));
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
operate(player, o, NULL);
return;
}
}
}
// ask which object to read
o = askobject(op, "Operate what", NULL, 'o', AO_OPERABLE);
if (o) {
operate(player, o, NULL);
}
}
int dopickup(obpile_t *op, int forceask) {
int obcount;
//object_t *o = NULL;
int howmany = ALL;
int i;
lifeform_t *fromlf = NULL;
object_t *fromob = NULL;
char lfname[BUFLEN],fromobname[BUFLEN];
char buf[BUFLEN];
int needtoask = B_TRUE;
int failed = B_FALSE;
if (op->owner) {
fromlf = op->owner;
getlfname(fromlf, lfname);
} else if (op->parentob) {
fromob = op->parentob;
getobname(fromob, fromobname, fromob->amt);
}
obcount = countobs(op, B_TRUE);
// anything here?
if (obcount == 0) {
failed = B_TRUE;
} else if (!fromlf && (obcount == 1)) {
object_t *o;
// find first visible object
o = op->first;
while (o && !canseeob(player, o)) {
o = o->next;
}
if (o) {
if ((o->amt == 1) && (!forceask)) {
// just get it
howmany = ALL;
retobs[0] = o;
retobscount[0] = o->amt;
nretobs = 1;
needtoask = B_FALSE;
}
} else {
failed = B_TRUE;
}
}
if (failed) {
if (fromlf) {
msg("%s is not carrying anything!", lfname);
} else if (fromob) {
msg("%s is empty!", fromobname);
} else {
msg("There is nothing here to pick up!");
}
return B_TRUE;
}
if (needtoask) {
if (fromlf) {
snprintf(buf, BUFLEN, "Take what from %s",lfname);
} else if (fromob) {
snprintf(buf, BUFLEN, "Take what out of %s",fromobname);
} else {
strcpy(buf, "Pick up what");
}
// prompt which one to pick up
askobjectmulti(op, buf, AO_NONE);
}
if (nretobs <= 0) {
return B_TRUE;
} else if (lfhasflag(player, F_NOPACK)) {
msg("You lack the ability to carry things!");
return B_TRUE;
}
for (i = 0; i < nretobs; i++) {
if (pickup(player, retobs[i],retobscount[i], B_TRUE, B_TRUE)) {
break;
}
}
/*
if (o) {
pickup(player, o, howmany);
} else {
return B_TRUE;
}
*/
return B_FALSE;
}
void doenter(lifeform_t *lf) {
object_t *enterob;
if (isplayer(lf)) {
// check for shops first
enterob = hasobwithflag(lf->cell->obpile, F_SHOP);
if (enterob) {
char ch,obname[BUFLEN],buf[BUFLEN];
getobname(enterob,obname, 1);
sprintf(buf, "Enter %s?", obname);
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
shop(lf, enterob);
return;
}
}
enterob = hasobwithflagval(lf->cell->obpile, F_CLIMBABLE, D_IN, NA, NA, NULL);
if (enterob) {
usestairs(lf, enterob, B_TRUE, B_FALSE);
return;
}
// try to go down
dostairs(D_DOWN);
}
}
void doexplain(char *question) {
askcoords(question, "", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE);
restoregamewindows();
msg("Done.");
}
void dofinaloblist(obpile_t *op) {
object_t *o;
o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE, '\0', AO_NONE, F_NONE);
while (o) {
// describe it
describeob(o);
// ask for another one
o = doaskobject(op, "Your final possessions were", NULL, B_TRUE, B_FALSE, B_TRUE,'\0', AO_NONE, F_NONE);
}
real_clearmsg(B_TRUE);
}
void dofire(void) {
if (shoot(player)) {
// why not?
switch (reason) {
case E_NOTEQUIPPED:
msg("You have no firearm equipped!");
break;
case E_NOTARGET:
msg("You have no target selected!");
break;
case E_NOAMMO:
msg("You are out of ammo!");
break;
default:
msg("You cannot fire for some reason!");
break;
}
}
}
void dohelp(char helpmode) {
int h;
int y;
command_t *c;
char *ftext= "%c %s";
int done = B_FALSE;
int ch;
h = getmaxy(mainwin);
while (!done) {
cls();
if (helpmode == '?') {
initprompt(&prompt, "What would you like help with (ESC when done)?");
addchoice(&prompt, 'k', "Keyboard Commands", NULL, NULL, NULL);
addchoice(&prompt, 'r', "Race Descriptions", NULL, NULL, NULL);
addchoice(&prompt, 's', "Skill Descriptions", NULL, NULL, NULL);
addchoice(&prompt, 'g', "God Descriptions", NULL, NULL, NULL);
addchoice(&prompt, '-', "(done)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoice(&prompt);
switch (ch) {
case '-':
case '\0':
done = B_TRUE;
break;
default:
helpmode = ch;
break;
}
} else if (helpmode == 'k') {
centre(mainwin,C_WHITE, 0, "KEYBOARD COMMAND REFERENCE");
y = 2;
for (c = firstcommand ; c ; c = c->next) {
mvwprintw(mainwin, y, 0, ftext, c->ch, c->desc); y++;
if (y >= (h-2)) {
centre(mainwin,C_WHITE, h-1, "--More--");
getch();
cls();
y = 2;
}
}
centre(mainwin,C_WHITE, h-1, "[Press any key]");
getch();
done = B_TRUE;
} else if (helpmode == 'r') {
race_t *r;
centre(mainwin,C_WHITE, 0, "RACE REFERENCE");
y = 2;
initprompt(&prompt, "Describe which race (ESC when done)?");
for (r = firstrace ; r ; r = r->next) {
if (r->known) {
addchoice(&prompt, 'a', r->name, NULL, r, r->desc);
}
}
addchoice(&prompt, '\0', "(done)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) {
done = B_TRUE;
} else {
r = (race_t *)prompt.result;
if (r) describerace(r->id);
}
} else if (helpmode == 's') {
skill_t *sk;
centre(mainwin,C_WHITE, 0, "SKILL REFERENCE");
y = 2;
initprompt(&prompt, "Describe which skill (ESC when done)?");
for (sk = firstskill ; sk ; sk = sk->next) {
addchoice(&prompt, 'a', sk->name, NULL, sk, sk->desc);
}
addchoice(&prompt, '\0', "(done)", NULL, NULL, NULL);
prompt.maycancel = B_TRUE;
ch = getchoicestr(&prompt, B_FALSE, B_TRUE);
if (!ch) {
done = B_TRUE;
} else {
sk = (skill_t *)prompt.result;
if (sk) describeskill(sk->id, PR_INEPT);
else done = B_TRUE;
}
} else if (helpmode == 'g') {
lifeform_t *god;
centre(mainwin,C_WHITE, 0, "GOD REFERENCE");
y = 2;
god = askgod("Describe which god (ESC when done)?", B_FALSE);
if (!god) {
done = B_TRUE;
} else {
describegod(god);
}
}
}
restoregamewindows();
}
void doinventory(obpile_t *op) {
object_t *o;
char buf[BUFLEN];
float packweight,maxweight,pct;
packweight = getobpileweight(player->pack);
maxweight = getmaxcarryweight(player);
pct = (packweight / maxweight) * 100;
snprintf(buf, BUFLEN, "Inventory (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct);
o = doaskobject(op, buf, NULL, B_TRUE, B_TRUE, B_FALSE, '\0', AO_NONE, F_NONE);
while (o) {
// describe it
describeob(o);
// ask for another one
o = askobject(op, buf, NULL, '\0', AO_NONE);
}
real_clearmsg(B_TRUE);
}
void doquaff(obpile_t *op) {
object_t *o,*liquid = NULL;
// quaffable objects here? (don't need to be able to pick them up)
for (o = player->cell->obpile->first; o ; o = o->next) {
if (isdrinkable(o) && canquaff(player, o) ) {
char obname[BUFLEN];
char buf[BUFLEN];
char ch;
char drink[BUFLEN];
getobname(o, obname, o->amt);
if (o->type->obclass->id == OC_POTION) {
strcpy(drink, "Drink");
} else {
strcpy(drink, "Drink from");
}
snprintf(buf, BUFLEN, "There %s %s here. %s %s", OB1(o,"is","are"),
obname, drink, OB1(o,"it","one"));
ch = askchar(buf, "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
liquid = o;
break;
}
}
}
// ask which object to quaff
if (!liquid) {
liquid = askobjectwithflag(op, "Quaff what", NULL, 'q', AO_NONE, F_DRINKABLE);
}
if (liquid) {
if (canquaff(player, liquid)) {
if (isunknownbadobject(liquid) && skillcheck(player, A_WIS, 30, 0)) {
if (!confirm_badfeeling(liquid)) {
msg("Cancelled.");
return;
}
}
quaff(player, liquid);
} else {
switch (reason) {
case E_INSUBSTANTIAL:
msg("You need a physical body to do that!");
break;
case E_WRONGOBTYPE:
default:
msg("You can't drink that!");
break;
}
}
}
}
void donextguntarget(void) {
object_t *gun;
char gunname[BUFLEN];
int i,startpos;
int done;
lifeform_t *targ;
gun = getfirearm(player);
if (!gun) {
msg("You have no firearm equipped!");
return;
}
getobname(gun, gunname, 1);
// get current target
targ = getguntarget(player);
// find current target cell
startpos = 0; // default
for (i = 0; i < player->nlos; i++) {
cell_t *c;
c = player->los[i];
if (c->lf && (c->lf == targ)) {
startpos = i;
break;
}
}
i = startpos;
done = B_FALSE;
while (!done) {
cell_t *c;
c = player->los[i];
if (c->lf && (c->lf != player) && (c->lf != targ)) {
if (haslof(player->cell, c, LOF_NEED, NULL) && isingunrange(player, c)) {
// found one!
setguntarget(player, c->lf);
done = B_TRUE;
}
}
i++;
if (i >= player->nlos) {
i = 0;
}
if (i == startpos) {
// no new targets found - keep current one.
setguntarget(player, targ);
done = B_TRUE;
}
}
}
void dopour(obpile_t *op) {
object_t *o;
// ask which object to read
o = askobject(op, "Pour what", NULL, 'P', AO_POURABLE);
if (o) {
if (ispourable(o)) {
pour(player, o);
} else {
msg("That isn't pourable!");
}
}
}
void doquit(void) {
char ch;
ch = askchar("Really quit", "yn","n", B_TRUE, B_FALSE);
if (ch == 'y') {
setlastdam(player, "quitting");
player->alive = B_FALSE;
}
}
void doread(obpile_t *op) {
object_t *o;
if (isblind(player)) {
msg("You can't read while blind!");
return;
}
// ask which object to read
o = askobject(op, "Read what", NULL, 'r', AO_READABLE);
if (o) {
if (isreadable(o)) {
readsomething(player, o);
} else {
msg("You can't read that!");
}
}
}
void dorest(void) {
// can we rest?
char validchars[BUFLEN];
char ques[BUFLEN];
char ch;
if (check_rest_ok(player)) return;
if (needstorest(player, validchars)) {
strcpy(ques, "Rest");
ch = askchar(ques, "yn", "y", B_TRUE, B_FALSE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILBETTER, B_TRUE, NA, NA, NULL);
}
} else {
if (countnearbyhurtallies(player)) {
strcpy(ques, "Rest until nearby allies are healed?");
ch = askchar(ques, "yn", "y", B_TRUE, B_FALSE);
if (ch == 'y') {
addflag(player->flags, F_RESTUNTILALLIES, B_TRUE, NA, NA, NULL);
}
} else {
msg("You don't need to rest at the moment.");
return;
}
}
if (!lfhasflag(player, F_RESTUNTILBETTER) && !lfhasflag(player, F_RESTUNTILALLIES)) {
msg("Cancelled.");
return;
}
if (!startresting(player, B_FALSE)) {
// do the first one right away
rest(player, B_TRUE);
}
}
int doselguntarget(void) {
object_t *gun;
cell_t *where;
char buf[BUFLEN],buf2[BUFLEN];
char gunname[BUFLEN];
gun = getfirearm(player);
if (!gun) {
msg("You have no firearm equipped!");
return B_TRUE;
}
getobname(gun, gunname, 1);
snprintf(buf, BUFLEN, "Aim %s where?",gunname);
snprintf(buf2, BUFLEN, "%s->Target->",gunname);
addflag(player->flags, F_THROWING, B_TRUE, NA, NA, NULL);
where = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, getfirearmloftype(player), B_TRUE);
killflagsofid(player->flags, F_THROWING);
if (where && where->lf) {
setguntarget(player, where->lf);
} else {
setguntarget(player, NULL);
return B_TRUE;
}
return B_FALSE;
}
void dostairs(int dir) {
object_t *o;
o = hasobwithflagval(player->cell->obpile, F_CLIMBABLE, dir, NA, NA, NULL);
if (o) {
usestairs(player, o, B_TRUE, B_FALSE);
} else {
msg("There are no stairs going %s here!", getdirname(dir));
}
}
int dotakeoff(obpile_t *op) {
object_t *o;
flag_t *f;
int rv = B_TRUE;
// ask which object to read
o = askobject(op, "Take off what", NULL, 'T', AO_EQUIPPEDNONWEAPON );
if (o) {
if (isarmour(o)) {
f = hasflag(o->flags, F_EQUIPPED);
if (f) {
rv = takeoff(player, o);
} else {
msg("You are not wearing that!");
rv = B_TRUE;
}
} else {
//rv = unweild(player, o);
rv = takeoff(player, o);
}
}
return rv;
}
void dothrow(obpile_t *op) {
object_t *o;
char buf[BUFLEN],buf2[BUFLEN];
flag_t *f;
if (!hasbp(player, BP_HANDS)) {
msg("You have no hands to throw with!");
return;
}
// ask which object to throw
o = askobject(op, "Throw what", NULL, 't', AO_NONE);
if (o) {
int maxdist;
char subprompt[BUFLEN],oidbuf[BUFLENSMALL];
cell_t *where;
getobname(o, buf, 1);
f = hasflag(o->flags, F_EQUIPPED);
if (f && (f->val[0] != BP_WEAPON)) {
msg("You'll need to take it off first.");
return;
}
// calculate throw range
maxdist = getmaxthrowrange(player, o);
// ask where to throw it
snprintf(buf2, BUFLEN, "Throw %s where?",buf);
snprintf(subprompt, BUFLEN, "%s->Throw->",buf);
sprintf(oidbuf, "%ld", o->id);
addflag(player->flags, F_THROWING, B_TRUE, NA, NA, oidbuf);
where = askcoords(buf2, subprompt, TT_MONSTER, player, maxdist, LOF_NEED, B_TRUE);
killflagsofid(player->flags, F_THROWING);
if (where) {
cell_t *newwhere = NULL;
if (!haslof(player->cell, where, LOF_WALLSTOP, &newwhere)) {
if (newwhere && (newwhere != player->cell)) {
char ch;
ch = askchar("Your line of fire is blocked - really throw here", "yn", "y", B_TRUE, B_FALSE);
if (ch == 'y') {
// update destination cell.
where = newwhere;
} else return;
} else {
if (reason == E_NOLOS) {
msg("You can't see there!");
} else { // ie. E_NOLOF and no new cell
msg("You don't have a clear line of fire to there.");
}
return;
}
}
if (getcelldist(player->cell, where) > maxdist) {
if (maxdist < 1) {
msg("%s is too heavy for you to throw!",buf, OB1(o,"is","are"));
} else {
msg("You can't throw %s that far!",buf);
}
} else {
throwat(player, o, where);
}
}
}
}
// returns TRUE if escape pressed
int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, char *cmdchars, char *retchar) {
char headbuf[BUFLEN];
int ch;
int w;
w = getmaxx(mainwin);
snprintf(headbuf, w-1, "%s (continued)", heading);
(*y)++;
if (*y >= (h-3)) {
centre(mainwin,C_WHITE, h-2, MORESTRING);
if (bottomstring) {
centre(mainwin, C_WHITE, h-1, bottomstring);
}
ch = getch();
if (ch == 27) { // ESC
if (retchar) *retchar = ch;
return B_TRUE;
} else if (cmdchars && strchr(cmdchars, ch)) {
if (retchar) *retchar = ch;
return B_TRUE;
}
cls(); *y = 0;
centre(mainwin, C_WHITE, *y, headbuf);
*y += 2;
wmove(mainwin, *y, 0);
if (subheading) {
doheading(mainwin, y, 0, subheading);
}
}
return B_FALSE;
}
// draw a cell which we remember, but can't see
/*
void drawunviscell(cell_t *cell, int x, int y) {
glyph_t glyph;
object_t *o;
// copy from cell
glyph = cell->type->glyph;
if (glyph.ch == '.') {
glyph.ch = ' ';
}
// show staircases...
o = hasobwithflag(cell->obpile, F_CLIMBABLE);
if (o) {
glyph = *(getglyph(o));
}
// show dungeon features
o = hasobofclass(cell->obpile, OC_DFEATURE);
if (o) {
glyph = *(getglyph(o));
}
//mvwprintw(gamewin, y, x, "%c", glyph);
drawglyph(&glyph, x, y);
}
*/
// draw a bar as follows, with coloured background:
//
// 0123456789
// title:[ 11 / 23 ]
void drawbar(WINDOW *win, char *title, int cur, int max, int realmax, int lossamt, enum COLOUR textcol, enum COLOUR textcolwithbg, int barbg, int lossbg) {
float fcur, fmax,curpct,losspct = 0;
char buf[BUFLEN];
char numbuf[BUFLEN];
char numbuffull[BUFLEN];
char *p;
int numpad,i;
fcur = cur;
fmax = max;
curpct = (fcur / fmax) * 100;
if ((cur > 0) && (curpct < 10)) curpct = 10;
if ((cur != max) && (curpct > 90)) curpct = 90;
if (lossamt > 0) {
losspct = ((float)lossamt / fmax) * 100;
if (losspct < 10) losspct = 10;
}
if (curpct + losspct > 100) {
losspct = 100 - curpct;
}
// construct number text to fit into 10 chars
sprintf(numbuf, "%d/%d",cur,max);
if (max != realmax) strcat(numbuf, "*");
numpad = (10 - strlen(numbuf)) / 2;
p = numbuffull;
for ( i = 0; i < 10; i++) {
if (i < numpad) {
*p = ' ';
} else {
int idx;
idx = i - numpad;
if (idx < strlen(numbuf)) {
*p = numbuf[idx];
} else {
*p = ' ';
}
}
p++;
}
*p = '\0';
// show prefix
sprintf(buf, "^n%s[",title);
textwithcol(win, buf);
// show background bar and text
p = numbuffull;
for (i = 0; i < 10; i++){
enum COLOUR bgcol = BLACKBG;
int thispct;
// select bg colour...
thispct = (i+1)*10;
if (thispct <= curpct) {
bgcol = barbg;
} else if (thispct <= curpct + losspct) {
bgcol = lossbg;
} else {
bgcol = BLACKBG;
}
// set colour
if ((cur == 0) && (max != 0)) {
setcol(win, C_ORANGE+bgcol);
} else if (bgcol == BLACKBG) {
setcol(win, textcol+bgcol);
} else {
setcol(win, textcolwithbg+bgcol);
}
// show this char
waddch(win, *p);
// inc char pointer
p++;
}
// show suffix
setcol(win, C_GREY);
waddch(win, ']');
waddch(win, ' ');
waddch(win, ' ');
}
void drawglyph(glyph_t *g, int x, int y) {
int col;
if ((gamemode == GM_GAMESTARTED) && lfhasflag(player, F_RAGE)) {
col = C_RED;
} else {
col = g->colour;
}
setcol(gamewin, col);
if (g->ch > 255) {
// note: much slower
mvwprintw(gamewin, y, x, "%lc", g->ch);
} else {
mvwaddch(gamewin, y, x, g->ch);
}
unsetcol(gamewin, col);
}
void drawcursor(void) {
// move cursor to player position
wmove(gamewin, player->cell->y - viewy, player->cell->x - viewx);
//wrefresh(gamewin);
// turn on cursor
curs_set(1);
wnoutrefresh(gamewin);
doupdate();
}
void drawlevelfor(lifeform_t *lf) {
int x,y;
cell_t *cell;
map_t *map;
int ndrawn = 0;
int db = B_FALSE;
int w,h;
char buf[BUFLEN];
if (noredraw) {
return;
}
if ((gamemode == GM_GAMESTARTED) && isplayer(lf) && lf->losdirty) {
precalclos(player);
}
//dbtimestart("drawscreen");
map = lf->cell->map;
needredraw = B_FALSE;
numdraws++;
// turn off cursor
curs_set(0);
if (db) dblog("starting DRAWLEVEL");
//wclear(gamewin);
//for (y = viewy; y < viewy + viewh; y++) {
// for (x = viewx; x < viewx + vieww; x++) {
getmaxyx(gamewin, h, w);
if (db) {
dblog("first x,y checked was %d,%d",0+viewx,0+viewy);
}
for (y = 0; y < h; y++) {
for (x = 0; x < w; x++) {
glyph_t glyph;
cell = getcellat(map, x + viewx, y + viewy);
if (cell) {
getcellglyph(&glyph, cell, player);
} else {
glyph.ch = ' ';
glyph.colour = C_GREY;
}
// only draw if screen char/colour is different
if (!screenglyphmatches(x, y, &glyph)) {
drawglyph(&glyph, x, y);
/*
if (db) {
dblog(" drawing char '%lc'/%d at %d,%d (screenglyph was '%lc'/%d)\n\n",
glyph.ch, glyph.ch,
x,y,
screenglyph.ch, screenglyph.ch);
}
*/
ndrawn++;
}
}
}
if (db) {
dblog("last x,y checked was %d,%d",x+viewx,y+viewy);
}
if (db) dblog("ending DRAWLEVEL");
snprintf(buf, BUFLEN, "end. ndrawn was %d",ndrawn);
if (db) dblog("%s",buf);
//dbtimeend(buf);
// move cursor to the player's position and blit
if (ndrawn) {
drawcursor();
}
}
void doheading(WINDOW *win, int *y, int x, char *what) {
int len,i;
char *underline;
len = strlen(what) + 1;
underline = malloc(len * sizeof(char));
for (i = 0; i < len; i++) {
underline[i] = '-';
}
underline[i] = '\0';
//mvwprintw(win, *y, x, what); (*y)++;
wmove(win, *y, x);
textwithcol(win, what); (*y)++;
setcol(win, C_WHITE);
mvwprintw(win, *y, x, underline); (*y)++;
unsetcol(win, C_WHITE);
free(underline);
}
void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading) {
setcol(win, C_WHITE);
mvwprintw(mainwin, y, x, format, heading);
unsetcol(win, C_WHITE);
}
void initgfx(void) {
int msgwinh = 2;
int statwinh = 3;
setlocale(LC_CTYPE, "");
mainwin = initscr();
// colour setup
if (!has_colors()) {
printf("Terminal does not support colour.\n");
hascolour = B_FALSE;
exit(1);
}
start_color();
// 0 through 15
init_pair(C_BLACK, COLOR_BLACK, COLOR_BLACK);
init_pair(C_RED, COLOR_RED, COLOR_BLACK);
init_pair(C_GREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(C_BROWN, COLOR_YELLOW, COLOR_BLACK);
init_pair(C_YELLOW, COLOR_YELLOW, COLOR_BLACK);
init_pair(C_BLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(C_MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(C_CYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(C_GREY, COLOR_WHITE, COLOR_BLACK);
init_pair(C_YELLOW, COLOR_YELLOW, COLOR_BLACK);
init_pair(C_WHITE, COLOR_WHITE, COLOR_BLACK);
init_pair(C_BOLDCYAN, COLOR_CYAN, COLOR_BLACK);
init_pair(C_BOLDBLUE, COLOR_BLUE, COLOR_BLACK);
init_pair(C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_BLACK);
init_pair(C_BOLDGREEN, COLOR_GREEN, COLOR_BLACK);
init_pair(C_ORANGE, COLOR_RED, COLOR_BLACK);
init_pair(C_DARKGREY, COLOR_BLACK, COLOR_BLACK);
// 16 through 31
init_pair(BLUEBG+C_BLACK, COLOR_BLACK, COLOR_BLUE);
init_pair(BLUEBG+C_RED, COLOR_RED, COLOR_BLUE);
init_pair(BLUEBG+C_GREEN, COLOR_GREEN, COLOR_BLUE);
init_pair(BLUEBG+C_BROWN, COLOR_YELLOW, COLOR_BLUE);
init_pair(BLUEBG+C_YELLOW, COLOR_YELLOW, COLOR_BLUE);
init_pair(BLUEBG+C_BLUE, COLOR_BLUE, COLOR_BLUE);
init_pair(BLUEBG+C_MAGENTA, COLOR_MAGENTA, COLOR_BLUE);
init_pair(BLUEBG+C_CYAN, COLOR_CYAN, COLOR_BLUE);
init_pair(BLUEBG+C_GREY, COLOR_WHITE, COLOR_BLUE);
init_pair(BLUEBG+C_YELLOW, COLOR_YELLOW, COLOR_BLUE);
init_pair(BLUEBG+C_WHITE, COLOR_WHITE, COLOR_BLUE);
init_pair(BLUEBG+C_BOLDCYAN, COLOR_CYAN, COLOR_BLUE);
init_pair(BLUEBG+C_BOLDBLUE, COLOR_BLUE, COLOR_BLUE);
init_pair(BLUEBG+C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_BLUE);
init_pair(BLUEBG+C_BOLDGREEN, COLOR_GREEN, COLOR_BLUE);
init_pair(BLUEBG+C_ORANGE, COLOR_RED, COLOR_BLUE);
// 32 through 47
init_pair(GREENBG+C_BLACK, COLOR_BLACK, COLOR_GREEN);
init_pair(GREENBG+C_RED, COLOR_RED, COLOR_GREEN);
init_pair(GREENBG+C_GREEN, COLOR_GREEN, COLOR_GREEN);
init_pair(GREENBG+C_BROWN, COLOR_YELLOW, COLOR_GREEN);
init_pair(GREENBG+C_YELLOW, COLOR_YELLOW, COLOR_GREEN);
init_pair(GREENBG+C_BLUE, COLOR_BLUE, COLOR_GREEN);
init_pair(GREENBG+C_MAGENTA, COLOR_MAGENTA, COLOR_GREEN);
init_pair(GREENBG+C_CYAN, COLOR_CYAN, COLOR_GREEN);
init_pair(GREENBG+C_GREY, COLOR_WHITE, COLOR_GREEN);
init_pair(GREENBG+C_YELLOW, COLOR_YELLOW, COLOR_GREEN);
init_pair(GREENBG+C_WHITE, COLOR_WHITE, COLOR_GREEN);
init_pair(GREENBG+C_BOLDCYAN, COLOR_CYAN, COLOR_GREEN);
init_pair(GREENBG+C_BOLDBLUE, COLOR_BLUE, COLOR_GREEN);
init_pair(GREENBG+C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_GREEN);
init_pair(GREENBG+C_BOLDGREEN, COLOR_GREEN, COLOR_GREEN);
init_pair(GREENBG+C_ORANGE, COLOR_RED, COLOR_GREEN);
// 48 through 63
init_pair(REDBG+C_BLACK, COLOR_BLACK, COLOR_RED);
init_pair(REDBG+C_RED, COLOR_RED, COLOR_RED);
init_pair(REDBG+C_GREEN, COLOR_GREEN, COLOR_RED);
init_pair(REDBG+C_BROWN, COLOR_YELLOW, COLOR_RED);
init_pair(REDBG+C_YELLOW, COLOR_YELLOW, COLOR_RED);
init_pair(REDBG+C_BLUE, COLOR_BLUE, COLOR_RED);
init_pair(REDBG+C_MAGENTA, COLOR_MAGENTA, COLOR_RED);
init_pair(REDBG+C_CYAN, COLOR_CYAN, COLOR_RED);
init_pair(REDBG+C_GREY, COLOR_WHITE, COLOR_RED);
init_pair(REDBG+C_YELLOW, COLOR_YELLOW, COLOR_RED);
init_pair(REDBG+C_WHITE, COLOR_WHITE, COLOR_RED);
init_pair(REDBG+C_BOLDCYAN, COLOR_CYAN, COLOR_RED);
init_pair(REDBG+C_BOLDBLUE, COLOR_BLUE, COLOR_RED);
init_pair(REDBG+C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_RED);
init_pair(REDBG+C_BOLDGREEN, COLOR_GREEN, COLOR_RED);
init_pair(REDBG+C_ORANGE, COLOR_RED, COLOR_RED);
noecho();
// TODO: change back to raw mode, or make this a switch
cbreak();
//raw();
nodelay(mainwin, FALSE);
getmaxyx(mainwin, SCREENH, SCREENW);
// determine window sizes
vieww = SCREENW;
//viewh = SCREENH - 4;
//viewh = SCREENH - statwinh - msgwinh - 1;
viewh = SCREENH - statwinh - msgwinh;
// create windows
//msgwin = newwin(1, vieww, 0, 0);
msgwin = newwin(msgwinh, vieww, 0, 0);
if (!msgwin) {
dblog("Error creating msgwin.");
exit(1);
}
gamewin = newwin(viewh, vieww, msgwinh, 0);
if (!gamewin) {
dblog("Error creating gamewin.");
exit(1);
}
//statwin = newwin(statwinh, vieww, msgwinh + viewh + statwinh - 2 ,0);
statwin = newwin(statwinh, vieww, SCREENH - statwinh,0);
if (!statwin) {
dblog("Error creating statwin.");
exit(1);
}
statdirty = B_TRUE;
redraw();
refresh();
// init message buffer
strcpy(msgbuf, "");
strcpy(lastmsgbuf, "xxx");
snprintf(prevmsg, BUFLEN, "!nolastmessage!");
msgmulti = 1;
// handle sigstop (ctrl-y)
signal(SIGTSTP, handle_ctrl_y);
}
int drop(object_t *o, int count) {
object_t *newob;
obpile_t *op;
char obname[BUFLEN];
enum OBTYPE origid;
op = o->pile;
assert(op->owner);
// in case we get burduned
if (isplayer(op->owner)) statdirty = B_TRUE;
getobname(o, obname, count);
origid = o->type->id;
// have to announce this before aclling drop, because
// drop might trigger 'the xx falls down a hole' etc
if (isplayer(op->owner)) {
msg("You drop %s.",obname);
} else if (cansee(player, op->owner)) {
char ownername[BUFLEN];
getlfname(op->owner, ownername);
msg("%s drops %s.",ownername, obname);
}
newob = moveob(o, op->owner->cell->obpile, count);
if (newob) { // if drop was successful...
//taketime(op->owner, (SPEED_DROP * count));
taketime(op->owner, SPEED_DROP);
// if object wasn't changed...
/*
if (newob->type->id == origid) {
if (op->owner) {
}
}
*/
} else {
// tell the player why!
if (isplayer(op->owner)) {
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;
}
}
return B_TRUE;
}
return B_FALSE;
}
void dumpbuildingusage(void) {
int i;
objecttype_t *ot;
dblog("BEGIN BUILDING USAGE DUMP");
for (i = 0; i < nbuildingusage; i++) {
ot = findot(buildingusage[i].oid);
dblog("'%s' used %d times", ot->name, buildingusage[i].count);
}
dblog("END BUILDING USAGE DUMP");
}
void dumpoc(void) {
enum RARITY rr;
objectclass_t *oc;
dblog("BEGIN OBJECTCLASS DUMP");
for (rr = RR_FREQUENT; rr <= RR_VERYRARE; rr++ ){
dblog(" %s", getrarityname(rr));
for (oc = objectclass ; oc ; oc = oc->next) {
if (oc->rarity == rr) {
dblog(" %s", oc->name);
}
}
}
dblog("END OBJECTCLASS DUMP");
}
void dumpspells(void) {
objecttype_t *ot;
enum SPELLSCHOOL ss;
int lev;
dblog("Spell dump:");
for (ss = 0; ss < SS_LAST; ss++) {
dblog("%s", getschoolname(ss));
for (lev = 1; lev <= MAXSPELLLEV; lev++) {
dblog("\tLevel %d:", lev);
// get list of spells/abilities we can cast at will
for (ot = objecttype ; ot ; ot = ot->next) {
if (ot->obclass->id == OC_SPELL) {
// matches the current school & level?
if (hasflagval(ot->flags, F_SPELLSCHOOL, ss, NA, NA, NULL) && (getspelllevel(ot->id) == lev)) {
dblog("\t\t%s", ot->name);
}
}
}
}
}
}
void dumpweps(void) {
objecttype_t *ot;
int wantdr = 0;
flag_t *f;
skill_t *sk;
for (sk = firstskill; sk ; sk = sk->next) {
if (!isweaponskill(sk->id)) continue;
dblog("%s", sk->name);
for (wantdr = 0; wantdr < 20; wantdr++) {
for (ot = objecttype ; ot ; ot = ot->next) {
f = hasflag(ot->flags, F_DAM);
if (f && (f->val[1] == wantdr)) {
if (hasflagval(ot->flags, F_USESSKILL, sk->id, NA, NA, NULL)) {
dblog("\t%s = %d (%s)",ot->name, f->val[1], getdamname(f->val[0]));
}
}
}
}
}
}
void forceredraw(void) {
needredraw = B_TRUE;
statdirty = B_TRUE;
wclear(gamewin); // this forces a redraw even though the glyphs didn't change
drawscreen();
}
enum COLOUR getattrcolour(enum ATTRBRACKET brack) {
switch (brack) {
case AT_EXLOW: return C_BOLDMAGENTA;
case AT_VLOW: return C_MAGENTA;
case AT_LOW: return C_RED;
case AT_LTAVERAGE: return C_BROWN;
case AT_AVERAGE: return C_GREY;
case AT_GTAVERAGE: return C_GREEN;
case AT_HIGH: return C_BLUE;
case AT_VHIGH: return C_CYAN;
case AT_EXHIGH: return C_BOLDCYAN;
default:
break;
}
return C_GREY;
}
char getchoice(prompt_t *prompt) {
int i;
int y;
char ch,msghistbuf[BUFLEN],fullprompt[BUFLEN];
int sel;
int gotheadings;
int first= 0;
int nextpage = -1;
int lastline = SCREENH - 4;
more();
gotheadings = B_FALSE;
for (i = 0; i < prompt->nchoices; i++) {
if (prompt->choice[i].heading) {
gotheadings = B_TRUE;
break;
}
}
curs_set(1);
// loop until result is valid
sel = -1;
while (sel == -1) {
// show choices
cls();
y = 2;
nextpage = -1;
for (i = first; i < prompt->nchoices; i++) {
int atbottom;
atbottom = B_FALSE;
if (y > lastline) { // if we're at the bottom of the screen
atbottom = B_TRUE;
} else if (prompt->choice[i].heading && (y+1 > lastline)) {
// on a heading, and next line is at the bottom
atbottom = B_TRUE;
}
if (atbottom) {
nextpage = i;
mvwprintw(mainwin, y, 0, "--More--");
break;
}
// heading?
if (prompt->choice[i].heading) {
mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].desc);
} else {
mvwprintw(mainwin, y, 0, "%s%c - %s", gotheadings ? " " : "", prompt->choice[i].ch, prompt->choice[i].desc);
}
y++;
}
// display prompt question
snprintf(fullprompt, BUFLEN, "%s %s", prompt->q[prompt->whichq], prompt->maycancel ? "[ESC to cancel] " : "");
mvwprintw(mainwin, 0, 0, "%s", fullprompt);
wrefresh(mainwin);
// ask for choice...
ch = getch();
if ((ch == 27) && (prompt->maycancel)) { // ESC - cancel
prompt->result = NULL;
sel = -1;
break;
} else if ((ch == '\\') && (gamemode == GM_GAMESTARTED)) {
doknowledgelist();
} else if (ch == ' ') {
if (nextpage == -1) {
first = 0;
} else {
first = nextpage;
}
} else {
sel = -1;
for (i = 0 ; i < prompt->nchoices; i++) {
if (prompt->choice[i].ch == ch) {
sel = i;
break;
}
}
}
}
if (ch != 27) {
// set result pointer
prompt->result = prompt->choice[i].data;
prompt->selection = i;
}
if ((gamemode == GM_GAMESTARTED)) {
needredraw = B_TRUE;
drawscreen();
} else {
cls();
wrefresh(mainwin);
}
curs_set(0);
restoregamewindows();
snprintf(msghistbuf, BUFLEN, "%s%s",fullprompt,prompt->choice[i].desc);
addmsghist(msghistbuf);
// return NUL or result char
if (ch == 27) {
return '\0';
}
return prompt->choice[i].ch;
}
char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) {
int i;
int y;
char ch;
int sel;
int gotheadings;
int first= 0;
int nextpage = -1;
int lastline = SCREENH - 4;
char inpstring[BUFLEN];
char curheading[BUFLEN];
char msghistbuf[BUFLEN];
int doneheading;
int nvalid;
char promptstr[BUFLEN];
int showall;
int autochar = 0;
int descendy = -1;
int validchoice = -1;
showall = showallatstart;
strcpy(inpstring, "");
more();
// mark valid choices, and determine whether we have
// headings
gotheadings = B_FALSE;
for (i = 0; i < prompt->nchoices; i++) {
if (prompt->choice[i].heading) {
gotheadings = B_TRUE;
prompt->choice[i].valid = B_FALSE;
} else {
prompt->choice[i].valid = B_TRUE;
}
}
strcpy(curheading, "");
doneheading = B_FALSE;
// loop until result is valid
curs_set(1);
sel = -1;
while (sel == -1) {
int foundfirstvalid = B_FALSE;
int atbottom;
// show choices which match our input string
if (showall) {
cls();
}
y = 2;
nextpage = -1;
nvalid = 0;
foundfirstvalid = B_FALSE;
atbottom = B_FALSE;
for (i = 0; i < prompt->nchoices; i++) {
if (showall) {
if (!atbottom) {
if (y > lastline) { // if we're at the bottom of the screen
atbottom = B_TRUE;
} else if (prompt->choice[i].heading && (y+1 >= (SCREENH-2))) {
// on a heading, and next line is at the bottom
atbottom = B_TRUE;
}
if (atbottom) {
nextpage = i;
mvwprintw(mainwin, y, 0, "--' for next page--");
}
}
}
// heading?
if (prompt->choice[i].heading) {
strcpy(curheading, prompt->choice[i].desc);
doneheading = B_FALSE;
//mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].text);
prompt->choice[i].valid = B_FALSE;
} else if (strlen(inpstring)) {
int matched = B_FALSE;
// does this choice match? use ->text, not ->desc
matched = strpixmatch(prompt->choice[i].text, inpstring);
if (matched) {
prompt->choice[i].valid = B_TRUE;
nvalid++;
if (showall) {
// if we haven't printed the heading yet...
if (gotheadings && !doneheading) {
// only print if on the page
if ((i >= first) && !atbottom) {
// show heading first
mvwprintw(mainwin, y, 0, "%s", curheading);
y++;
}
doneheading = B_TRUE;
}
// only print if we're not off the bottom
if ((i >= first) && !atbottom) {
if (nvalid && !foundfirstvalid) setcol(mainwin, C_BOLDGREEN);
mvwprintw(mainwin, y, 0, "%s%s", gotheadings ? " " : "", prompt->choice[i].desc);
y++;
if (nvalid && !foundfirstvalid) unsetcol(mainwin, C_BOLDGREEN);
foundfirstvalid = B_TRUE;
}
}
} else {
prompt->choice[i].valid = B_FALSE;
}
} else {
// if we haven't printed the heading yet...
if (showall) {
if (gotheadings && !doneheading) {
// only print if on the page
if ((i >= first) && !atbottom) {
// show heading first
mvwprintw(mainwin, y, 0, "%s", curheading);
y++;
}
doneheading = B_TRUE;
}
// only print if we're not off the bottom
if ((i >= first) && !atbottom) {
mvwprintw(mainwin, y, 0, "%s%s", gotheadings ? " " : "", prompt->choice[i].desc);
y++;
}
}
}
}
// if there is not only one valid choice, clear to bottom of screen (ie overwrite any
// previous descriptions).
validchoice = -1;
// if we only ahve 1 valid choice, show description (if we have it)
if (nvalid == 1) {
// find the valid one
for (i = 0; i < prompt->nchoices; i++) {
if (prompt->choice[i].valid) {
validchoice = i;
break;
}
}
if (strlen(prompt->choice[validchoice].longdesc)) {
int dummy;
int x = 0;
if (showall) y++;
wmove(mainwin, y, 0);
//textwithcol(mainwin, prompt->choice[validchoice].longdesc);
wrapprint(mainwin, &y, &x, "%s", prompt->choice[validchoice].longdesc);
getyx(mainwin, descendy, dummy); // remember bottom of description
}
} else if (descendy != -1) {
if (showall) {
int yy;
// clear to bottom of screen
for (yy = y ; yy < lastline; yy++) {
wmove(mainwin, yy, 0);
wclrtoeol(mainwin);
}
} else {
int yy;
int gamewinbuf[BUFLEN];
// copy text from gamewin
for (yy = y ; yy < lastline; yy++) {
mvwinchstr(gamewin, yy-2, 0, (chtype *)gamewinbuf);
mvwaddchstr(mainwin, yy, 0,(chtype *) gamewinbuf);
}
}
descendy = -1;
}
// display prompt question
snprintf(promptstr, BUFLEN, "%s [%s%s] %s",
prompt->q[prompt->whichq],
prompt->maycancel ? "ESC," : "",
showall ? "'=next page,?=toggle" : "?=list",
inpstring);
mvwprintw(mainwin, 0, 0, "%s", promptstr);
wclrtoeol(mainwin);
// if there's only one match, complete it
if (nvalid == 1) {
char remainder[BUFLEN];
int cx,cy;
// remember cursor pos
getyx(mainwin, cy, cx);
// fill in the name of the completed choice
/*
snprintf(promptstr, BUFLEN, "%s %s %s",
prompt->q[prompt->whichq], prompt->maycancel ? "[ESC=cancel, '=next page] " : "",
prompt->choice[validone].text);
*/
/*
snprintf(promptstr, BUFLEN, "%s [%s%s] ",
prompt->q[prompt->whichq],
prompt->maycancel ? "ESC," : "",
showall ? "'=next page,?=toggle" : "?=list");
prompt->choice[validchoice].text);
*/
// show the remainder of what we have typed.
// ('validchoice' was calculated earlier)
snprintf(remainder, BUFLEN, "^g%s^n",prompt->choice[validchoice].text + strlen(inpstring));
textwithcol(mainwin, remainder);
// move cursor back
wmove(mainwin, cy, cx);
}
wrefresh(mainwin);
// ask for choice...
if (autochar) {
ch = autochar;
autochar = 0;
} else {
ch = getch();
}
if (useshortcuts && ((ch >= '0') && (ch <= '9'))) { // shortcut
flag_t *f;
// autofill from the shortcut
f = lfhasflagval(player, F_SHORTCUT, ch - '0', NA, NA, NULL);
if (f) {
strcpy(inpstring, f->text);
// now press enter
autochar = 10;
}
} else if ((ch == 27) && (prompt->maycancel)) { // ESC - cancel
sel = -1;
break;
} else if ((ch == '\\') && (gamemode == GM_GAMESTARTED)) {
doknowledgelist();
} else if (ch == '\'') {
if (nextpage == -1) {
first = 0;
} else {
first = nextpage;
}
} else if ((ch == '!') || (ch == '?')) { // toggle prompts
if (showall) {
prompt->whichq++;
if (prompt->whichq >= prompt->nqs) prompt->whichq = 0;
} else {
showall = B_TRUE;
}
} else if ((ch == 8) || (ch == 127)) { // backspace
if (strlen(inpstring) > 0) {
inpstring[strlen(inpstring)-1] = '\0';
}
} else if (ch == 10) { // enter
// valid choices?
if (nvalid) {
for (i = 0; i < prompt->nchoices; i++) {
if (prompt->choice[i].valid) {
sel = i;
break;
}
}
} else if (nvalid == 0) { // no choices?
// cancel
sel = -1;
break;
}
} else {
char temp[2];
// append to input string
temp[0] = ch;
temp[1] = '\0';
strcat(inpstring, temp);
/*
sel = -1;
for (i = 0 ; i < prompt->nchoices; i++) {
if (prompt->choice[i].ch == ch) {
sel = i;
break;
}
}
*/
}
}
// set result pointer
if (sel == -1) {
prompt->result = NULL;
prompt->selection = -1;
} else {
prompt->result = prompt->choice[i].data;
prompt->selection = i;
}
if ((gamemode == GM_GAMESTARTED)) {
needredraw = B_TRUE;
drawscreen();
} else {
cls();
wrefresh(mainwin);
}
curs_set(0);
if ((gamemode == GM_GAMESTARTED)) {
restoregamewindows();
}
snprintf(promptstr, BUFLEN, "%s [%s%s] ",
prompt->q[prompt->whichq],
prompt->maycancel ? "ESC," : "",
showall ? "'=next page,?=toggle" : "?=list" );
snprintf(msghistbuf, BUFLEN, "%s%s",promptstr,prompt->choice[i].text);
addmsghist(msghistbuf);
// return NUL or result char
if (ch == 27) {
return '\0';
}
return prompt->choice[i].ch;
}
int getkey(int escseqok) {
int key_code=0;
key_code = getch();
// XXX NEW CODE:
if (gettinginput) {
if (strcmp(msgbuf, "")) {
clearmsg();
//strcpy(msgbuf, "");
//drawmsg();
//drawcursor();
}
}
if (key_code == CH_BREAK) { // ctrl-c
cbreak();
raise(SIGINT); // break to debugger
raw();
}
return keycodetokey(key_code, escseqok);
}
enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev) {
switch (slev) {
case PR_INEPT:
return C_RED;
case PR_NOVICE:
return C_BROWN;
case PR_BEGINNER:
return C_GREY;
case PR_ADEPT:
return C_GREEN;
case PR_SKILLED:
return C_BLUE;
case PR_EXPERT:
return C_CYAN;
case PR_MASTER:
return C_MAGENTA;
}
return C_GREY;
}
void handle_ctrl_y(int arg) {
ungetch(25); // put 'ctrl-y' char onto keyboard queue
}
void handleinput(void) {
int ch;
//char buf[BUFLEN];
flag_t *f;
int gotcmd = B_FALSE;
char numstring[BUFLEN];
int count = 1;
// if running, automatically do move
f = hasflag(player->flags, F_RUNNING);
if (f) {
int rundir = D_NONE;
int lastdir;
int ihaveturned;
int stopnow = B_FALSE;
object_t *o;
lastdir = f->val[0];
ihaveturned = f->val[1];
// certain objects in the current cell will stop us from running.
for (o = player->cell->obpile->first ; o ; o = o->next) {
if ( !hasflag(o->flags, F_NOPICKUP) ||
hasflag(o->flags, F_SHOP) ||
hasflag(o->flags, F_CLIMBABLE) ) {
stopnow = B_TRUE;
break;
}
}
if (countadjcellswithflag(player->cell, F_DOOR, DT_COMPASS)) {
stopnow = B_TRUE;
}
// stop if enter/exit a room
if (player->prevcell[0] && (getroomid(player->cell) != getroomid(player->prevcell[0]))) {
stopnow = B_TRUE;
}
// something here?
if (stopnow) {
} else if (!ihaveturned && moveclear(player, lastdir, NULL)) {
// go the same dir if we can.
rundir = lastdir;
} else {
int dir;
int poss[MAXDIR_COMPASS],nposs;
// we have now turned
f->val[1] = B_TRUE;
// check how many possible moves we have.
nposs = 0;
for (dir = DC_N; dir <= DC_W; dir+= 2) { // ie. only go orthogonally from now on
// don't count the way we just came from
if (dir == diropposite(lastdir)) continue;
if (moveclear(player,dir, NULL)) {
cell_t *adjcell;
// if not in last two spots moved...
adjcell = getcellindir(player->cell, dir);
if ((adjcell != player->prevcell[0]) && (adjcell != player->prevcell[1])) {
poss[nposs++] = dir;
}
}
}
// only one possible direction?
if (nposs == 1) {
rundir = poss[0];
} else {
// stop running
stoprunning(player);
stopnow = B_TRUE;
}
}
if (rundir == D_NONE) {
stopnow = B_TRUE;
}
if (stopnow) {
stoprunning(player);
} else {
cell_t *c;
c = getcellindir(player->cell, rundir);
if (c && celldangerous(player, c, B_TRUE, NULL)) {
stoprunning(player);
} else {
if (trymove(player, rundir, B_TRUE, B_FALSE)) {
// failed.
stoprunning(player);
} else {
// moved ok. remember this dir.
f->val[0] = rundir;
// our turn ends
return;
}
}
}
}
drawmsg();
strcpy(numstring, "");
gotcmd = B_FALSE;
while (!gotcmd) {
char temp[2];
flag_t repeatflag;
int wantrepeat = B_FALSE;
int dir;
repeatflag.val[0] = NA; repeatflag.val[1] = NA; repeatflag.val[2] = NA;
repeatflag.text = NULL;
drawcursor();
// repeated commands?
f = hasflag(player->flags, F_AUTOCMD);
if (f) {
ch = f->text[0];
if (f->val[0] <= 0) {
killflag(f);
msg("Finished repeating '%c'.",ch);
} else {
count = 1;
f->val[0]--;
}
} else {
gettinginput = B_TRUE;
ch = getkey(B_TRUE);
gettinginput = B_FALSE;
}
gotcmd = B_TRUE;
switch (ch) {
// count
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
temp[0] = ch;
temp[1] = '\0';
strcat(numstring, temp);
count = atoi(numstring);
if (count < 1) count = 1;
if (count > 1) {
mvwprintw(msgwin, 0, 0, "count = %d", count);
} else {
wclear(msgwin);
}
wrefresh(msgwin);
gotcmd = B_FALSE;
break;
case 127:
case 8: // ie. backspace
if (strlen(numstring) > 0) {
// remove last letter of number string
numstring[strlen(numstring)-1] = '\0';
count = atoi(numstring);
if (count < 1) count = 1;
if (count > 1) {
mvwprintw(msgwin, 0, 0, "count = %d", count);
} else {
wclear(msgwin);
}
wrefresh(msgwin);
}
gotcmd = B_FALSE;
break;
case 'g': // repeat last command
f = hasflag(player->flags, F_LASTCMD);
if (f) {
ch = f->text[0];
repeatflag.id = f->id;
repeatflag.val[0] = f->val[0];
repeatflag.val[1] = f->val[1];
repeatflag.val[2] = f->val[2];
repeatflag.text = strdup(f->text);
wantrepeat = B_TRUE;
} else {
msg("Cannot repeat last command.");
}
break;
}
// now handle actual commands
f = hasflag(player->flags, F_LASTCMD);
if (f) {
killflag(f);
}
temp[0] = ch;
temp[1] = '\0';
// actions other than movement will cancel certain effects
switch (tolower(ch)) {
case 'h': case 'j': case 'k': case 'l':
case 'y': case 'u': case 'b': case 'n':
case CH_TURN_N: case CH_TURN_E: case CH_TURN_S: case CH_TURN_W:
case CH_TURN_NE: case CH_TURN_SE: case CH_TURN_SW: case CH_TURN_NW:
break;
default:
stoprunning(player);
if (hasactivespell(player, OT_S_SLIDE)) stopspell(player, OT_S_SLIDE);
break;
}
switch (ch) {
// movement
case 'h':
case 'j':
case 'k':
case 'l':
case 'y':
case 'u':
case 'b':
case 'n':
trymove(player, chartodir(ch), B_TRUE, B_FALSE);
break;
// run / strafe
case 'H':
case 'J':
case 'K':
case 'L':
case 'Y':
case 'U':
case 'B':
case 'N':
dir = chartodir(ch);
if (dir == player->facing) { // shift+samedir = run
tryrun(player, dir);
} else { // shift + diffdir = strafe
trymove(player, dir, B_TRUE, B_TRUE);
}
break;
// turn
case CH_TURN_N:
case CH_TURN_E:
case CH_TURN_S:
case CH_TURN_W:
case CH_TURN_NE:
case CH_TURN_SE:
case CH_TURN_SW:
case CH_TURN_NW:
dir = chartodir(ch);
if (dir != player->facing) {
if (getrelativedir(player, dir) != RD_FORWARDS) {
taketime(player, getturnspeed(player));
}
setfacing(player, dir);
drawscreen();
}
break;
case 's': // slowwalk
trysneak(player, D_NONE);
break;
case '.': // wait
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
if (count > 1) {
addflag(player->flags, F_AUTOCMD, count, NA, NA, ".");
} else {
rest(player, B_TRUE);
}
break;
// testing
/*
case '1':
gettimetext(buf);
msg("The current time is %s",buf);
break;
case '2':
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 'A': // attack
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
if (wantrepeat) {
doattackcell(repeatflag.val[2]);
} else {
doattackcell('\0');
}
break;
case 'i': // inventory
doinventory(player->pack);
break;
case '?': // help
dohelp('?');
break;
case '@': // display player stats
showlfstats(player, B_FALSE);
break;
case ']': // display armour
showlfarmour(player);
break;
case ':': // look at what's here
dolook(player->cell, B_TRUE);
break;
case CH_HISTORY:
case '|': // msg history
domsghist();
break;
case '/': // explain object
doexplain("Select glyph to explain (v for info, ESC to cancel):");
break;
case '\\': // list knowledge
doknowledgelist();
break;
case 'R': // rest
dorest();
break;
case 'm': // 'm'agic/abilities (magic)
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
if (wantrepeat) {
//domagic(repeatflag.val[2], repeatflag.val[0], repeatflag.val[1]);
// don't repeat the target cell!
domagic(repeatflag.val[2], NA, NA);
} else {
domagic(OT_NONE, NA, NA);
}
break;
case 'M': // 'M'emorise magic/ability shortcut
domemmagic();
break;
case '<': // go up
if (isprone(player)) {
standup(player);
} else {
dostairs(D_UP);
}
break;
case '>': // go down
doenter(player);
break;
// firearm functions
case 'f': // fire gun
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
dofire();
break;
case 'a': // aim
doselguntarget();
break;
case 'F': // aim then fire
if (!doselguntarget()) {
dofire();
}
break;
case 'G': // reload Gun with current ammo
loadfirearmfast(player, B_TRUE);
break;
case '\'':
donextguntarget();
break;
// object functions
case 'c': // close
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
doclose();
break;
case 'C': // communicate
docomms(NULL);
break;
case 'e': // eat
doeat(player->pack);
break;
case 'd': // drop multiple things
//dodrop(player->pack, B_SINGLE, player->cell->obpile);
dodrop(player->pack, B_MULTIPLE, player->cell->obpile);
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, B_FALSE);
break;
case 'r': // read
doread(player->pack);
break;
case 'q': // quaff
doquaff(player->pack);
break;
case 't': // throw
dothrow(player->pack);
break;
case 'P': // Pour
dopour(player->pack);
break;
case 'o': // operate
addflag(player->flags, F_LASTCMD, NA, NA, NA, temp);
dooperate(player->pack);
break;
case 'O':
dooffer();
break;
// GAME FUNCTIONS
case 'Q': // quit
doquit();
break;
case 'S': // save + quit
if (savegame()) {
msg("Save failed.");
} else {
msg("Saved successfully. See you later...");
more();
exit(0);
}
break;
default:
gotcmd = B_FALSE;
break;
}
if (repeatflag.text) {
free(repeatflag.text);
}
}
}
void initprompt(prompt_t *p, char *q1) {
int i;
for (i = 0; i < MAXPROMPTQUESTIONS; i++) {
if (p->q[i]) {
free(p->q[i]);
p->q[i] = NULL;
}
}
p->q[0] = strdup(q1);
p->nqs = 1;
p->whichq = 0;
p->maycancel = B_FALSE;
p->result = NULL;
p->nchoices = 0;
for (i = 0; i < MAXCHOICES; i++) {
choice_t *c;
c = &p->choice[i];
if (c->text) {
free(c->text);
c->text = NULL;
}
if (c->desc) {
free(c->desc);
c->desc = NULL;
}
if (c->longdesc) {
free(c->longdesc);
c->longdesc = NULL;
}
c->data = NULL;
}
}
// if escseqok is true, then process escape sequences by
// reading 3 more chars
int keycodetokey(int keycode, int escseqok) {
int keystroke = 0;
if (keycode == -1) return -1;
if (escseqok && (keycode == 27)) { // an esc sequence
timeout(0); // don't block
keycode=getch();
timeout(-1); // resume blocking
if (keycode == ERR) {
return 27; // ESC
}
keystroke=keycode;
keycode=getch();
keystroke=keystroke | (keycode<<8);
keycode=getch();
keystroke=keystroke | (keycode<<16);
} else {
// regular keypress
return (int)keycode;
}
return keystroke;
}
void dblog(char *format, ... ) {
char buf[HUGEBUFLEN];
va_list args;
va_start(args, format);
vsnprintf( buf, HUGEBUFLEN, format, args );
va_end(args);
if (logfile) {
fprintf(logfile, "%s\n", buf);
fflush(logfile);
} else {
fprintf(stdout, "%s\n", buf);
fflush(stdout);
}
}
void dblog_nocr(char *format, ... ) {
char buf[HUGEBUFLEN];
va_list args;
va_start(args, format);
vsnprintf( buf, HUGEBUFLEN, format, args );
va_end(args);
if (logfile) {
fprintf(logfile, "%s", buf);
fflush(logfile);
} else {
fprintf(stdout, "%s", buf);
fflush(stdout);
}
}
// force a '--more--' prompt
void more(void) {
if (strlen(msgbuf)) {
//msg("^");
strcat(msgbuf, MSGMORESTRING);
//mvwprintw(msgwin, 0, 0, msgbuf);
drawmsg();
curs_set(1);
// wait for space
while (getch() != ' ');
curs_set(0);
// clear msg
clearmsg();
}
}
void warn(char *format, ... ) {
char buf[BUFLEN];
va_list args;
// like msg, but interrupts rest ect
interrupt(player);
va_start(args, format);
vsnprintf( buf, BUFLEN, format, args );
va_end(args);
msg_real("%s", buf);
}
void msgnocap(char *format, ... ) {
char buf[BUFLEN];
va_list args;
va_start(args, format);
vsnprintf( buf, BUFLEN, format, args );
va_end(args);
// like msg, but don't capitalise
msg_real("%s", buf);
}
void msg(char *format, ... ) {
char buf[BUFLEN];
va_list args;
va_start(args, format);
vsnprintf( buf, BUFLEN, format, args );
va_end(args);
capitalise(buf);
msg_real("%s", buf);
}
void msg_real(char *format, ... ) {
char buf[BUFLEN];
va_list args;
//char *p;
int db = B_FALSE;
// any msg will interrupt the player
//interrupt(player);
//msgmod = B_TRUE;
va_start(args, format);
vsnprintf( buf, BUFLEN, format, args );
va_end(args);
assert(buf[0] != '\0');
// ie repeat of previous message, doesn't have colours, prev msg still on screen
if (streq(buf, prevmsg) && !strchr(buf, '^') && strstr(msgbuf, prevmsg)) {
msgmulti++;
snprintf(buf, BUFLEN, "x%d",msgmulti);
} else {
strcpy(prevmsg, buf);
msgmulti = 1;
}
if (db) dblog("adding to msgbuf: [%s]",buf);
if (strstr(buf, "(NULL)")) {
assert(2 == 3);
}
//assert(!strchr(buf, '#'));
// ie. can the message buffer fit:
// what is already there + 2 spaces + the new text + '--more--' ?
//if (strlen(msgbuf) + 2 + strlen(buf) + strlen(MORESTRING) >= SCREENW) {
if (strlen(msgbuf) + 2 + strlen(buf) >= SCREENW) {
// do more
more();
} else {
if (strlen(msgbuf) > 0) {
strcat(msgbuf, " ");
}
}
strcat(msgbuf, buf);
strcat(msgbuf, "^n"); // back to normal colour
if (db) dblog(" msgbuf is now: [%s]",msgbuf);
msgmod = B_TRUE;
// update msg window
drawmsg();
//drawcursor();
}
int needsbold(enum COLOUR col) {
if (col >= REDBG) col -= REDBG;
if (col >= GREENBG) col -= GREENBG;
if (col >= BLUEBG) col -= BLUEBG;
switch (col) {
case C_YELLOW:
case C_WHITE:
case C_BOLDCYAN:
case C_BOLDBLUE:
case C_BOLDMAGENTA:
case C_BOLDGREEN:
case C_ORANGE:
case C_DARKGREY:
return B_TRUE;
default:
break;
}
return B_FALSE;
}
void nothinghappens(void) {
msg("Nothing seems to happen.");
}
void drawstatus(void) {
char buf[BUFLEN];
char buf2[BUFLEN];
//char mpbuf[BUFLEN];
char waitbuf[BUFLEN];
//char pname[BUFLEN];
//char maxmpstr[BUFLEN];
flag_t *f;
enum ATTRIB a;
int myatt[MAXATTS];
int xpleft;
curs_set(0);
wclear(statwin);
// FIRST LINE
wmove(statwin, 0, 0);
// hp
drawbar(statwin, "HP", player->hp, player->maxhp, player->maxhp, player->damlastturn, C_GREY, C_BLUE, GREENBG, REDBG);
// mp
drawbar(statwin, "MP", player->mp, getmaxmp(player), player->maxmp, player->mplastturn, C_GREY, C_GREY, BLUEBG, REDBG);
// stamina
drawbar(statwin, "SP", getstamina(player), getmaxstamina(player), getmaxstamina(player), ceil(player->stamlastturn), C_GREY, C_GREY, BLUEBG, REDBG);
// gun target ?
f = hasflag(player->flags, F_GUNTARGET);
if (f) {
wprintw(statwin, "Aim: ");
textwithcol(statwin, f->text);
}
// SECOND LINE
wmove(statwin, 1, 0);
//xpleft = getxpforlev(player->level + 1) - player->xp;
xpleft = (int) (((float)player->xp / (float)getxpforlev(player->level + 1)) * 100.0);
/*
getplayername(pname);
wattron(statwin, A_BOLD); wprintw(statwin, "["); wattroff(statwin, A_BOLD);
wprintw(statwin, "%-12s", pname);
wattron(statwin, A_BOLD); wprintw(statwin, "] "); wattroff(statwin, A_BOLD);
*/
/*
// HP
wattron(statwin, A_BOLD); wprintw(statwin, "HP:"); wattroff(statwin, A_BOLD);
setcol(statwin, getpctcol(player->hp, player->maxhp));
wprintw(statwin, "%d",player->hp);
unsetcol(statwin, getpctcol(player->hp, player->maxhp));
wprintw(statwin, "/%d ",player->maxhp);
// MP
if (getmaxmp(player) == player->maxmp) {
strcpy(maxmpstr, "");
} else {
snprintf(maxmpstr, BUFLEN, "(%d)",player->maxmp);
}
// note: not using getmaxmp() here on purpose!
if (player->maxmp > 0) {
wattron(statwin, A_BOLD); wprintw(statwin, "MP:"); wattroff(statwin, A_BOLD);
setcol(statwin, getpctcol(player->mp, getmaxmp(player)));
wprintw(statwin, "%d",player->mp);
unsetcol(statwin, getpctcol(player->mp, getmaxmp(player)));
wprintw(statwin, "/%d%s ",getmaxmp(player),maxmpstr);
} else {
wattron(statwin, A_BOLD); wprintw(statwin, "MP:"); wattroff(statwin, A_BOLD);
wprintw(statwin, "- ");
}
// stamina
wattron(statwin, A_BOLD); wprintw(statwin, "SP:"); wattroff(statwin, A_BOLD);
setcol(statwin, getpctcol(getstamina(player), (int)getmaxstamina(player)));
wprintw(statwin, "%d",getstamina(player));
unsetcol(statwin, getpctcol(getstamina(player), (int)getmaxstamina(player)));
wprintw(statwin, "/%d ",(int)getmaxstamina(player));
*/
wattron(statwin, A_BOLD); wprintw(statwin, "AR:"); wattroff(statwin, A_BOLD);
snprintf(buf, BUFLEN, "%d ", getarmourrating(player, NULL, NULL, NULL));
wprintw(statwin, buf);
wattron(statwin, A_BOLD); wprintw(statwin, "EV:"); wattroff(statwin, A_BOLD);
wprintw(statwin, "%d ", getevasion(player));
wattron(statwin, A_BOLD); wprintw(statwin, "$:"); wattroff(statwin, A_BOLD);
snprintf(buf, BUFLEN, "%d ", countmoney(player->pack));
wprintw(statwin, buf);
wattron(statwin, A_BOLD); wprintw(statwin, "Xp:"); wattroff(statwin, A_BOLD);
snprintf(buf, BUFLEN, "%d", player->level);
wprintw(statwin, buf);
if (lfhasflag(player, F_HASNEWLEVEL)) {
wattron(statwin, A_BOLD); wprintw(statwin, "/"); wattroff(statwin, A_BOLD);
setcol(statwin, C_BOLDGREEN);
wprintw(statwin, "LevUp",xpleft);
unsetcol(statwin, C_BOLDGREEN);
} else {
wattron(statwin, A_BOLD); wprintw(statwin, "/"); wattroff(statwin, A_BOLD);
wprintw(statwin, "%d%%",xpleft);
}
wattron(statwin, A_BOLD); wprintw(statwin, " Trn:"); wattroff(statwin, A_BOLD);
wprintw(statwin, "%d/%d%% ", player->skillpoints,
(int) ((float)player->skillxp / (float)getspforpoint(player) * 100.0) );
// blinded?
if (isblind(player) && !lfhasflag(player, F_ASLEEP)) {
setcol(statwin, C_RED);
wprintw(statwin, " Blind");
unsetcol(statwin, C_RED);
}
if (lfhasflag(player, F_GRAVBOOSTED)) {
setcol(statwin, C_RED);
wprintw(statwin, " HiGrv");
unsetcol(statwin, C_RED);
}
if (lfhasflag(player, F_GRAVLESSENED)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " LoGrv");
unsetcol(statwin, C_BOLDBLUE);
}
if (lfhasflag(player, F_RAGE)) {
setcol(statwin, C_RED);
wprintw(statwin, " Rage");
unsetcol(statwin, C_RED);
}
if (isswimming(player)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Swim");
unsetcol(statwin, C_BOLDBLUE);
}
if (isclimbing(player)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Climb");
unsetcol(statwin, C_BOLDBLUE);
}
if (isairborne(player)) {
if (lfhasflag(player, F_FLYING)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Fly");
unsetcol(statwin, C_BOLDBLUE);
} else if (lfhasflag(player, F_LEVITATING)) {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Lev");
unsetcol(statwin, C_BOLDBLUE);
} else {
setcol(statwin, C_BOLDBLUE);
wprintw(statwin, " Hov"); // "hov"ering
unsetcol(statwin, C_BOLDBLUE);
}
}
if (iswoozy(player)) {
setcol(statwin, C_YELLOW);
wprintw(statwin, " Woozy");
unsetcol(statwin, C_YELLOW);
}
if (lfhasflag(player, F_STUNNED)) {
setcol(statwin, C_YELLOW);
wprintw(statwin, " Stunned");
unsetcol(statwin, C_YELLOW);
}
// paralysed somehow?
if ((f = isresting(player)) != NULL) {
setcol(statwin, C_CYAN);
if (f->val[1] == ST_ASLEEP) {
wprintw(statwin, " Resting");
} else {
wprintw(statwin, " Meditating");
}
unsetcol(statwin, C_CYAN);
} else if ((f = lfhasflag(player, F_ASLEEP)) != NULL) {
setcol(statwin, C_MAGENTA);
if (f->val[1] == ST_KO) {
wprintw(statwin, " KO");
} else {
wprintw(statwin, " Asleep");
}
unsetcol(statwin, C_MAGENTA);
} else if (isprone(player)) {
setcol(statwin, C_YELLOW);
wprintw(statwin, " Prone");
unsetcol(statwin, C_YELLOW);
} else if (isimmobile(player)) {
setcol(statwin, C_RED);
wprintw(statwin, " Immobile");
unsetcol(statwin, C_RED);
} else {
char actbuf[BUFLEN],movebuf[BUFLEN];
getspeednameshort(getactspeed(player), actbuf);
getspeednameshort(getmovespeed(player), movebuf);
// both action and movement speed the same, and not "normal" ?
if (!strcmp(actbuf, movebuf) && strcmp(actbuf, "normal")) {
// show combiner action/movement speed
enum COLOUR col;
if (getactspeed(player) < SP_NORMAL) {
col = C_GREEN;
} else {
col = C_RED;
}
setcol(statwin, col);
capitaliseall(actbuf);
wprintw(statwin, " %s", actbuf);
unsetcol(statwin, col);
} else {
// show action/movement speed seperately
// show player action speed
if (strcmp(actbuf, "normal")) {
enum COLOUR col;
if (getactspeed(player) < SP_NORMAL) {
col = C_GREEN;
} else {
col = C_RED;
}
setcol(statwin, col);
wprintw(statwin, " Act:");
capitaliseall(actbuf);
wprintw(statwin, "%s", actbuf);
unsetcol(statwin, col);
}
// show player movement speed
if (strcmp(movebuf, "normal")) {
enum COLOUR col;
if (getmovespeed(player) < SP_NORMAL) {
col = C_GREEN;
} else {
col = C_RED;
}
setcol(statwin, col);
wprintw(statwin, " Mv:");
capitaliseall(movebuf);
wprintw(statwin, "%s", movebuf);
unsetcol(statwin, col);
}
}
}
// burdened somehow?
switch (isburdened(player)) {
case BR_BURDENED:
setcol(statwin, C_BROWN);
wprintw(statwin, " Burdened");
unsetcol(statwin, C_BROWN);
break;
case BR_STRAINED:
setcol(statwin, C_RED);
wprintw(statwin, " Strained");
unsetcol(statwin, C_RED);
break;
case BR_OVERLOADED:
setcol(statwin, C_YELLOW);
wprintw(statwin, " Overloaded");
unsetcol(statwin, C_YELLOW);
break;
default:
break;
}
if (lfhasflag(player, F_PAIN)) {
setcol(statwin, C_YELLOW);
wprintw(statwin, " Pain");
unsetcol(statwin, C_YELLOW);
}
// show certain flags
f = lfhasflag(player, F_DRUNK);
if (f) {
char dstring[BUFLEN];
strcpy(dstring, getdrunktext(f));
capitalise(dstring);
setcol(statwin, C_BROWN);
//wprintw(statwin, " %s(%d)", dstring,f->lifetime);
wprintw(statwin, " %s", dstring);
unsetcol(statwin, C_BROWN);
}
f = ispoisoned(player);
if (f) {
// find highest amount of poison
if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) {
if (poisonthreatenslife(player, f)) {
setcol(statwin, C_RED);
wprintw(statwin, " %s(bad)", getpoisondesc(f->val[0]));
unsetcol(statwin, C_RED);
} else {
setcol(statwin, C_BROWN);
wprintw(statwin, " %s(mild)", getpoisondesc(f->val[0]));
unsetcol(statwin, C_BROWN);
}
} else {
setcol(statwin, C_RED);
wprintw(statwin, " %s", getpoisondesc(f->val[0]));
unsetcol(statwin, C_RED);
}
}
//mvwprintw(statwin, 0, 0, buf);
f = hasflag(player->flags, F_HUNGER);
if (f) {
int hlev;
hlev = gethungerlevel(f->val[0]);
if (hlev == H_NONE) {
strcpy(buf2, "");
} else {
gethungername(player, hlev, buf2);
capitalise(buf2);
}
if (hlev == H_STARVING) setcol(statwin, C_RED);
else setcol(statwin, C_BROWN);
wprintw(statwin, " %s", buf2);
if (hlev == H_STARVING) unsetcol(statwin, C_RED);
else unsetcol(statwin, C_BROWN);
}
// good effects
f = lfhasflag(player, F_HIDING);
if (f) {
setcol(statwin, C_MAGENTA);
if (f->val[0] < 0) {
wprintw(statwin, " Hiding--");
} else {
wprintw(statwin, " Hiding");
}
unsetcol(statwin, C_MAGENTA);
}
// construct waiting string
strcpy(waitbuf, "");
/*
// timespent > 0?
if (player->timespent) {
snprintf(buf, BUFLEN, "busy: %d", player->timespent);
strcat(waitbuf, buf);
}
*/
f = hasflag(player->flags, F_AUTOCMD);
if (f) {
if (strlen(waitbuf)) strcat(waitbuf, ", ");
snprintf(buf, BUFLEN, "'%c' x %d", f->text[0], f->val[0]);
strcat(waitbuf, buf);
}
if (strlen(waitbuf)) {
wprintw(statwin, " (%s)",waitbuf);
}
// THIRD LINE
for (a = 0; a < MAXATTS; a++) {
myatt[a] = getattr(player, a);
}
//redraw();
wmove(statwin, 2, 0);
for (a = 0; a < MAXATTS; a++) {
wattron(statwin, A_BOLD); wprintw(statwin, "%s:",getattrabbrev(a)); wattroff(statwin, A_BOLD);
if (myatt[a] == player->baseatt[a]) {
wprintw(statwin, "%d ",myatt[a]);
} else {
if (myatt[a] > player->baseatt[a]) {
setcol(statwin, C_GREEN);
wprintw(statwin, "%d*",myatt[a]);
unsetcol(statwin, C_GREEN);
} else {
setcol(statwin, C_RED);
wprintw(statwin, "%d*",myatt[a]);
unsetcol(statwin, C_RED);
}
}
}
//wprintw(statwin, "DLev:%d", player->cell->map->depth);
setcol(statwin, C_BROWN);
getregionname(buf, player->cell->map, B_TRUE);
capitalise(buf);
wprintw(statwin, "%s", buf);
unsetcol(statwin, C_BROWN);
}
void drawmsg(void) {
//char *nexttok;
int db = B_FALSE;
if (db) dblog("drawmsg called");
// is msgbuf has changed...
if (strcmp(msgbuf, lastmsgbuf) || msgmod) {
wclear(msgwin);
wmove(msgwin, 0, 0);
// default
setcol(msgwin, C_GREY);
textwithcol(msgwin, msgbuf);
//wprintw(msgwin, "%s", msgbuf);
//mvwprintw(msgwin, 0, 0, msgbuf);
wrefresh(msgwin);
strcpy(lastmsgbuf, msgbuf);
}
// drawcursor();
}
void redraw(void) {
//dblog("redraw");
//wrefresh(msgwin);
wrefresh(statwin);
wrefresh(gamewin);
}
void redrawpause(void) {
noredraw = B_TRUE;
}
void redrawresume(void) {
noredraw = B_FALSE;
if (needredraw) {
drawlevelfor(player);
}
}
void restoregamewindows(void) {
needredraw = B_TRUE;
statdirty = B_TRUE;
wclear(mainwin);
wrefresh(mainwin);
clearmsg();
wclear(gamewin);
drawscreen();
redraw();
}
int screenglyphmatches(int x, int y, glyph_t *g) {
int attribs;
glyph_t screenglyph;
screenglyph.ch = mvwinch(gamewin, y, x) & A_CHARTEXT;
if (screenglyph.ch != g->ch) {
return B_FALSE;
}
screenglyph.colour = PAIR_NUMBER(mvwinch(gamewin, y, x) & A_COLOR);
if (screenglyph.colour != g->colour) {
return B_FALSE;
}
// reverse video highlight from askcoords?
attribs = mvwinch(gamewin, y, x) & A_ATTRIBUTES;
if (attribs & A_REVERSE) {
return B_FALSE;
}
return B_TRUE;
}
void setcol(WINDOW *win, enum COLOUR col) {
if (needsbold(col)) {
wattron(win, A_BOLD);
} else {
wattroff(win, A_BOLD);
}
wattron(win, COLOR_PAIR(col));
}
void unsetcol(WINDOW *win, enum COLOUR col) {
wattroff(win, COLOR_PAIR(col));
if (needsbold(col)) {
wattroff(win, A_BOLD);
}
}
void setobcolour(WINDOW *win, object_t *o, int set) {
void (*funcptr)(WINDOW *, enum COLOUR);
// which function?
if (set) {
funcptr = setcol;
} else {
funcptr = unsetcol;
}
if (!o) return;
// unpaid?
if (hasflag(o->flags, F_SHOPITEM) && o->pile->owner) {
funcptr(win, C_ORANGE);
return;
}
if (hasflag(o->flags, F_KNOWNBAD)) {
funcptr(win, C_RED);
return;
}
if (o->blessknown) {
if (iscursed(o)) {
funcptr(win, C_RED);
return;
} else if (isblessed(o)) {
funcptr(win, C_CYAN);
return;
}
}
if ((getskill(player, SK_COOKING) >= PR_BEGINNER) && isbadfood(o)) {
funcptr(win, C_GREEN);
return;
}
if (lfhasflag(player, F_DETECTMAGIC) && ismagical(o)) {
funcptr(win, C_BOLDGREEN);
return;
}
}
// dump out a single hiscore line
int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname) {
int i;
char *rank = NULL, *score = NULL, *name = NULL, *job = NULL, *killer = NULL;
for (i = 0; i < ncols; i++) {
if (streq(colname[i], "rank")) rank = strdup(argv[i]);
else if (streq(colname[i], "score")) score = strdup(argv[i]);
else if (streq(colname[i], "name")) name = strdup(argv[i]);
else if (streq(colname[i], "job")) job = strdup(argv[i]);
else if (streq(colname[i], "killedby")) killer = strdup(argv[i]);
}
if (streq(score, (char *)hilitescore)) setcol(mainwin, C_BOLDGREEN);
wprintw(mainwin, HISCOREFORMAT, rank, score, name, job, killer);
if (streq(score, (char *)hilitescore)) unsetcol(mainwin, C_BOLDGREEN);
wprintw(mainwin, "\n");
free(score);
free(name);
free(job);
free(killer);
return B_FALSE;
}
void showlfarmour(lifeform_t *lf) {
enum BODYPART bp;
object_t *o;
object_t *arm[MAXBODYPARTS];
int y;
char buf[BUFLEN],ch;
int keepgoing = B_TRUE;
while (keepgoing) {
cls();
if (isplayer(lf)) {
centre(mainwin, C_WHITE, 0, "CHARACTER EQUIPMENT");
} else{
centre(mainwin, C_WHITE, 0, "MONSTER EQUIPMENT");
}
y = 2;
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
char rhs[BUFLEN];
// default
strcpy(rhs, "");
if (hasbp(lf, bp)) {
object_t *outerob;
snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " ");
o = getequippedob(lf->pack, bp);
arm[bp] = o; // remember for later
outerob = getouterequippedob(lf, bp);
if (o) {
flag_t *f;
char obname[BUFLEN];
getobname(o, obname, o->amt);
sprintf(rhs, "%c - %s",o->letter, obname);
if (outerob && (outerob != o)) {
char outerobname[BUFLEN];
getobname(outerob, outerobname, outerob->amt);
if (strlen(rhs)) strcat(rhs, " ");
strcat(rhs, "(covered) ");
}
f = hasflag(o->flags, F_ARMOURRATING);
if (f && (f->val[0])) {
char numbuf[BUFLENSMALL];
int thisar;
thisar = f->val[0] + getobbonus(o, B_TRUE);
snprintf(numbuf, BUFLENSMALL, " ^g[AR:%d]^n",thisar);
strcat(rhs, numbuf);
}
f = hasflag(o->flags, F_OBHP);
if (f && (f->val[0] != f->val[1])) {
char numbuf[BUFLENSMALL];
int pct;
pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0);
snprintf(numbuf, BUFLENSMALL, " ^w[%d%%]^n",pct);
strcat(rhs, numbuf);
}
} else {
strcpy(rhs, "-");
}
mvwprintw(mainwin, y, 0, "%s", buf);
if (o) setobcolour(mainwin, o, B_TRUE);
//wprintw(mainwin, "%s", rhs);
textwithcol(mainwin, rhs);
if (o) setobcolour(mainwin, o, B_FALSE);
y++;
}
}
y = getmaxy(mainwin);
centre(mainwin, C_WHITE, y-1, "[Press letter to view armour, ESC to exit]");
ch = getch();
keepgoing = B_FALSE;
if (ch == 27) { // ESC
keepgoing = B_FALSE;
} else {
// does it match an object?
for (bp = BP_WEAPON; bp < MAXBODYPARTS; bp++) {
if (arm[bp] && (arm[bp]->letter == ch)) {
describeob(arm[bp]);
}
}
keepgoing = B_TRUE;
}
}
restoregamewindows();
}
void showlfstats(lifeform_t *lf, int showall) {
int y = 0, y2 = 0, x2 = 40;
int x;
int arating, evasion;
int acc;
char actbuf[BUFLEN],movebuf[BUFLEN];
int h;
char buf[BUFLEN],buf2[BUFLEN];
job_t *j;
flag_t *f;
//char *ftext= "%13s: ";
char *ftext= "%11s: ";
long xpneeded;
object_t *o;
object_t *w[2];
flag_t *damflag[2];
int nweps = 0;
objecttype_t *ot;
int first;
int i;
float dammod;
int accmod;
enum BODYPART bp;
enum BODYPART missingbp[MAXBODYPARTS];
int nmissingbp;
obpile_t *op = NULL;
char ch;
char mode = '@';
char promptstr[BUFLEN];
char cmdchars[BUFLEN];
int done = B_FALSE;
enum SKILLLEVEL lorelev;
enum COLOUR lorecol;
int min,max;
flag_t *retflag[MAXCANDIDATES];
int nretflags;
h = getmaxy(mainwin);
// determine knowledge about this monster
lorelev = getlorelevel(player, lf->race->raceclass->id);
if (isplayer(lf)) {
lorecol = C_GREY; // ie. no colour
} else if (lorelev == PR_MASTER) {
lorecol = C_GREY; // ie. no colour
} else {
lorecol = C_BROWN;
}
// override showall sometimes...
// need 'player == lf' to cope with mind scans
// where we update the player pointer, but don't
// change the target's '->controller' setting (meaning
// that isplayer(target) still returns false).
if (isplayer(lf) || (player == lf) || (lorelev >= PR_MASTER) || ispetof(lf, player)) {
showall = B_TRUE;
}
if (isplayer(lf) || showall) {
snprintf(promptstr, BUFLEN, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects %s%s^W?^n=help ^WESC^n=quit^h]",
isplayer(lf) ? "^WG^nods " : "",
isplayer(lf) ? "" : "^WI^ntems " );
snprintf(cmdchars, BUFLEN, "@asme%s%s",isplayer(lf) ? "g" : "", isplayer(lf) ? "" : "i");
} else {
snprintf(cmdchars, BUFLEN, "@e?");
// can always see stats & effects
snprintf(promptstr, BUFLEN, "^h[^W@^n=stats ^WE^nffects ");
if (!isplayer(lf)) {
snprintf(buf, BUFLEN, "^WI^ntems ");
strcat(promptstr, buf);
strcat(cmdchars, "i");
}
if ((lorelev >= PR_ADEPT) || (getskill(player, SK_LORE_ARCANA) >= PR_ADEPT)) {
snprintf(buf, BUFLEN, "^M^agic ");
strcat(promptstr, buf);
strcat(cmdchars, "m");
}
snprintf(buf, BUFLEN, "^W?^n=help ^WESC^n=quit]");
strcat(promptstr, buf);
}
while (!done) {
cls();
y = 0;
ch = '\0';
if (mode == '@') {
if (isplayer(lf)) {
centre(mainwin, C_WHITE, 0, "CHARACTER DETAILS");
} else{
centre(mainwin, C_WHITE, 0, "MONSTER DETAILS");
}
x = 0;
y = 2;
y2 = 2;
dammod = getstrdammod(lf);
accmod = getstatmod(lf, A_AGI);
if (isplayer(lf)) {
getplayername(buf);
} else {
getlfnamea(lf, buf);
}
doheadingsmall(mainwin, y, 0, ftext, "Name");
wprintw(mainwin, "%-20s", buf); y++;
if (isplayer(lf)) {
doheadingsmall(mainwin, y, 0, ftext, "Race");
wprintw(mainwin, "%-20s", lf->race->name); y++;
} else {
doheadingsmall(mainwin, y, 0, ftext, "Type");
wprintw(mainwin, "%-20s", lf->race->raceclass->name); y++;
}
j = getjob(lf);
if (j) {
doheadingsmall(mainwin, y, 0, ftext, "Job");
if (showall) {
snprintf(buf, BUFLEN, "Level %d %s", lf->level, j->name);
} else {
snprintf(buf, BUFLEN, "%s", j->name);
}
wprintw(mainwin, "%-20s", buf); y++;
}
// size
if (showall) {
float w;
w = getlfweight(lf, B_NOOBS);
doheadingsmall(mainwin, y, 0, ftext, "Size/Weight");
getweighttext(w, buf, B_FALSE);
wprintw(mainwin, "%s (%s)", getsizetext(getlfsize(lf)), buf); y++;
} else {
doheadingsmall(mainwin, y, 0, ftext, "Size");
wprintw(mainwin, "%-20s", getsizetext(getlfsize(lf))); y++;
}
if (showall) {
doheadingsmall(mainwin, y, 0, ftext, "Weight");
}
if (showall ||
(getseenlfconditioncutoff(player) == C_HEALTHY) ||
(lorelev >= PR_SKILLED)) {
int xx,yy;
doheadingsmall(mainwin, y, 0, ftext, "HP");
if (lorelev >= PR_SKILLED) setcol(mainwin, lorecol);
wprintw(mainwin, "%d/%d ", lf->hp , lf->maxhp);
if (lorelev >= PR_SKILLED) unsetcol(mainwin, lorecol);
getyx(mainwin, yy, xx);
doheadingsmall(mainwin, y, xx, "%5s:", "Stam");
wprintw(mainwin, " %d/%d", getstamina(lf) , (int)getmaxstamina(lf));
y++;
} else {
char hpinfo[BUFLEN];
snprintf(hpinfo, BUFLEN, "%s",getseenlfconditionname(lf, player));
if (strlen(hpinfo) > 0) {
doheadingsmall(mainwin, y, 0, ftext, "Hit Points");
wprintw(mainwin, "%s", hpinfo); y++;
}
}
if (showall) {
char maxmpstr[BUFLEN];
if (getmaxmp(lf) == lf->maxmp) {
strcpy(maxmpstr, "");
} else {
snprintf(maxmpstr, BUFLEN, "(%d)",lf->maxmp);
}
doheadingsmall(mainwin, y, 0, ftext, "Mana");
wprintw(mainwin, "%d / %d%s ", lf->mp , lf->maxmp,maxmpstr);
y++;
}
if (showall || (lorelev >= PR_ADEPT)) {
if (isplayer(lf)) {
doheadingsmall(mainwin, y, 0, ftext, "Exp Level");
} else {
doheadingsmall(mainwin, y, 0, ftext, "Hit Dice");
}
if (isplayer(lf)) {
xpneeded = getxpforlev(lf->level + 1) - lf->xp;
wprintw(mainwin, "%d (%ld XP, %ld for next)", lf->level, lf->xp, xpneeded); y++;
} else {
wprintw(mainwin, "%d", gethitdice(lf)); y++;
}
}
if (showall) {
if (isplayer(lf)) {
int attpoints;
int pct;
long amtneeded;
attpoints = getattpoints(lf);
amtneeded = getspforpoint(lf);
doheadingsmall(mainwin, y, 0, ftext, "Skill Pts");
pct = ((float)lf->skillxp / (float)amtneeded) * 100.0;
limit(&pct, 0, 100);
if (lf->skillpoints ) {
/*
wprintw(mainwin, "%d skill%s, %d attrib%s", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s",
attpoints,
(attpoints == 1) ? "" : "s");
*/
wprintw(mainwin, "%d point%s, ", lf->skillpoints,
(lf->skillpoints == 1) ? "" : "s");
}
wprintw(mainwin, "%d%%", pct);
y++;
}
}
for (i = 0; i < MAXATTS; i++) {
int val;
char bracketname[BUFLEN];
char attrname[BUFLEN];
enum ATTRBRACKET brack;
int mod;
val = getattr(lf, i);
brack = getattrbracket(val, i, bracketname);
strcpy(attrname, getattrname(i));
capitalise(attrname);
snprintf(buf, BUFLEN, "%d (%s",val, bracketname);
if (showall) {
char buf2[BUFLEN];
switch (i) {
case A_STR:
if (dammod > 1) {
snprintf(buf2, BUFLEN, ", +%d%% dmg", (int)((dammod * 100) - 100) );
strcat(buf, buf2);
} else if (dammod < 1) {
snprintf(buf2, BUFLEN, ", -%d%% dmg", (int)(100 - (dammod * 100)) );
strcat(buf, buf2);
}
break;
case A_CON:
mod = getstatmod(lf, A_CON);
if (mod > 0) {
mod *= 2; // note: same code as in rollhitdice
snprintf(buf2, BUFLEN, ", +%d%% hp",mod );
strcat(buf, buf2);
}
break;
/*
case A_AGI:
if (accmod != 0) {
snprintf(buf2, BUFLEN, ", %c%d acc",(accmod >= 0) ? '+' : '-',
abs(accmod)/5 );
strcat(buf, buf2);
}
break;
*/
default:
break;
}
strcat(buf, ")");
if (val != lf->baseatt[i]) strcat(buf, "*");
doheadingsmall(mainwin, y, 0, ftext, attrname);
} else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) {
// just show name
strcat(buf, ")");
if (val != lf->baseatt[i]) strcat(buf, "*");
doheadingsmall(mainwin, y, 0, ftext, attrname);
}
if (showall) {
// colour based on level
setcol(mainwin, getattrcolour(brack));
wprintw(mainwin, "%s", buf); y++;
unsetcol(mainwin, getattrcolour(brack));
} else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) {
// colour based on lore level
setcol(mainwin, lorecol);
wprintw(mainwin, "%s", buf); y++;
unsetcol(mainwin, lorecol);
}
} // end foreach att
//mvwprintw(mainwin, y, 0, ftext, "XP");
//wprintw(mainwin, "%ld (%ld more for next level)", lf->xp, xpneeded); y++;
y++; // skip line
// now go to second column
doheadingsmall(mainwin, y2, x2, ftext, "# Attacks");
getattacks(lf, &min, &max);
if (min == max) {
wprintw(mainwin, "%d", max); y2++;
} else {
wprintw(mainwin, "%d-%d", min,max); y2++;
}
y2++;
// current weapon + dam
nweps = 0;
for (i = 0; i < 2; i++) {
w[i] = NULL;
damflag[i] = NULL;
}
o = getweapon(lf);
if (o) w[nweps++] = o;
o = getsecmeleeweapon(lf);
if (o) {
// can't be the same as the first one!
if ((nweps == 1) && (o == w[0])) {
} else {
w[nweps++] = o;
}
}
if (!nweps) {
// get first innate attack weapon.
op = addobpile(NULL, NULL, NULL);
f = hasflag(lf->flags, F_HASATTACK);
if (f) {
w[0] = addobfast(op, f->val[0]);
if (w[0]) {
damflag[0] = f;
nweps = 1;
}
}
}
for (i = 0; i < nweps; i++) {
if (w[i]) {
int mindam,maxdam;
int bonus,speed;
int accnum;
// weapon
if (showall) {
char buf2[BUFLEN];
// calculate damage
f = hasflag(w[i]->flags, F_BONUS);
if (f && f->known) {
// only tell player about bonuses if they are known.!
bonus = f->val[0];
} else {
bonus = 0;
}
// damflag[i] will be null for real weapons- this is okay.
getdamrange(w[i], damflag[i], &mindam, &maxdam);
mindam += bonus;
maxdam += bonus;
applylfdammod(&mindam, lf, w[i]);
applylfdammod(&maxdam, lf, w[i]);
if (mindam < 0) mindam = 0;
if (maxdam < 0) maxdam = 0;
snprintf(buf, BUFLEN, "%s (%d-%d dmg)", w[i]->type->name,(int)mindam,(int)maxdam);
doheadingsmall(mainwin, y2, x2, ftext, "Weapon");
wprintw(mainwin, "%-20s", buf); y2++;
// attack speed & accuracy
acc = getlfaccuracy(lf, w[i]);
accnum = getaccuracynum(acc);
speed = getattackspeed(lf);
getspeedname(speed, buf2);
capitalise(buf2);
snprintf(buf, BUFLEN, "Spd:%s Acc:%c%d",buf2,(accnum < 0) ? '-' : '+', abs(accnum));
mvwprintw(mainwin, y2, x2, "%14s", " ");
wprintw(mainwin, "%-20s", buf); y2++;
} else {
// just show weapon name
snprintf(buf, BUFLEN, "%s", w[i]->type->name);
doheadingsmall(mainwin, y2, x2, ftext, "Weapon");
wprintw(mainwin, "%-20s", buf); y2++;
}
}
} // end for each weapon
if (op) {
killobpile(op);
op = NULL;
}
// skip a line
y2++;
// unarmed attacks
op = addobpile(NULL, NULL, NULL);
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_HASATTACK) {
object_t *o;
objecttype_t *ot;
ot = findot(f->val[0]);
o = addobfast(op, ot->id);
if (o) {
char dambuf[BUFLEN];
strcpy(dambuf, "");
snprintf(buf, BUFLEN, "%s", o->type->name);
// damage
if (showall || (lorelev >= PR_BEGINNER)) {
int mindam,maxdam;
getdamrange(o, f, &mindam, &maxdam);
// DONT apply damage mod for strength
/*
if (!hasflag(o->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) {
mindam = (int)((float)mindam * dammod);
maxdam = (int)((float)maxdam * dammod);
}
if (mindam < 0) mindam = 0;
if (maxdam < 0) maxdam = 0;
*/
snprintf(dambuf, BUFLEN, " (%d-%d basedmg)",(int)mindam,(int)maxdam);
}
doheadingsmall(mainwin, y2, x2, ftext, "Innate Attack");
wprintw(mainwin, "%s", buf);
if (strlen(dambuf)) {
if (lorelev >= PR_BEGINNER) setcol(mainwin, lorecol);
wprintw(mainwin, "%s", dambuf);
if (lorelev >= PR_BEGINNER) unsetcol(mainwin, lorecol);
}
y2++;
} // end if o
} // end if fid == hasattack
} // end for each flag
// no attacks at all?
if ((nweps == 0) && !op->first) {
snprintf(buf, BUFLEN, "N/A");
doheadingsmall(mainwin, y2, x2, ftext, "Attack");
wprintw(mainwin, "%-20s", buf); y2++;
}
// skip line
y2++;
if (op) {
killobpile(op);
op = NULL;
}
// ARMOUR STUFF
if (showall || (lorelev >= PR_NOVICE)) {
int min,max;
//int min,max;
arating = getarmourrating(lf, NULL, NULL, NULL);
//min = pctof(25, arating);
//max = pctof(75, arating);
doheadingsmall(mainwin, y2, x2, ftext, "Armour Rating");
if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol);
getarrange(arating, &min, &max);
if (max <= 0) {
wprintw(mainwin, "%d (no dmgreduce)", arating); y2++;
} else {
wprintw(mainwin, "%d (dmgreduce %d-%d)", arating, min, max); y2++;
}
if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol);
}
if (showall || (lorelev >= PR_NOVICE)) {
evasion = getevasion(lf);
doheadingsmall(mainwin, y2, x2, ftext, "Evasion");
if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol);
wprintw(mainwin, "%d%%", evasion); y2++;
y2++; // skip line
if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol);
}
getspeednameshort(getactspeed(lf), actbuf);
getspeednameshort(getmovespeed(lf), movebuf);
if (streq(actbuf, movebuf)) {
snprintf(buf, BUFLEN, "%s", actbuf);
capitalise(buf);
} else {
snprintf(buf, BUFLEN, "Mv:%s Act:%s", movebuf,actbuf);
}
doheadingsmall(mainwin, y2, x2, ftext, "Speed");
wprintw(mainwin, "%-20s", buf); y2++;
y2++; // skip line
if (showall) {
f = hasflag(lf->flags, F_HUNGER);
if (f) {
int i;
char hungerbar[11];
float pct;
enum COLOUR col;
doheadingsmall(mainwin, y2, x2, ftext, "Satiation");
// select colour for hungerbar
// hunger can be from -(const*2) up to (const*5)
pct = (((float)f->val[0] + (float)(HUNGERCONST*2)) / ((float)HUNGERCONST*7.0)) * 100;
limitf(&pct, 0, 100);
pct = 100 - pct;
col = gethungercol(gethungerlevel(f->val[0]));
// construct hungerbar
for (i = 0; i < 10; i++) {
if (pct >= (i*10)) {
hungerbar[i] = '*';
} else {
hungerbar[i] = '.';
}
}
hungerbar[10] = '\0';
//gethungername(lf, gethungerlevel(f->val[0]), buf);
capitalise(buf);
wprintw(mainwin, "[");
setcol(mainwin, col);
wprintw(mainwin, "%s", hungerbar);
unsetcol(mainwin, col);
wprintw(mainwin, "]");
y2++;
}
}
/////////////////////////////////////////////////////////
// now show bottom information.
// NOTE: most text here is wrapped, so make sure to end every bit of text with a space.
/////////////////////////////////////////////////////////
if (y2 > y) {
y = y2 + 1;
}
/*
if (!isplayer(lf)) {
char *descbuf = NULL;
int x=0;
// description first.
descbuf = malloc(HUGEBUFLEN * sizeof(char));
makedesc_race(lf->race->id, descbuf, B_FALSE );
//mvwprintw(mainwin, y, 0, "%s", descbuf);
wrapprint(mainwin, &y, &x, "%s", descbuf);
free(descbuf);
getyx(mainwin, y, x);
}
*/
// knowledge?
if (lf != player) {
char knowstring[BUFLEN];
switch (lorelev ){
case PR_NOVICE:
strcpy(knowstring, "You have heard of this creature.");
break;
case PR_BEGINNER:
strcpy(knowstring, "You know a little about this creature.");
break;
case PR_ADEPT:
strcpy(knowstring, "You are fairly knowledgable about this creature.");
break;
case PR_SKILLED:
strcpy(knowstring, "You have studied this creature in depth.");
break;
case PR_EXPERT:
strcpy(knowstring, "You are an expert on this creature.");
break;
case PR_MASTER:
strcpy(knowstring, "You are an absolute authority on this creature.");
break;
default:
strcpy(knowstring, "");
break;
}
if (strlen(knowstring)) {
char dambonusstr[BUFLEN];
// append dam bonus
snprintf(dambonusstr, BUFLEN, " (+%d%% acc/dmg)",(lorelev*10));
strcat(knowstring, dambonusstr);
// print it
setcol(mainwin, lorecol);
mvwprintw(mainwin, y, 0, "%s", knowstring);
unsetcol(mainwin, lorecol);
y++;
}
// extra info from lore?
if (lorelev >= PR_SKILLED) {
int hitstokillyou,hitstokillit;
hitstokillit = gethitstokill(player, lf, B_TRUE, B_TRUE);
hitstokillyou = gethitstokill(lf, player, B_TRUE, B_TRUE);
if (hitstokillit == hitstokillyou) {
if (hitstokillit) {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "You could both kill each other in %d hit%s. ", hitstokillit,
(hitstokillit == 1) ? "" : "s");
unsetcol(mainwin, lorecol);
} else {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "Neither of you would be able to kill the other. ");
unsetcol(mainwin, lorecol);
}
} else {
if (hitstokillit) {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "You could kill it in %d hit%s. ", hitstokillit,
(hitstokillit == 1) ? "" : "s");
unsetcol(mainwin, lorecol);
} else {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "You would never be able to kill it. ");
unsetcol(mainwin, lorecol);
}
if (hitstokillyou) {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "It could kill you in %d hit%s. ", hitstokillyou,
(hitstokillyou == 1) ? "" : "s");
unsetcol(mainwin, lorecol);
} else {
setcol(mainwin, lorecol);
wrapprint(mainwin, &y, &x, "It would never be able to kill you. ");
unsetcol(mainwin, lorecol);
}
}
}
if (lorelev >= PR_ADEPT) {
float rating;
// get threat rating
rating = comparelfs(player, lf);
setcol(mainwin, lorecol);
if (rating >= 4) {
snprintf(buf, BUFLEN, "It should pose no threat to you.");
} else if (rating >= 3) {
snprintf(buf, BUFLEN, "You could defeat it very easily.");
} else if (rating >= 2) {
snprintf(buf, BUFLEN, "You could defeat it quite easily.");
} else if (rating >= 1) {
snprintf(buf, BUFLEN, "It would present an average challenge.");
} else if (rating >= 0.5) {
snprintf(buf, BUFLEN, "It would be challenging to defeat.");
} else if (rating >= 0.25) {
snprintf(buf, BUFLEN, "It would make a formidable opponent.");
} else if (rating >= 0.125) {
snprintf(buf, BUFLEN, "It is very dangerous to you.");
} else {
snprintf(buf, BUFLEN, "It is EXTREMELY dangerous to you.");
}
//mvwprintw(mainwin, y, 0, "Threat rating: %0.1f",comparelfs(player, lf));
wrapprint(mainwin, &y, &x, "%s ", buf);
unsetcol(mainwin, lorecol);
y++; x = 0;
}
}
// obvious physical effects here.
f = lfhasknownflag(lf, F_ASLEEP);
if (f) {
char sleepname[BUFLEN];
switch (f->val[1]) {
case ST_ASLEEP:
strcpy(sleepname, "sleeping"); break;
case ST_MEDITATING:
strcpy(sleepname, "meditating"); break;
case ST_KO:
strcpy(sleepname, "unconscious"); break;
}
wrapprint(mainwin, &y, &x, "%s %s %s. ", you(lf), is(lf), sleepname);
}
f = lfhasknownflag(lf, F_ATTACHEDTO);
if (f && (f->known)) {
lifeform_t *lf2;
char grabeename[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabeename);
} else {
strcpy(grabeename, "something");
}
snprintf(buf, BUFLEN,"%s %s attached to %s.",you(lf), is(lf), grabeename);
wrapprint(mainwin, &y, &x, "%s ", buf);
}
if (isbleeding(lf)) {
wrapprint(mainwin, &y, &x, "%s %s bleeding. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_CLIMBING);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s climbing on a wall. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_FASTMETAB);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s metabolic rate has been increased. ", your(lf), getpossessive(you(lf)));
}
f = lfhasknownflag(lf, F_FEIGNINGDEATH);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s pretending to be dead. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_FLYING);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s flying. ", you(lf), is(lf));
}
if (isswimming(lf)) {
wrapprint(mainwin, &y, &x, "%s %s swimming. ", you(lf), is(lf));
}
if (isclimbing(lf)) {
wrapprint(mainwin, &y, &x, "%s %s currently climbing. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_PRONE);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s lying on the ground. ", you(lf), is(lf));
}
f = lfhasflag(lf, F_FROZEN);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s been turned to ice, and %s slowly melting. ", you(lf), isplayer(lf) ? "have" : "has",
is(lf));
}
f = lfhasknownflag(lf, F_GRABBEDBY);
if (f && (f->known)) {
lifeform_t *lf2;
char grabbername[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabbername);
} else {
strcpy(grabbername, "something");
}
snprintf(buf, BUFLEN,"%s %s being held by %s.",you(lf), is(lf), grabbername);
wrapprint(mainwin, &y, &x, "%s ",buf);
}
f = lfhasknownflag(lf, F_GRABBING);
if (f && (f->known)) {
lifeform_t *lf2;
char grabeename[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, grabeename);
} else {
strcpy(grabeename, "something");
}
snprintf(buf, BUFLEN,"%s %s holding on to %s.",you(lf), is(lf), grabeename);
wrapprint(mainwin, &y, &x, "%s ", buf);
}
f = lfhasknownflag(lf, F_HIDING);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s hiding. ", you(lf), is(lf));
}
getflags(lf->flags, retflag, &nretflags, F_INJURY, F_NONE);
for (i = 0; i < nretflags; i++) {
char *p;
char injname[BUFLEN],injdesc[BUFLEN];
f = retflag[i];
p = readuntil(injname, f->text, '^');
readuntil(injdesc, p, '^');
wrapprint(mainwin, &y, &x, "^%c%s %s (%s). ", getlfcol(lf, CC_VBAD), your(lf), injname, injdesc);
}
f = lfhasknownflag(lf, F_INVISIBLE);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s invisible. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_LEVITATING);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s levitating. ", you(lf), is(lf));
}
f = lfhasflag(lf, F_NONCORPOREAL);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s noncorporeal and can walk through walls. ", you(lf), is(lf));
}
f = lfhasflag(lf, F_PRODUCESLIGHT);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s produce%s light. ", you(lf), isplayer(lf) ? "" : "s");
}
f = lfhasknownflag(lf, F_SLOWMETAB);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s metabolic rate has been decreased. ", your(lf), getpossessive(you(lf)));
}
f = lfhasknownflag(lf, F_SPRINTING);
if (f) {
wrapprint(mainwin, &y, &x, "%s %s sprinting. ", you(lf), is(lf));
}
if (!getstamina(lf)) {
wrapprint(mainwin, &y, &x, "%s %s exhausted. ", you(lf), is(lf));
}
f = lfhasknownflag(lf, F_UNDEAD);
if (f) {
wrapprint(mainwin, &y, &x, "%s %s undead. ", you(lf), is(lf));
}
// non-intrinsic effecst like polymorph, eye shading
f = lfhasknownflag(lf, F_POLYMORPHED);
if (f && (f->known)) {
snprintf(buf, BUFLEN, "%s have been polymorphed into a %s.",you(lf), lf->race->name);
//if (lfhasflag(lf, F_OMNIPOTENT) || lfhasflag(lf, F_EXTRAINFO)) {
snprintf(buf2, BUFLEN, " [%d left]", f->lifetime);
strcat(buf, buf2);
// }
wrapprint(mainwin, &y, &x, "%s ", buf);
}
if (!canuseweapons(lf)) {
wrapprint(mainwin, &y, &x, "%s cannot use weapons. ", you(lf));
}
nmissingbp = 0;
getflags(lf->flags, retflag, &nretflags, F_NOBODYPART, F_NONE);
for (i = 0; i < nretflags; i++) {
bp = retflag[i]->val[0];
if (bp == BP_RIGHTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_LEFTFINGER) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL) &&
!lfhasflagval(lf, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL)
) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else if (bp == BP_SECWEAPON) {
if (!lfhasflagval(lf, F_NOBODYPART, BP_HANDS, NA, NA, NULL)) {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
} else {
missingbp[nmissingbp] = bp;
nmissingbp++;
}
}
if (nmissingbp) {
snprintf(buf, BUFLEN, "%s %s no %s",you(lf), isplayer(lf) ? "have" : "has", getbodypartname(lf, missingbp[0]));
if (nmissingbp > 1) {
// construct list of missing body parts
for (i = 1; i < nmissingbp ; i++) {
if (i == nmissingbp - 1) { // last
strcat(buf, " or ");
strcat(buf, getbodypartname(lf, missingbp[i]));
} else {
strcat(buf, ", ");
strcat(buf, getbodypartname(lf, missingbp[i]));
}
}
}
strcat(buf, ".");
wrapprint(mainwin, &y, &x, "%s ", buf);
}
f = lfhasflag(lf, F_REFLECTION);
if (f && (f->known)) {
wrapprint(mainwin, &y, &x, "%s %s surrounded by a negative gravity field.", you(lf), is(lf));
}
f = lfhasflag(lf, F_RETALIATE);
if (f && (f->known)) {
if (showall || (lorelev >= PR_BEGINNER)) {
wrapprint(mainwin, &y, &x, "%s %s covered by %s (%dd%d %s dmg to attackers). ", you(lf), is(lf), f->text,
f->val[0], f->val[1], getdamname(f->val[2]));
} else {
wrapprint(mainwin, &y, &x, "%s %s covered by %s ", you(lf), is(lf), f->text);
}
}
// fleeing?
if (showall) {
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_FLEEFROM) {
lifeform_t *lf2;
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfname(lf2, buf);
wrapprint(mainwin, &y, &x, "%s %s fleeing from %s. ", you(lf), is(lf), buf);
}
}
}
}
// diff materials?
if (getlfmaterial(lf) != MT_FLESH) {
material_t *mt;
mt = findmaterial(getlfmaterial(lf));
wrapprint(mainwin, &y, &x, "%s %s made out of %s. ",you(lf), is(lf), mt->name);
}
} else if (mode == 'a') {
centre(mainwin, C_WHITE, 0, "ABILITIES");
y = 2;
for (ot = objecttype ; ot ; ot = ot->next) {
f = lfhasknownflagval(lf, F_CANWILL, ot->id, NA, NA, NULL);
if (f && (f->known)) {
char expirebuf[BUFLEN];
char eb2[BUFLEN],racestr[BUFLEN];
int needgrab = B_FALSE;
int range;
if (f->val[2] == NA) {
snprintf(expirebuf, BUFLEN, "at will");
} else {
snprintf(expirebuf, BUFLEN, "every %d turn%s",f->val[2],
(f->val[2] == 1) ? "" : "s");
}
// extra options?
texttospellopts(f->text, "needgrab:", &needgrab, "range:", &range, "race:", racestr, NULL);
if (needgrab) {
strcat(expirebuf, ",after grab");
}
if (range) {
char rbuf[BUFLEN];
snprintf(rbuf, BUFLEN, ",range:%d",range);
strcat(expirebuf, rbuf);
}
if (strlen(racestr)) {
char rbuf[BUFLEN];
snprintf(rbuf, BUFLEN, ",race:%s",racestr);
strcat(expirebuf, rbuf);
}
if (strlen(expirebuf)) {
snprintf(eb2, BUFLEN,"(%s)",expirebuf);
} else {
strcpy(eb2, "");
}
setcol(mainwin, C_GREEN);
snprintf(buf, BUFLEN, "%-12s", ot->name);
mvwprintw(mainwin, y, 0, buf);
unsetcol(mainwin, C_GREEN);
snprintf(buf, BUFLEN, "%s%s", ot->desc, eb2);
wprintw(mainwin, buf);
if (downline(&y, h, "ABILITIES", NULL, promptstr, cmdchars, &ch)) {
break;
}
}
}
y++;
} else if (mode == 's') {
char skilltitle[BUFLEN];
enum SKILLLEVEL slev;
skill_t *sk;
int finished = B_FALSE,dounknown;
centre(mainwin, C_WHITE, 0, "SKILLS");
y = 2;
snprintf(skilltitle, BUFLEN, "%-21s"," ");
for (i = PR_NOVICE; i <= PR_MASTER; i++) {
char toadd[BUFLEN], *sn;
int prepad,postpad,n;
// construct: "|xxxxxxxx"
// ie "|Beginner"
// ie "| Inept "
sn = getskilllevelname(i);
prepad = (8 - strlen(sn))/2;
postpad = 8 - strlen(sn) - prepad;
limit(&postpad, 0, NA);
sprintf(toadd, "|^%d", getskilllevelcolour(i));
for (n = 0;n < prepad; n++) strcat(toadd, " ");
strcat(toadd, sn);
for (n = 0;n < postpad; n++) strcat(toadd, " ");
strcat(toadd, "^n");
strcat(skilltitle, toadd);
}
doheading(mainwin, &y, 0, skilltitle);
// for each skill...
for (dounknown = 0; dounknown <= 1; dounknown++) {
for (sk = firstskill ; sk ; sk = sk->next) {
char thisline[BUFLEN];
int printed = B_FALSE;
slev = getskill(lf, sk->id);
if (!dounknown && (slev != PR_INEPT)) {
char endbit[BUFLEN];
char basecolour = 'n';
int max;
if (ismaxedskill(lf, sk->id)) {
basecolour = 'h';
}
// known skill
sprintf(thisline, "^%c%-21s^%c[^%d", basecolour, sk->name, basecolour,
getskilllevelcolour(slev));
max = getmaxskilllevel(player, sk->id);
for (i = PR_NOVICE; i <= PR_MASTER; i++) {
char toadd[BUFLEN];
/*if (i == (max+1)) {
sprintf(toadd, "^n]########");
} else if (i > max) {
sprintf(toadd, "^n#########");
} else*/
if (i <= max) {
if (i == slev) {
if (ismaxedskill(lf, sk->id)) {
sprintf(toadd, "*********");
} else {
sprintf(toadd, "========|");
}
} else if (i < slev) {
if (ismaxedskill(lf, sk->id)) {
sprintf(toadd, "*********");
} else {
sprintf(toadd, "=========");
}
} else {
sprintf(toadd, "^n.........");
}
strcat(thisline, toadd);
}
}
sprintf(endbit, "^%c]^n",basecolour);
strcat(thisline, endbit);
wmove(mainwin, y, 0);
textwithcol(mainwin, thisline);
printed = B_TRUE;
} else if (dounknown && !slev && lfhasflagval(lf, F_CANLEARN, sk->id, NA, NA, NULL)) {
char toadd[BUFLEN];
int max;
// learnable skill
sprintf(toadd, "^B%-21s[", sk->name );
wmove(mainwin, y, 0);
textwithcol(mainwin, toadd);
max = getmaxskilllevel(player, sk->id);
for (i = PR_NOVICE; i <= PR_MASTER; i++) {
/*
if (i == max+1) {
textwithcol(mainwin, "^B]########");
} else if (i > max) {
textwithcol(mainwin, "^B#########");
} else {
wprintw(mainwin, " ");
}
*/
if (i <= max) {
textwithcol(mainwin, "^B.........");
}
}
textwithcol(mainwin, "^B]^n");
printed = B_TRUE;
}
if (printed) {
if (downline(&y, h, "SKILLS", skilltitle, promptstr, cmdchars, &ch)) {
finished = B_TRUE;
break;
}
}
}
}
} else if (mode == 'm') {
char subheading[BUFLEN];
int lev;
int anyfound;
int exitnow = B_FALSE;
snprintf(subheading, BUFLEN, " %-4s%-26s%-15s%-13s%s","Lv","Spell", "School", "Power", "Cost");
centre(mainwin, C_WHITE, y, "MAGIC"); y += 2;
doheading(mainwin, &y, 0, subheading);
// show spells monster can cast using mp
for (lev = 0; (lev <= 9) && !exitnow; lev++) {
for (ot = objecttype ; ot && !exitnow ; ot = ot->next) {
if (ot->obclass->id == OC_SPELL) {
int thislev;
thislev = getspelllevel(ot->id);
if (thislev == lev) {
f = lfhasknownflagval(lf, F_CANCAST, ot->id, NA, NA, NULL);
if (f && (f->known)) {
char spellname[BUFLEN];
char mpbuf[BUFLEN];
char powerbuf[BUFLEN];
int power;
int mpcost;
int castable = B_TRUE;
int atwill = B_FALSE;
// power
power = getspellpower(lf, ot->id);
snprintf(powerbuf, BUFLEN, "[");
for (i = 0; i < power; i++) {
strcat(powerbuf, "#");
}
for (i = 0; i < (getspellmaxpower(ot->id) - power); i++) {
strcat(powerbuf, "-");
}
strcat(powerbuf, "]");
// mp cost
if (f->id == F_CANWILL) {
mpcost = 0;
if (f->val[2] == NA) {
snprintf(mpbuf, BUFLEN, "At will");
} else {
snprintf(mpbuf, BUFLEN, "At will, every %d turn%s",f->val[2],
(f->val[2] == 1) ? "" : "s");
}
atwill = B_TRUE;
} else {
mpcost = getmpcost(lf, ot->id);
if (mpcost) {
getspellcosttext(lf, ot->id, power, mpbuf);
} else {
snprintf(mpbuf, BUFLEN, "At will");
}
}
if (!atwill) {
if ((mpcost > getmaxmp(lf)) || (power <= 0)) {
castable = B_FALSE;
}
}
getspellname(ot->id, lf, spellname);
if (castable) setcol(mainwin, C_GREEN);
else setcol(mainwin, C_RED);
snprintf(buf, BUFLEN, " %-4d%-26s%-15s%-13s%s",thislev, spellname, getschoolnameshort(getspellschoolknown(lf, ot->id)), powerbuf, mpbuf);
mvwprintw(mainwin, y, 0, "%s\n", buf);
if (castable) unsetcol(mainwin, C_GREEN);
else unsetcol(mainwin, C_RED);
anyfound = B_TRUE;
if (downline(&y, h, "MAGIC", subheading, promptstr, cmdchars, &ch)) {
exitnow = B_TRUE;
break;
}
}
}
}
}
}
if (!anyfound) {
mvwprintw(mainwin, y, 0, "%s cannot cast any spells.", you(lf));
}
} else if (mode == 'e') {
int nfound = 0,luckmod;
x = 0; // override
// down a line.
centre(mainwin, C_WHITE, y, "EFFECTS");
y += 2;
// ready to gain a level?
if (lfhasflag(lf, F_STATGAINREADY)) {
mvwprintw(mainwin, y, 0, "%s are ready to train your attributes.", you(lf));
y++;
}
if (lf->skillpoints) {
mvwprintw(mainwin, y, 0, "%s are ready to learn a new skill.", you(lf));
y++;
}
if (levelabilityready(lf)) {
mvwprintw(mainwin, y, 0, "%s are ready to learn a new job-based ability.", you(lf));
y++;
}
// spells
nfound = 0;
for (f = lf->flags->first ; f ; f = f->next) {
if (f->id == F_BOOSTSPELL) {
objecttype_t *sp;
sp = findot(f->val[0]);
if (sp) {
if (nfound == 0) {
mvwprintw(mainwin, y, 0, "%s %s the following spells active:", you(lf),
isplayer(lf) ? "have" : "has");
y++;
}
mvwprintw(mainwin, y, 0, " - %s %s (consuming %d MP)", sp->name, roman(f->val[2]), f->val[1]);
y++;
nfound++;
}
}
}
if (nfound) y++;
// obvious physical effects first.
f = lfhasknownflag(lf, F_BEINGSTONED);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s being turning to stone.", you(lf), is(lf));
y++;
}
if (eyesshaded(lf)) {
mvwprintw(mainwin, y, 0, "%s eyes are shaded.", your(lf), buf);
y++;
}
f = lfhasflag(lf, F_FLAMMABLELF);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s covered in %s.", you(lf), is(lf), f->text);
y++;
}
// show racial effects
if (hasjob(lf, J_PIRATE)) {
mvwprintw(mainwin, y, 0, "%s can hold %s liquor well.", you(lf), isplayer(lf) ? "Your" : "its");
y++;
mvwprintw(mainwin, y, 0, "%s %s missing one eye.", you(lf), is(lf));
y++;
}
if (hasjob(lf, J_DRUID)) {
mvwprintw(mainwin, y, 0, "%s spell power is boosted by nearby plants.", isplayer(lf) ? "Your" : "Its");
y++;
mvwprintw(mainwin, y, 0, "%s regenerate mana when plants are nearby.", you(lf));
y++;
}
if (lfhasflag(lf, F_CANCAST)) {
int chance;
chance = getmiscastchance(lf);
if (chance) {
mvwprintw(mainwin, y, 0, "%s spells have a %d%% chance of failing due to cumbersome armour.", your(lf), chance);
y++;
}
}
// we DONT show traits based on the monster's racial characteristics
// here. leave that to makedesc_race.
//
// This display is only for effects specific to this INDIVIDUAL lifeform.
if (showall || (lorelev >= PR_NOVICE)) {
if (isdeaf(lf)) {
mvwprintw(mainwin, y, 0, "%s %s deaf.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_ENHANCESMELL);
if (f && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s %s an enhanced sense of smell.", you(lf), isplayer(lf) ? "have" : "has");
y++;
}
f = lfhasknownflag(lf, F_DISEASEIMMUNE);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s immune to disease.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_HEAVYBLOW);
if (f && (f->lifetime != FROMRACE)) {
snprintf(buf, BUFLEN,"%s%s attacks knock enemies back.", you(lf), getpossessive(you(lf)));
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasknownflag(lf, F_REGENERATES);
if (f) {
char regenspeed[BUFLEN];
if (f->val[0] == 1) {
strcpy(regenspeed, "");
} else if (f->val[0] == 2) {
strcpy(regenspeed, " quickly");
} else if (f->val[0] == 3) {
strcpy(regenspeed, " very quickly");
} else { // >= 4
strcpy(regenspeed, " extremely quickly");
}
mvwprintw(mainwin, y, 0, "%s regenerate%s health%s.", you(lf),isplayer(lf) ? "" : "s", regenspeed);
y++;
}
f = lfhasknownflag(lf, F_RESISTMAG);
if (f) {
int mr;
char adjective[BUFLEN];
mr = getmr(lf);
if (mr <= 5) {
strcpy(adjective, "slightly");
} else if (mr <= 10) {
strcpy(adjective, "quite");
} else if (mr <= 15) {
strcpy(adjective, "very");
} else if (mr <= 20) {
strcpy(adjective, "extremely");
} else { // ie. 21 upwards
strcpy(adjective, "incredibly");
}
mvwprintw(mainwin, y, 0, "%s %s %s resistant to magic.", you(lf), is(lf), adjective);
y++;
}
f = lfhasknownflag(lf, F_TREMORSENSE);
if (f && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s can 'see' by sensing vibrations around %s.", you(lf), you(lf));
y++;
}
f = lfhasflag(lf, F_STENCH);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s smell%s terrible.", you(lf), isplayer(lf) ? "" : "s");
y++;
}
f = lfhasknownflag(lf, F_SEEINDARK);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s can see in the dark.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_SEEINVIS);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s can see invisible things.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_SPIDERCLIMB);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s adhesive skin allows %s to climb walls.", your(lf), you(lf));
y++;
}
f = lfhasknownflag(lf, F_STABILITY);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s will not fall on slippery ground.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_XRAYVIS);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s can see through walls.", you(lf));
y++;
}
getflags(lf->flags, retflag, &nretflags, F_CANSEETHROUGHMAT, F_NONE);
for (i = 0; i < nretflags; i++) {
material_t *m;
f = retflag[i];
m = findmaterial(f->val[0]);
if (m) {
mvwprintw(mainwin, y, 0, "%s can see through %s.", you(lf), m->name);
y++;
}
}
}
// traits based on the monster's bevaviour.
// only known if you've studied this creature type a bit.
if (showall || (lorelev >= PR_BEGINNER)) {
// morale and sleeping habits
if (!isplayer(lf)) {
int morale;
char moralebuf[BUFLEN];
morale = getmorale(lf);
if (morale >= 30) {
strcpy(moralebuf, "fearless");
} else if (morale >= 20) {
strcpy(moralebuf, "bold");
} else if (morale >= 10) {
strcpy(moralebuf, "confident");
} else if (morale >= 5) {
strcpy(moralebuf, "fairly confident");
} else if (morale >= 0) {
strcpy(moralebuf, "hesitant");
} else {
strcpy(moralebuf, "nervous");
}
mvwprintw(mainwin, y, 0, "It looks %s.", moralebuf); y++;
}
// damage desistances/vulnerabilities
// resistances
strcpy(buf, "");
f = lfhasflagval(lf, F_DTRESIST, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "%s %s resistant to %s", you(lf), is(lf), getdamname(DT_ALL));
} else {
first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isresistantto(lf->flags, i, B_TRUE);
if (f) {
if (first) {
snprintf(buf2, BUFLEN, "%s %s resistant to: %s", you(lf), is(lf),getdamnamenoun(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamnamenoun(i));
}
if (lfhasknownflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) {
if (f->lifetime != PERMENANT) {
char buf3[BUFLEN];
snprintf(buf3, BUFLEN, "[%dt]",f->lifetime);
strcat(buf2, buf3);
}
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
wrapprint(mainwin, &y, &x, buf);
}
// immunities
strcpy(buf, "");
f = lfhasflagval(lf, F_DTIMMUNE, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "%s %s immune to %s", you(lf), is(lf), getdamname(DT_ALL));
} else {
first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isimmuneto(lf->flags, i, B_TRUE);
if (f) {
if (first) {
snprintf(buf2, BUFLEN, "%s %s immune to: %s", you(lf), is(lf), getdamname(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamname(i));
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
wrapprint(mainwin, &y, &x, buf);
}
// vulnerabilities
strcpy(buf, "");
f = lfhasflagval(lf, F_DTVULN, DT_ALL, NA, NA, NULL);
if (f) {
snprintf(buf, BUFLEN, "%s %s vulnerable to %s", you(lf), is(lf), getdamname(DT_ALL));
} else {
first = B_TRUE;
for (i = 0; i < MAXDAMTYPE; i++) {
if (basedamagetype(i) != i) continue;
f = isvulnto(lf->flags, i, B_TRUE);
if (f) {
if (first) {
snprintf(buf2, BUFLEN, "%s %s vulnerable to: %s", you(lf), is(lf), getdamnamenoun(i));
first = B_FALSE;
} else {
snprintf(buf2, BUFLEN, ", %s", getdamnamenoun(i));
}
if (lfhasknownflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) {
if (f->lifetime > 0) {
char buf3[BUFLEN];
snprintf(buf3, BUFLEN, "[%dturns]",f->lifetime);
strcat(buf2, buf3);
}
}
strcat(buf, buf2);
}
}
}
if (strlen(buf) > 0) {
strcat(buf, ".\n");
wrapprint(mainwin, &y, &x, buf);
}
// wants/desires
if (!isplayer(lf)) {
getflags(lf->flags, retflag, &nretflags, F_WANTS, F_WANTSOBFLAG, F_WANTSBETTERWEP, F_WANTSBETTERARM, F_NONE);
for (i = 0; i < nretflags; i++) {
f = retflag[i];
if (f->id == F_WANTS) {
char *pname;
objecttype_t *ot;
ot = findot(f->val[0]);
pname = makeplural(ot->name);
mvwprintw(mainwin, y, 0, "It %s %s.", (f->val[1] == B_COVETS) ? "covets" : "wants", pname);
y++;
free(pname);
} else if (f->id == F_WANTSOBFLAG) {
char what[BUFLEN];
switch (f->val[0]) {
case F_EDIBLE: strcpy(what, "edible things"); break;
case F_OPERABLE: strcpy(what, "tools and technology"); break;
case F_RARITY: strcpy(what, "all objects"); break; // special case
default:
strcpy(what, "some objects"); break; // shouldn't happen
}
mvwprintw(mainwin, y, 0, "It %s %s.", (f->val[1] == B_COVETS) ? "covets" : "wants", what);
y++;
} else if (f->id == F_WANTSBETTERWEP) {
mvwprintw(mainwin, y, 0, "It %s better weapons.", (f->val[1] == B_COVETS) ? "covets" : "wants");
y++;
} else if (f->id == F_WANTSBETTERARM) {
mvwprintw(mainwin, y, 0, "It %s better armour.", (f->val[1] == B_COVETS) ? "covets" : "wants");
y++;
}
}
}
}
// show intrinsics
f = lfhasknownflag(lf, F_ATTRSET);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s has been modified.", your(lf), getattrname(f->val[0]));
y++;
} else {
f = lfhasknownflag(lf, F_ATTRMOD);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s has been %s.", your(lf), getattrname(f->val[0]), (f->val[1] > 0) ? "increased" : "decreased");
y++;
}
}
if (lfhasknownflag(lf, F_ANONYMOUS)) {
mvwprintw(mainwin, y, 0, "%s identity is obscured.", your(lf));
y++;
}
f = lfhasknownflag(lf, F_AWARENESS);
if (f && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s can see things which are behind %s.", you(lf), you(lf));
y++;
}
f = lfhasknownflag(lf, F_MAGICARMOUR);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s protected by %s %s", you(lf), is(lf),
needan(f->text) ? "an" : "a", f->text);
if (isplayer(lf)) {
wprintw(mainwin, " (+%d AR).",f->val[0]);
} else {
wprintw(mainwin, ".");
}
y++;
}
f = lfhasknownflag(lf, F_MAGICBOOST);
if (f && (f->known)) {
int boost;
sumflags(lf->flags, F_MAGICBOOST, &boost, NULL, NULL);
mvwprintw(mainwin, y, 0, "The power of %s spells is boosted by %d.",
isplayer(lf) ? "your" : "its", boost);
y++;
}
f = lfhasflag(lf, F_OMNIPOTENT);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s are omnipotent.", you(lf));
y++;
}
if (isblind(lf)) {
mvwprintw(mainwin, y, 0, "%s cannot see.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_CHARMEDBY);
if (f) {
lifeform_t *lf2;
char charmername[BUFLEN];
lf2 = findlf(NULL, f->val[0]);
if (lf2) {
getlfnamea(lf2, charmername);
} else {
strcpy(charmername, "something");
}
snprintf(buf, BUFLEN,"%s %s been charmed by %s.",you(lf), isplayer(lf) ? "have" : "has", charmername);
mvwprintw(mainwin, y, 0, buf);
y++;
}
if (lfhasknownflag(lf, F_BREATHWATER) || lfhasknownflag(lf, F_AQUATIC)) {
mvwprintw(mainwin, y, 0, "%s can breath normally while underwater.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_CONTROL);
if (f) {
mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_CONFUSED);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s confused.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_DETECTAURAS);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect blessings or curses.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_DETECTLIFE);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect %snearby lifeforms.", you(lf),
(f->val[1] == B_TRUE) ? "" : "the size of ");
y++;
}
f = lfhasknownflag(lf, F_DETECTMAGIC);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect magical enchantments on objects.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_DETECTMETAL);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect nearby metal.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_DETECTOBS);
if (f) {
mvwprintw(mainwin, y, 0, "%s automatically detect nearby objects.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_ENHANCESEARCH);
if (f) {
mvwprintw(mainwin, y, 0, "%s searching ability is enhanced.", you(lf), isplayer(lf) ? "Your" : "Its");
y++;
}
f = lfhasknownflag(lf, F_DRUNK);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s %s.", you(lf), is(lf), getdrunktext(f));
y++;
}
getflags(lf->flags, retflag, &nretflags, F_EXTRADAM, F_NONE);
for (i = 0; i < nretflags; i++) {
int ndice,nsides,bonus;
char dicebuf[BUFLEN];
char mmbuf[BUFLEN];
char damtypebuf[BUFLEN];
int min = 0,max = 0;
f = retflag[i];
texttodice(f->text, &ndice,&nsides,&bonus);
if ((f->lifetime == FROMOBEQUIP) ||
(f->lifetime == FROMOBHOLD) ||
(f->lifetime == FROMOBACTIVATE) ) {
object_t *obfrom;
obfrom = findobbyid(lf->pack, f->obfrom);
if (obfrom) {
int bonusdam;
sumflags(obfrom->flags, F_BONUS, &bonusdam, NULL, NULL);
bonus += bonusdam;
}
}
if (f->val[0] == NA) {
strcpy(damtypebuf, "damage");
} else {
snprintf(damtypebuf, BUFLEN, "%s damage", getdamname(f->val[0]));
}
dicetotext(ndice, nsides, bonus, &min, &max, dicebuf, mmbuf);
if (strcmp(dicebuf, mmbuf)) {
mvwprintw(mainwin, y, 0, "%s deal%s %s (%s) extra %s each hit.", you(lf),
isplayer(lf) ? "" : "s", dicebuf, mmbuf, damtypebuf);
} else {
mvwprintw(mainwin, y, 0, "%s deal%s %s extra %s each hit.", you(lf),
isplayer(lf) ? "" : "s", dicebuf, damtypebuf);
}
y++;
}
sumflags(lf->flags, F_EXTRALUCK, &luckmod, NULL, NULL);
if (luckmod) {
char luckamt[BUFLEN];
switch (luckmod) {
case 1: strcpy(luckamt, "fairly "); break;
case 2: strcpy(luckamt, "quite "); break;
case 3: strcpy(luckamt, "very "); break;
case 4: strcpy(luckamt, "extremely "); break;
case 5:
default:
strcpy(luckamt, "incredibly "); break;
}
mvwprintw(mainwin, y, 0, "%s %s %slucky.", you(lf), is(lf), luckamt);
y++;
}
f = lfhasknownflag(lf, F_EXTRAMP);
if (f) {
mvwprintw(mainwin, y, 0, "Your mana pool is being boosted.", you(lf));
y++;
}
f = lfhasknownflag(lf, F_EXTRAINFO);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s receive enhanced knowledge about the world.", you(lf));
y++;
}
for (f = lf->flags->first ; f ; f = f->next ){
if (f->known && (f->id == F_POISONED)) {
int knownfatal = B_FALSE;
if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) {
if (poisonthreatenslife(lf, f)) {
knownfatal = B_TRUE;
}
}
snprintf(buf, BUFLEN, "%s %s sick with %s%s.", you(lf), is(lf),
getpoisonname(f->val[0]),
knownfatal ? ", potentially fatally" : "");
if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) ||
(getskill(player, SK_FIRSTAID) >= PR_ADEPT) ) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, " [max %d turns left]", f->lifetime);
strcat(buf, buf2);
}
mvwprintw(mainwin, y, 0, buf);
y++;
}
}
f = lfhasflag(lf, F_NAUSEATED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s nauseated.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_HOLYAURA);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s surrounded by a holy aura.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_ICESLIDE);
if (f) {
msg("%s%s feet automatically generating sheets of ice.",your(lf));
}
f = lfhasknownflag(lf, F_FREEZINGTOUCH);
if (f && (f->known)) {
strcpy(buf,"The next object you touch will turn to solid ice.");
if (lfhasflag(lf, F_OMNIPOTENT)) {
char buf2[BUFLEN];
snprintf(buf2, BUFLEN, " [%d uses left]", f->val[0]);
strcat(buf, buf2);
}
mvwprintw(mainwin, y, 0, buf);
y++;
}
f = lfhasflag(lf, F_GRAVBOOSTED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "Gravity is increased around %s.", you_l(lf));
y++;
}
f = lfhasflag(lf, F_GRAVLESSENED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "Gravity is lessened around %s, preventing fall damage and increasing flight speed.", you_l(lf));
y++;
}
f = lfhasknownflag(lf, F_INVULNERABLE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s protected from all physical harm.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_MAGSHIELD);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s surrounded by a magnetic shield.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_PAIN);
if (f && (f->known)) {
if (lfhasflag(lf, F_DRUNK)) {
mvwprintw(mainwin, y, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.", you(lf), is(lf), isplayer(lf) ? "Your" : "its");
} else {
mvwprintw(mainwin, y, 0, "%s %s in extreme pain, and movement will cause %s damage.", you(lf), is(lf), isplayer(lf) ? "You" : "it");
}
y++;
}
f = lfhasflag(lf, F_PARALYZED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s paralyzed.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_PHOTOMEM);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s do not forget your surroundings.", you(lf));
y++;
}
f = lfhasflag(lf, F_RAGE);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s enraged, gaining accuracy, damage and hit point bonuses.", you(lf), is(lf));
y++;
}
f = lfhasknownflag(lf, F_TRUESTRIKE);
if (f) {
mvwprintw(mainwin, y, 0, "%s%s attacks will automatically hit.", you(lf), getpossessive(you(lf)));
y++;
}
f = lfhasknownflag(lf, F_WINDSHIELD);
if (f) {
mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), is(lf));
if (isplayer(lf)) {
wprintw(mainwin, " (power %d).",roman(f->val[0]));
} else {
wprintw(mainwin, ".");
}
y++;
}
f = lfhasflag(lf, F_RISEASGHOST);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s will rise as a ghost after death.", you(lf));
y++;
}
f = lfhasflag(lf, F_STENCH);
if (f && (f->known) && (f->lifetime != FROMRACE)) {
mvwprintw(mainwin, y, 0, "%s %s emitting a foul stench, nauseating those nearby.", you(lf), is(lf));
y++;
}
f = lfhasflag(lf, F_STUNNED);
if (f && (f->known)) {
mvwprintw(mainwin, y, 0, "%s %s stunned and cannot attack, cast spells or use abilities.", you(lf), is(lf));
y++;
}
} else if (mode == 'i') {
object_t *o;
cls();
if (lf == player) { // mindscanning it
centre(mainwin, C_WHITE, 0, "INVENTORY");
} else { // not mindscanning
centre(mainwin, C_WHITE, 0, "INVENTORY (equipped items only)");
}
y = 2;
if ((lf == player) && lfhasflag(lf, F_NOPACK)) {
mvwprintw(mainwin, y, 0, "It cannot carry anything.");
} else if (countobs(lf->pack, B_FALSE)) {
char invtitle[BUFLEN];
if (lf == player) {
float packweight,maxweight,pct;
packweight = getobpileweight(lf->pack);
maxweight = getmaxcarryweight(lf);
pct = (packweight / maxweight) * 100;
snprintf(invtitle, BUFLEN, "It is carrying: (%0.0f/%0.0f kg, %0.0f%%)", packweight, maxweight, pct);
} else {
snprintf(invtitle, BUFLEN, "It is using:");
}
mvwprintw(mainwin, y, 0, "%s", invtitle);
y += 2;
for (o = lf->pack->first ; o ; o = o->next) {
if ((lf == player) || isequipped(o)) {
getobname(o, buf,o->amt);
getobequipinfo(o, buf2); strcat(buf, buf2);
getobextrainfo(o, buf2); strcat(buf, buf2);
mvwprintw(mainwin, y, 0, "%s", buf);
if (o->next && downline(&y, h, "INVENTORY", NULL, promptstr, cmdchars, &ch)) {
break;
}
}
}
} else {
mvwprintw(mainwin, y, 0, "It is not carrying anything.");
}
} else if (mode == 'g') {
int i;
char line[BUFLEN];
cls();
centre(mainwin, C_WHITE, 0, "GODS");
y = 2;
snprintf(line, BUFLEN, "%-26s Prayed? %-22s %s","God","Piety", "Happiness");
doheading(mainwin, &y, 0, line);
for (i = 0; i < ngodlfs; i++) {
lifeform_t *god;
flag_t *f;
char godname[BUFLEN];
char pietybuf[BUFLEN];
char happiness[BUFLEN];
int prayedto = B_FALSE;
char colbuf[3];
enum PIETYLEV plev;
enum COLOUR col;
int piety,n;
god = godlf[i];
real_getlfname(god, godname, B_FALSE);
f = lfhasflag(god, F_GODOF);
if (f->val[0] == B_FEMALE) {
strcat(godname, " (Goddess of ");
} else {
strcat(godname, " (God of ");
}
strcat(godname, f->text);
strcat(godname, ")");
if (lfhasflag(god, F_PRAYEDTO)) {
prayedto = B_TRUE;
}
piety = getpiety(god->race->id);
plev = getpietylev(god->race->id, &col, happiness);
// TODO: construct piety buf [---+--|--------------------]
snprintf(pietybuf, BUFLEN, "^n[");
switch (col) {
case C_ORANGE: strcpy(colbuf, "^T"); break;
case C_RED: strcpy(colbuf, "^B"); break;
case C_YELLOW: strcpy(colbuf, "^w"); break;
case C_BROWN: strcpy(colbuf, "^b"); break;
case C_GREEN: strcpy(colbuf, "^g"); break;
case C_BOLDGREEN: strcpy(colbuf, "^G"); break;
case C_BOLDCYAN: strcpy(colbuf, "^E"); break;
default: case C_GREY: strcpy(colbuf, "^n"); break;
}
strcat(pietybuf, colbuf);
for (n = PIETY_MIN; n <= PIETY_MAX; n += 25) {
if ((piety >= n) && (piety < n+25)){
strcat(pietybuf, "+");
} else {
strcat(pietybuf, "-");
}
}
strcat(pietybuf, "^n]");
snprintf(line, BUFLEN, "%s%-26s%-9s%s %s%s",
prayedto ? "^g" : "^n",
godname,
prayedto ? " Yes " : " No ",
pietybuf, colbuf, happiness);
wmove(mainwin, y, 0);
textwithcol(mainwin, line);
y++;
}
}
// wait for key
centre(mainwin, C_WHITE, h-1, promptstr);
if (ch == '\0') {
ch = getch();
}
if (!strchr(cmdchars, ch)) {
if ((ch != 27) && (ch != '?')) {
ch = '\0';
}
}
switch (ch) {
case 27: // ESC
done = B_TRUE;
break;
case '@':
case 'a':
case 'e':
case 'g':
case 'm':
case 's':
case 'i':
mode = ch;
break;
case '?':
if (mode == 'g') { // help on gods
dohelp('g');
} else if (mode == 's') { // help on skills
dohelp('s');
} else if (mode == '@') { // help on current race
describerace(lf->race->id);
}
break;
default:
break;
}
} // end while !done
restoregamewindows();
/*
statdirty = B_TRUE;
needredraw = B_TRUE;
cls(); wrefresh(mainwin);
needredraw = B_TRUE;
drawscreen();
wrefresh(gamewin);
wrefresh(statwin);
real_clearmsg(B_TRUE);
*/
//redraw();
}
void textwithcol(WINDOW *win, char *buf) {
textwithcol_real(win, buf, B_TRUE);
}
void textwithcol_real(WINDOW *win, char *buf, int resetcolatend) {
char *p;
enum COLOUR col;
int done = B_FALSE;
col = C_NONE;
// print char by char, looking for colour codes
for (p = buf ; *p ; p++) {
while (*p == '^') {
// colour change
if (col != C_NONE) unsetcol(win, col);
p++;
if (!(*p)) {
done = B_TRUE;
break;
}
if (isdigit(*p)) { // direct enum COLOUR number
char numbuf[4];
char *np = numbuf;
while (isdigit(*p)) {
*np = *p;
p++;
np++;
}
*np = '\0';
col = (enum COLOUR) atoi(numbuf);
} else { // descriptive colour, ie 'W'arning
col = chartocol(*p);
p++;
}
if (col != C_NONE) setcol(win, col);
if (!(*p)) {
done = B_TRUE;
break;
}
}
if (done) break;
waddch(win, *p);
}
if (resetcolatend) {
// back to default colour
if (col != C_NONE) {
unsetcol(win, col);
}
}
}
void tombstone(lifeform_t *lf) {
char pname[BUFLEN];
char buf[BUFLEN];
char killer[BUFLEN];
int y;
int rank,minrank,maxrank;
char *p;
long playerscore;
playerscore = calcscore(lf);
getplayernamefull(pname);
// clear screen
cls();
y = 1;
centre(mainwin, C_GREY, y, "R.I.P."); y++;
//printf("%s\n",lf->name);
centre(mainwin, C_GREY, y, "%s (%ld points)",pname, playerscore); y++;
if (player->cell->map->region->rtype->id == RG_WORLDMAP) {
getregionname(buf, player->cell->map, B_TRUE);
centre(mainwin, C_GREY, y, "Died on %s.", buf); y++;
} else {
getregionname(buf, player->cell->map, B_FALSE);
centre(mainwin, C_GREY, y, "Died on level %d of %s.", player->cell->map->depth, buf); y++;
}
makekillertext(killer, lf->killverb, lf->lastdam, B_TRUE);
p = readuntil(buf, killer, '\n');
while (strlen(buf)) {
centre(mainwin, C_GREY, y, buf); y++;
p = readuntil(buf, p, '\n');
}
wrefresh(mainwin);
// write hiscores and calculate player's rank
writehiscore(player, &rank);
// wait for key...
getch();
cls();
y = 0;
if (rank == -1) {
mvwprintw(mainwin, y, 0, "Since you were cheating, your score will not be listed."); y++;
minrank = 1;
maxrank = 10;
} else if (rank > 100) {
mvwprintw(mainwin, y, 0, "You didn't make the top 100 list."); y++;
minrank = 1;
maxrank = 10;
} else {
setcol(mainwin, C_BOLDGREEN);
mvwprintw(mainwin, y, 0, "You made rank #%d on the high score table!", rank); y++;
unsetcol(mainwin, C_BOLDGREEN);
minrank = rank - 4;
maxrank = rank + 4;
limit(&minrank, 0, NA);
limit(&maxrank, NA, 100);
}
centre(mainwin, C_GREY, y, "High Scores"); y += 2;
wattron(mainwin, A_BOLD);
mvwprintw(mainwin, y, 0, HISCOREFORMAT, "Rank", "Score", "Name", "Job", "Method of death"); y++;
wmove(mainwin, y, 0);
wattroff(mainwin, A_BOLD);
showhiscores(player, minrank, maxrank);
getch();
// close down graphics ready to quit
// clear windows
delwin(gamewin);
delwin(statwin);
delwin(msgwin);
// clear screen
cls();
// close down curses
curs_set(1);
endwin();
}
//
// returns TRUE if you answered 'Yes' or you'd already accepted this warning
int warnabout(char *what) {
char ch = 'n';
warning_t *w;
// have we already warned about this?
w = findwarning(what);
if (w) {
w->lifetime = DEF_WARNINGTIME;
ch = 'y';
} else {
char ques[BUFLEN];
sprintf(ques, "%s", what);
ch = askchar(what, "yn", "n", B_TRUE, B_FALSE);
}
if (ch == 'y') {
addwarning(what);
return B_TRUE;
}
return B_FALSE;
}
// @ = tab
void wrapprint(WINDOW *win, int *y, int *x, char *format, ... ) {
char word[HUGEBUFLEN],buf[HUGEBUFLEN];
char *p;
va_list args;
int w,nspaces = 0;
int first = B_TRUE;
va_start(args, format);
vsnprintf( buf, HUGEBUFLEN, format, args );
va_end(args);
if (!strlen(buf)) return;
w = getmaxx(win);
// remember the amount of spaces at the end
p = buf + strlen(buf) - 1;
while (*p == ' ') {
nspaces++;
p--;
}
// add on spaces at the end
//strncat(buf, " ", HUGEBUFLEN);
// new code: print it word by word.
p = readuntil(word, buf, ' '); // get first word
//while (strlen(word)) {
while (strlen(p) || strlen(word)) {
char *repword;
int rv = B_TRUE;
repword = strdup(word);
while (rv) {
repword = strrep(repword, "@", " ", &rv);
}
// if this word won't fit, put it on the next line.
if (*x != 0) {
if (*x + strlen(repword) >= w) {
(*y)++;
*x = 0;
}
}
wmove(win, *y, *x);
if (first) {
first = B_FALSE;
} else if (*x != 0) {
textwithcol_real(win, " ", B_FALSE);
}
textwithcol_real(win, repword, B_FALSE);
//(*x) += strlen(buf);
getyx(win, *y, *x);
free(repword);
p = readuntil(word, p, ' '); // get next word
}
if (*x + nspaces >= w) {
// if we're at the end of the line, just go to the next one.
(*y)++;
*x = 0;
wmove(win, *y, *x);
} else {
int i;
// otherwise print the trailing spaces
for (i = 0;i < nspaces; i++) {
textwithcol_real(win, " ", B_FALSE);
}
}
// return colour to normal now
//wattroff(win, A_BOLD);
setcol(win, C_GREY);
getyx(win, *y, *x);
}