#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #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" int gfxready = B_FALSE; // has graphics system been initialised? WINDOW *mainwin; WINDOW *gamewin; WINDOW *msgwin; WINDOW *statwin; extern enum WINGAMETYPE wintype; 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 = 0; int escok = B_TRUE; extern int notime; extern int needredraw; extern int numdraws; extern int SCREENW, SCREENH; extern enum ERROR reason; extern char msghist[MAXHISTORY][BUFLEN]; extern int nmsghist; 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 option_t *firstoption,*lastoption; extern vault_t *firstvault; extern skill_t *firstskill; extern job_t *firstjob; extern enum GAMEMODE gamemode; extern long curtime; extern condset_t ccwalkable; 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; choice_t *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].hilite = B_FALSE; p->choice[p->nchoices].valid = B_TRUE; p->choice[p->nchoices].shortcutslot = -1; p->nchoices++; return &(p->choice[p->nchoices - 1]); } void killchoice(prompt_t *p, int idx) { int n; for (n = idx; n < p->nchoices-1; n++) { if (p->choice[n].text) free(p->choice[n].text); if (p->choice[n].desc) free(p->choice[n].desc); if (p->choice[n].longdesc) free(p->choice[n].longdesc); // shuffle other choices down p->choice[n].ch = p->choice[n+1].ch; if (p->choice[n+1].text) p->choice[n].text = strdup(p->choice[n+1].text); else p->choice[n].text = strdup(""); if (p->choice[n+1].desc) p->choice[n].desc = strdup(p->choice[n+1].desc); else p->choice[n].desc = strdup(""); if (p->choice[n+1].longdesc) p->choice[n].longdesc = strdup(p->choice[n+1].longdesc); else p->choice[n].longdesc = strdup(""); p->choice[n].data = p->choice[n+1].data; p->choice[n].heading = p->choice[n+1].heading; p->choice[n].hilite = p->choice[n+1].hilite; p->choice[n].valid = p->choice[n+1].valid; p->choice[n].shortcutslot = p->choice[n+1].shortcutslot; } 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); 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... if (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); 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 (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); 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; } // make all the passed cells 'flash' void animflashcells(cell_t **cell, int ncells, int ch,int colour, char *seetext) { glyph_t gl; int i; int nseen = 0; gl.ch = ch; gl.colour = colour; if (ncells == 0) return; // update screen updateviewfor(cell[0]); drawlevelfor(player); // hide cursor curs_set(0); for (i = 0; i <= ncells; i++) { if (haslos(player, cell[i])) { if (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); drawglyph(&gl, cell[i]->x - viewx, cell[i]->y - viewy); nseen++; } } if (nseen) { wrefresh(gamewin); usleep(DEF_ANIMDELAY); if (seetext) { msg(seetext); more(); } } // show cursor curs_set(1); needredraw = B_TRUE; drawscreen(); } 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 (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); 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); if (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); 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++) { if (colour == C_RANDOM) gl.colour = rnd(C_FIRST, C_LAST); 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[BIGBUFLEN]; 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; } cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail) { return real_askcoords(prompt, subprompt, targettype, srclf, 0, maxrange, loftype, wanttrail, NULL, 0); } cell_t *real_askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int minrange, int maxrange, enum LOFTYPE loftype, int wanttrail, cell_t **spectarg, int nspectargs) { 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_SPECIFIED) { int i; for (i = 0; i < nspectargs; i++) { target[i] = spectarg[i]; } ntargets = nspectargs; } else 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, getlfsize(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; ntargets++; } } } } } if ((curtarget == -1) && ntargets) { int closest = -1,i; // set to the closest one. //curtarget = ntargets; for (i = 0; i < ntargets; i++) { if (closest == -1) { closest = i; } else if (getcelldist(srclf->cell, target[i]) < getcelldist(srclf->cell, target[closest])) { closest = i; } } if (closest != -1) { curtarget = closest; } else { curtarget = 0; } } // 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; char groundbuf[BUFLEN],fullbuf[BIGBUFLEN]; 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; strcpy(groundbuf, c->type->name); addengineeringinfo(player, groundbuf, c); if (c->lf) { if (cansee(player, c->lf)) { flag_t *f; object_t *wep,*o; char extrainfo[BIGBUFLEN]; enum SKILLLEVEL lorelev; int height = 0; lorelev = getlorelevel(player, c->lf->race->raceclass->id); strcpy(extrainfo, ""); getlfnamea(c->lf, buf); if (lfhasflag(c->lf, F_NAME)) { // add on their job if (getjob(c->lf)) { strcat(buf, " the "); strcat(buf, getjobname(c->lf)); } } else if (c->lf->race->raceclass->id == RC_GOD) { f = lfhasflag(c->lf, F_GODOF); if (getgender(c->lf) == G_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 ((getlorelevel(player, getraceclass(c->lf)) >= PR_NOVICE) || getskill(player, SK_SPEECH)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "peaceful"); } break; case AL_HOSTILE: break; } // clone? if (ispetof(c->lf, player) && lfhasflag(c->lf, F_PHANTASM)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "phantasm"); } // obvious things if (isfleeing(c->lf)) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "fleeing"); } // can only be one of the below things 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, &height)) { double metres; metres = ((double)height) / 2; if (strlen(extrainfo)) strcat(extrainfo, ", "); if (lfhasflag(c->lf, F_FLYING)) { char fbuf[BUFLEN]; sprintf(fbuf, "flying:%0.2gm",metres); strcat(extrainfo, fbuf); } 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"); } } f = lfhasflag(c->lf, F_EATING); if (f) { char eatobname[BUFLEN]; object_t *eatob; int eatobid; eatobid = atol(f->text); eatob = findobbyid(c->lf->pack, eatobid); if (!eatob) { eatob = findobbyid(c->obpile, eatobid); } if (eatob) { real_getobname(eatob, eatobname, eatob->amt, B_PREMODS, B_NOCONDITION, B_BLINDADJUST, B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL); } else { strcpy(eatobname, ""); } if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "eating "); strcat(extrainfo, eatobname); } 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_NOPREMODS, B_NOCONDITION, B_BLINDADJUST, B_NOBLESSINGS, B_NOUSED, B_NOSHOWALL); if (strlen(extrainfo)) strcat(extrainfo, ", "); snprintf(buf2, BUFLEN, "stuck in %s",obname); strcat(extrainfo, buf2); } if ((getallegiance(c->lf) == AL_HOSTILE) && (lorelev >= 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, "extremely dangerous"); } if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, dangerbuf); } // hp if (!isplayer(c->lf)) { if (areallies(player, c->lf) || 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++) { char *loctext,obname[BUFLEN],dicetext[BUFLEN],*p; f = retflag[i]; if (strlen(extrainfo)) strcat(extrainfo, ", "); loctext = strdup(f->text); p = readuntil(dicetext, loctext, '^'); readuntil(obname, p, '^'); strcat(extrainfo, obname); free(loctext); } wep = getweapon(c->lf); if (wep && (c->lf->race->baseid != R_DANCINGWEAPON)) { object_t *secwep; char obname[BUFLEN]; char obname2[BUFLEN]; char buf2[BUFLEN]; int donesec = B_FALSE; getobname(wep, obname, wep->amt); secwep = getequippedob(c->lf->pack, BP_SECWEAPON); if (secwep) { getobname(secwep, obname2, secwep->amt); } else { strcpy(obname2, ""); } // two different weapons with the same name? if (secwep && (secwep != wep) && streq(obname, obname2)) { char *plur; //plur = makeplural(noprefix(obname)); plur = strdup(noprefix(obname)); makeplural(&plur); snprintf(buf2, BUFLEN, "weilding two %s",plur); free(plur); donesec = B_TRUE; } else { snprintf(buf2, BUFLEN, "weilding %s",obname); } if (strlen(extrainfo)) strcat(extrainfo, ", "); if (!donesec && secwep && (secwep != wep) ) { strcat(buf2, " and "); strcat(buf2, obname2); } 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]; strcpy(groundbuf, "(unseen)"); 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 if (streq(groundbuf, buf)) { strcpy(fullbuf, buf); } else { sprintf(fullbuf, "%s%s%s", groundbuf, strlen(buf) ? ", " : "", buf); } capitalise(fullbuf); if (srclf && (maxrange != UNLIMITED)) { if (getcelldist(srclf->cell, c) > maxrange) { inrange = B_FALSE; strcat(fullbuf, " ^R[too-far]^n"); valid = B_FALSE; } } trailtarg = c; if (loftype != LOF_DONTNEED) { cell_t *newcell; int bad = B_FALSE; if (srclf) { if (!haslofknown(srclf->cell, c, loftype, &newcell)) { bad = B_TRUE; } } else { if (!haslof(srclf->cell, c, loftype, &newcell)) { bad = B_TRUE; } } if (bad) { inlof = B_FALSE; strcat(fullbuf, " ^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(fullbuf, throwbuf); } } wclear(msgwin); if (subprompt) { char fullline[BIGBUFLEN]; wmove(msgwin, 0, 0); sprintf(fullline, "%s%s", subprompt, fullbuf); textwithcol(msgwin, fullline); } else { wmove(msgwin, 0, 0); textwithcol(msgwin, fullbuf); } 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, NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, SA_NONE, NULL, B_FALSE); while (o) { describeob(o); o = doaskobject(c->obpile, "Describe which object", NULL, NULL, B_TRUE, B_FALSE, B_FALSE, '\0', NULL, SA_NONE, NULL, B_FALSE); } 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; } // returns a direction char askdir(char *prompt, int maycancel, int usedrunk) { int dirch,dir = D_NONE; dirch = askchar(prompt, "yuhjklbn.-","-", B_FALSE, maycancel); if (dirch == '.') return D_MYSELF; dir = chartodir(dirch); // tipsy... if (usedrunk && willmoverandomly(player)) { int dir; dir = rnd(DC_N, DC_NW+1); if (dir == (DC_NW + 1)) { dir = D_MYSELF; } } return dir; } // 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)) { char backtext[BUFLEN]; if (lf->cell->map == newmap) { strcpy(backtext, "elsewhere "); } else if (newmap->lastplayervisit == -1) { // never been here before strcpy(backtext, ""); } else { strcpy(backtext, "back "); } if (newmap->region->rtype->id == BH_WORLDMAP) { if (lf->cell->map->region->rtype->id == BH_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_ANTNEST: msg("You find yourself %sin a giant ant's nest.", backtext); break; case H_CAVE: if ((newmap->depth == 1) && (newmap->lastplayervisit == -1)) { msg("You arrive at the goblin caves."); } else { msg("You arrive %sat level %d of the goblin caves.", backtext, newmap->depth); } break; case H_DUNGEON: msg("You arrive %sat dungeon level %d.", backtext, newmap->depth); break; case H_FOREST: if ((newmap->depth == 1) && (newmap->lastplayervisit == -1)) { msg("You arrive in the sylvan woods."); } else { msg("You arrive %sat level %d of the sylvan woods.", backtext, newmap->depth); } break; case H_HEAVEN: msg("You arrive in the Realm of the Gods!"); break; case H_MASTERVAULTS: if ((newmap->lastplayervisit == -1) && (newmap->depth == 1)) { msg("You have found the master vaults!"); } break; case H_SWAMP: msg("You arrive %sat a swamp.", backtext); 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; } } // show light level if different from previous level if ((newmap->illumination != IL_FULLLIT) && (newmap->illumination != lf->cell->map->illumination)) { msg("%s", getilluminationdesc(newmap->illumination)); } } } int announceflaggain(lifeform_t *lf, flag_t *f) { object_t *o; int donesomething = B_FALSE; lifeform_t *lf2; char lfname[BUFLEN]; char buf[BUFLEN]; char *buf2; char *p; char *loctext; char obname[BUFLEN],dicetext[BUFLEN]; poisontype_t *pt; if (player && isdead(player)) { return B_FALSE; } /// note: notime = maybe means we can still announce flag loss if (notime == B_TRUE) return B_FALSE; if (!lf->born && !isplayer(lf)) { return B_FALSE; } if (lf->race->baseid == R_DANCINGWEAPON) { return B_FALSE; } // stop announcement when we add f_awareness at the end of the game. if (lfhasflag(lf, F_WINNER)) { 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_AICONTROLLED: if (isplayer(lf)) { msg("^%cYou lose control of your body!", getlfcol(lf, CC_VBAD)); more(); donesomething = B_TRUE; } break; case F_ANTICIPATE: if (isplayer(lf)) { lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); msg("^%c%s%s intentions enter your mind!", getlfcol(lf, CC_GOOD), buf, getpossessive(buf)); donesomething = B_TRUE; } } break; case F_ARBOOST: if (isplayer(lf)) { msg("You feel %s!", (f->val[0] >= 0) ? "protected" : "vulnerable"); donesomething = B_TRUE; } break; 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_MINDSHIELD: if (isplayer(lf)) { msg("^gYour mind feels insulated.^n"); donesomething = B_TRUE; } break; case F_MISCASTCHANCE: if (isplayer(lf)) { msg("Your magical ability feels unreliable..."); 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 if (f->val[1] == ST_MEDITATING) { msg("%s enter%s a trance.",lfname, isplayer(lf) ? "" : "s"); } else { msg("^%c%s lose%s consciousness.^n",getlfcol(lf, CC_BAD), 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_AUTOTANGLE: if (isplayer(lf)) { msg("^%cSmall tendrils sprout from your %s.",getlfcol(lf, CC_GOOD), getbodypartname(lf, BP_HANDS)); } else { msg("^%cSmall tendrils sprout from %s%s %s.",getlfcol(lf, CC_GOOD), lfname, getpossessive(lfname), getbodypartname(lf, BP_HANDS)); } 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_BLOODBOIL: if (isplayer(lf)) { msg("A malignant red nimbus surrounds you."); } else if (cansee(player, lf)) { msg("A malignant red nimbus surrounds %s.", lfname); } 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; char spellname[BUFLEN],source[BUFLEN]; int forcepower; if (texttospellopts(f->text, "pw:", &forcepower, NULL)) { getspellname(ot->id, lf, spellname, forcepower); } else { getspellname(ot->id, lf, spellname, B_FALSE); } school = getspellschoolknown(lf, ot->id); getflagsourcetext(f,source); msg("^gYou have learned the %s '%s'%s.", (school == SS_MENTAL) ? "psionic power" : "spell", spellname, source); 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]; char spellname[BUFLEN],sourcetext[BUFLEN]; int forcepower; if (texttospellopts(f->text, "pw:", &forcepower, NULL)) { getspellname(ot->id, lf, spellname, forcepower); } else { getspellname(ot->id, lf, spellname, B_FALSE); } getflagsourcetext(f,sourcetext); snprintf(buf, BUFLEN, "^gYou have gained the ability '%s'%s.", spellname, sourcetext); msg(buf, ot->name); more(); donesomething = B_TRUE; } } break; case F_CHARMEDBY: lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); msg("^%c%s %s now under %s%s power!^n",getlfcol(lf, CC_BAD), 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_CONSUMESOULS: if (isplayer(lf)) { msg("^wYou hunger for the souls of the dead!"); donesomething = B_TRUE; } break; case F_DEAF: if (isplayer(lf)) { msg("^wYou cannot hear anything!"); } donesomething = B_TRUE; break; case F_DODGES: if (isplayer(lf)) { msg("You now automatically dodge fatal attacks."); } 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_FREEZINGTOUCH: if (isplayer(lf)) { // don't know if monsters get it msg("Your hands begin to glow blue!"); } else { msg("%s%s hands begin to glow blue!", lfname, getpossessive(lfname)); } donesomething = B_TRUE; break; case F_FULLSHIELD: o = hasobid(lf->pack, atol(f->text)); assert(o); getobname(o,obname,1); if (isplayer(lf)) { msg("You are now cowering behind your %s.", noprefix(obname)); donesomething = B_TRUE; } else { msg("%s starts cowering behind %s.", lfname, obname); donesomething = B_TRUE; } break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it msg("^%cYou are surrounded by a %s!", getlfcol(lf, CC_GOOD), f->text); donesomething = B_TRUE; } else { msg("^%c%s is surrounded by a %s!", getlfcol(lf, CC_GOOD), lfname, f->text); 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_HOTFEET: if (isplayer(lf)) { msg("Your %s feel like they are on fire!", getbodypartname(lf, BP_FEET)); donesomething = B_TRUE; } else { msg("%s%s %s are on fire!", lfname, getpossessive(lfname), getbodypartname(lf, BP_FEET)); donesomething = B_TRUE; } break; case F_ICESLIDE: msg("Sheets of ice start forming under %s%s %s!",lfname, getpossessive(lfname), getbodypartname(lf, BP_FEET)); 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; if (isplayer(lf)) more(); } 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)) { msg("^%cYou feel invulnerable!", getlfcol(lf, CC_VGOOD)); donesomething = B_TRUE; } else { msg("^%c%s looks invulnerable!", getlfcol(lf, CC_VGOOD), lfname); 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("^%c%s turn%s to flee from %s!", getlfcol(lf, CC_BAD), 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: pt = findpoisontype(f->val[0]); if (isplayer(lf)) { /* if ((pt->id == P_FOOD) || (pt->id == P_FOODBAD)) { msg("^%cYou are sick with %s.", getlfcol(lf, CC_VBAD), pt->name); } else { msg("^%cYou %s %s.", getlfcol(lf, CC_VBAD), pt->contracttext, pt->name); } */ msg("^%cYou %s %s.", getlfcol(lf, CC_VBAD), pt->contracttext, pt->name); more(); } else { msg("^%c%s looks 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: case F_WOUNDING: 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_FEARLESS: msg("^%c%s %s fearless!", getlfcol(lf, CC_GOOD), lfname, isplayer(lf) ? "feel" : "looks"); 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; if (isplayer(lf)) { real_warnabout(TEXT_WARN_FLY, PERMENANT, B_FALSE); } break; case F_FROZEN: // strip "frozen" out... buf2 = strdup(lfname); 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_HOLYTOUCH: msg("%s%s %s are surrounded by a holy aura!", lfname, getpossessive(lfname), hasbp(lf, BP_HANDS) ? getbodypartname(lf, BP_HANDS) : "limbs"); donesomething = B_TRUE; break; case F_LEARNBOOST: if (isplayer(lf)) { if (f->val[0] > 0) { msg("^gYou feel more receptive to new knowledge!"); } else { msg("^bYou feel less receptive to new knowledge!"); } donesomething = B_TRUE; } break; case F_LEVITATING: msg("%s begin%s to levitate in the air!",lfname, isplayer(lf) ? "" : "s"); if (isplayer(lf)) { real_warnabout(TEXT_WARN_FLY, PERMENANT, B_FALSE); } 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_MUTABLE: if (isplayer(lf)) { msg("^GYour body feels ready for mutation.^n"); real_warnabout(TEXT_WARN_MUTABLE, PERMENANT, B_FALSE); donesomething = B_TRUE; } break; case F_NAUSEATED: if (isplayer(lf)) { msg("^%cYou are nauseated by a disgusting stench!", getlfcol(lf, CC_BAD)); donesomething = B_TRUE; } else { msg("^%c%s looks nauseous.",getlfcol(lf, CC_BAD), 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_PLANTFRIEND: if (isplayer(lf)) { // don't know if monsters get it msg("^gYou feel a sudden affinity towards plantlife!"); donesomething = B_TRUE; } break; case F_POLYIMMUNE: if (isplayer(lf)) { // don't know if monsters get it msg("You feel very resistant to change."); donesomething = B_TRUE; } break; case F_PRODUCESLIGHT: msg("%s start%s producing light!", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; case F_PROTALIGN: msg("A sphere of %s force surrounds %s!", (f->val[1] == AL_GOOD) ? "demonic" : "holy", lfname); 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: loctext = strdup(f->text); p = readuntil(dicetext, loctext, '^'); readuntil(obname, p, '^'); msg("^%c%s rise%s from %s%s skin.", getlfcol(lf, CC_GOOD), noprefix(obname), (obname[strlen(obname)-1] == 's') ? "" : "s", lfname, getpossessive(lfname)); free(loctext); donesomething = B_TRUE; break; case F_REGENERATES: if (isplayer(lf)) { // don't know if monsters get it msg("^%cYour body's healing rate is enhanced!",getlfcol(lf, CC_GOOD)); 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, NA) ? "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_SHADOWED: if (isplayer(lf)) { msg("You are cloaked in shadows!"); } else { msg("%s is cloaked in shadows!", lfname); } donesomething = B_TRUE; break; case F_SILENCED: if (isplayer(lf)) { msg("^%cYou are surrounded in a field of silence!",getlfcol(lf, CC_BAD)); } else { msg("^%c%s is surrounded in a field of silence!", getlfcol(lf, CC_BAD), lfname); } 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_SOULLINK: if (isplayer(lf)) { // don't know if monsters get it lf2 = findlf(lf->cell->map, f->val[0]); if (lf2) { if (cansee(player, lf2)) { real_getlfname(lf2, buf, NULL, B_NOSHOWALL, B_REALRACE); } else { real_getlfnamea(lf2, buf, NULL, B_NOSHOWALL, B_REALRACE); } msg("^wA psychic bond forms between you and %s!", buf); } else { // shouldn't happen. msg("^wA psychic bond forms between you and something unknown."); } 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_SIXTHSENSE: if (isplayer(lf)) { // don't know if monsters get it msg("You will now be warned of creatures behind you."); donesomething = B_TRUE; } break; case F_SPRINTING: msg("%s %s sprinting!",lfname, isplayer(lf) ? "start" : "starts"); donesomething = B_TRUE; break; case F_STASIS: if (isplayer(lf)) { // don't know if monsters get it msg("Time within you warps and slows down!"); donesomething = B_TRUE; } break; case F_STAMBOOST: if (isplayer(lf)) { msg("^gYour stamina feels boosted!"); 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_STRIKETOKO: if (isplayer(lf)) { // don't know if monsters get it msg("Your attacks will now be non-lethal."); donesomething = B_TRUE; } break; case F_STUNNED: msg("%s %s stunned!",lfname, is(lf)); donesomething = B_TRUE; break; case F_TEMPMAGICBOOST: // don't know if monsters get it // also we only announce GAINING this flag, not losing it if (isplayer(lf)) { msg("Your magical power feels temporarily boosted!"); } 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_UNDEAD: if (isplayer(lf)) { msg("^%cAn evil taint spreads through your body!", getlfcol(lf, CC_GOOD)); donesomething = B_TRUE; } break; case F_WINDSHIELD: if (isplayer(lf)) { msg("^gYou are surrounded by a whirling cyclone of debris!"); } else if (cansee(player, lf)) { msg("%s is surrounded by a whirling cyclone of debris!",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; char *p; char *loctext; char obname[BUFLEN],dicetext[BUFLEN]; if (isdead(player)) { return B_FALSE; } /// note: notime = maybe means we can still announce flag loss if (notime == B_TRUE) return B_FALSE; if (!lf->born) { return B_FALSE; } if (lf->race->baseid == R_DANCINGWEAPON) { return B_FALSE; } // dont announce loss of flags you didnt know about if (!f->known) { 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_AICONTROLLED: if (isplayer(lf)) { msg("You have regained control of your body."); donesomething = B_TRUE; } break; case F_ANTICIPATE: if (isplayer(lf)) { lf2 = findlf(NULL, f->val[0]); if (lf2) { getlfname(lf2, buf); msg("^%cYou no longer know %s%s intentions.", getlfcol(lf, CC_BAD), buf, getpossessive(buf)); donesomething = B_TRUE; } } break; case F_ARBOOST: if (isplayer(lf)) { msg("You no longer feel so %s.", (f->val[0] >= 0) ? "protected" : "vulnerable"); donesomething = B_TRUE; } break; 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_MINDSHIELD: if (isplayer(lf)) { msg("Your mind no longer feels insulated."); donesomething = B_TRUE; } break; case F_MISCASTCHANCE: if (isplayer(lf)) { msg("Your magical ability no longer feels unreliable."); 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_AUTOTANGLE: if (isplayer(lf)) { msg("The tendrils vanish from your %s.",getlfcol(lf, CC_GOOD), getbodypartname(lf, BP_HANDS)); } else { msg("Tendrils vanish from %s%s %s.",lfname, getpossessive(lfname), getbodypartname(lf, BP_HANDS)); } 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: if (isplayer(lf)) { msg("%s can see again.",lfname); donesomething = B_TRUE; } break; case F_BLOODBOIL: if (isplayer(lf)) { msg("A calming blue nimbus surrounds you."); } else if (cansee(player, lf)) { msg("A calming blue nimbus surrounds %s.", lfname); } 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("^%c%s break%s free of %s%s control!^n",getlfcol(lf, CC_GOOD), 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_CONSUMESOULS: if (isplayer(lf)) { msg("Your hunger for souls has abated."); donesomething = B_TRUE; } break; case F_DEAF: if (isplayer(lf)) { msg("Your hearing returns."); } donesomething = B_TRUE; break; case F_DODGES: if (isplayer(lf)) { msg("You will no longer automatically dodge fatal attacks."); } 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: case F_WOUNDING: 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.", lfname, 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 is no longer serving you.", lfname); break; case F_POISONED: msg("^%c%s %s less sick now.^n", getlfcol(lf, CC_VGOOD), lfname, isplayer(lf) ? "feel" : "looks"); donesomething = B_TRUE; break; case F_FREEZINGTOUCH: if (isplayer(lf)) { msg("Your hands are no longer glowing blue."); } else { msg("%s%s hands are no longer glowing blue.", lfname, getpossessive(lfname)); } donesomething = B_TRUE; break; case F_FULLSHIELD: msg("%s %s no longer fully shielded.", lfname, isplayer(lf) ? "are" : "is"); donesomething = B_TRUE; break; case F_HEAVENARM: if (isplayer(lf)) { // don't know if monsters get it msg("^%cYour %s vanishes!", getlfcol(lf, CC_BAD), f->text); donesomething = B_TRUE; } else { char text[BIGBUFLEN]; sprintf(text,"%s%s %s vanishes!", lfname, getpossessive(lfname), f->text); capitalise(text); msg("^%c%s", getlfcol(lf, CC_BAD), text); 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_HOTFEET: if (isplayer(lf)) { msg("Your %s feel cooler now.", getbodypartname(lf, BP_FEET)); donesomething = B_TRUE; } else { msg("%s%s %s look cooler now", lfname, getpossessive(lfname), getbodypartname(lf, BP_FEET)); donesomething = B_TRUE; } break; case F_ICESLIDE: msg("%s%s feet are no 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 %s healed.", getlfcol(lf, CC_VGOOD), lfname, getpossessive(lfname), buf, isplural(buf) ? "have" : "has"); 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)) { msg("You no longer feel invulnerable."); donesomething = B_TRUE; } else { msg("%s no longer looks invulnerable.", lfname); 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_FEARLESS: msg("%s no longer %s fearless.", lfname, isplayer(lf) ? "feel" : "looks"); 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_HOLYTOUCH: msg("The holy aura vanishes from %s%s %s.", lfname, getpossessive(lfname), hasbp(lf, BP_HANDS) ? getbodypartname(lf, BP_HANDS) : "limbs"); donesomething = B_TRUE; break; case F_LEARNBOOST: if (isplayer(lf)) { if (f->val[0] > 0) { msg("You no longer feel receptive to new knowledge."); } else { msg("You no longer feel opposed 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_MUTABLE: if (isplayer(lf)) { msg("Your body is no longer receptive to mutation."); 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_PLANTFRIEND: if (isplayer(lf)) { // don't know if monsters lose it msg("You no longer feel an affinity towards plantlife."); donesomething = B_TRUE; } break; case F_POLYIMMUNE: if (isplayer(lf)) { // don't know if monsters lose it msg("You no longer feel resistant to change."); donesomething = B_TRUE; } break; case F_PRODUCESLIGHT: msg("%s %s no longer producing light.", lfname, is(lf)); donesomething = B_TRUE; break; case F_PROTALIGN: msg("%s%s sphere of %s force disappates.", lfname, getpossessive(lfname), (f->val[1] == AL_GOOD) ? "demonic" : "holy"); 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!", getlfcol(lf, CC_BAD), lfname); donesomething = B_TRUE; break; case F_RETALIATE: loctext = strdup(f->text); p = readuntil(dicetext, loctext, '^'); readuntil(obname, p, '^'); msg("%s disappear%s from %s%s skin.", noprefix(obname), (obname[strlen(obname)-1] == 's') ? "" : "s", lfname, getpossessive(lfname)); donesomething = B_TRUE; free(loctext); 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, NA)) { 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_SHADOWED: if (isplayer(lf)) { msg("The shadows around you disappate."); } else { msg("The shadows around %s disappate.", lfname); } donesomething = B_TRUE; break; case F_SILENCED: if (isplayer(lf)) { msg("You can now make noises again."); } else { msg("The field of silence around %s vanishes.", lfname); } 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_SIXTHSENSE: if (isplayer(lf)) { // don't know if monsters get it msg("You will no longer be warned of creatures behind you."); donesomething = B_TRUE; } break; case F_SOULLINK: if (isplayer(lf)) { // don't know if monsters get it msg("^wYour psychic soul-link vanishes."); donesomething = B_TRUE; } break; case F_SPIDERCLIMB: if (isplayer(lf)) { msg("Your skin is no longer 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_STASIS: if (isplayer(lf)) { msg("Time within you returns to normal."); donesomething = B_TRUE; } break; case F_STAMBOOST: if (isplayer(lf)) { msg("Your stamina no longer feels boosted."); donesomething = B_TRUE; } break; case F_STENCH: msg("%s no longer smell%s bad.",lfname, isplayer(lf) ? "" : "s" ); donesomething = B_TRUE; break; case F_STRIKETOKO: if (isplayer(lf)) { // don't know if monsters lose it msg("Your attacks will no longer be non-lethal."); 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_UNDEAD: if (isplayer(lf)) { msg("The evil taint leaves your body."); donesomething = B_TRUE; } 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) || (f->id == F_HOT)) { // don't want "the flaming sword catches on fire" wantpremods = B_FALSE; } real_getobname(o, obname, o->amt, wantpremods, B_NOPREMODS, B_CONDITION, B_BLESSINGS, B_NOUSED, B_NOSHOWALL); 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_ARMOURPIERCE: donesomething = B_TRUE; if (o->birthtime != curtime) msg("%s suddenly become%s razor-sharp!",prefix, OB1(o, "s", "")); break; 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; case F_HOT: // you only know an object is hot if you notice the effects on the // person wearing it. if (hasflag(o->flags, F_EQUIPPED)) { msg("%s glow%s red hot!", 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_PREMODS, B_NOCONDITION, B_BLINDADJUST, B_BLESSINGS, B_NOUSED, B_NOSHOWALL); 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_ARMOURPIERCE: if (o->birthtime != curtime) msg("%s %s no longer razor-sharp!",prefix, OB1(o, "is", "are")); break; case F_ONFIRE: // replace "the flaming xxx is no longer on fire" // with "the xxx is no longer on fire" temp = strdup(prefix); 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; } } void announcetime(int h, int m, int s, int showfull) { if (m <= 10) { enum TIMEPHASE tp; tp = gettimephase(); if (showfull == B_TRUE) { msg("It is now %02d:%02d (%s).", h, m, gettimephasename(tp)); switch (tp) { case TP_MORNING: if (getskill(player, SK_LORE_UNDEAD) >= PR_ADEPT) { real_warnabout("The undead will be less dangerous now.", 200, B_FALSE); } break; case TP_NIGHT: if (getskill(player, SK_LORE_UNDEAD) >= PR_ADEPT) { real_warnabout("The undead will be more dangerous!", 200, B_FALSE); } break; default: break; } } else { int modh; modh = h; if (modh == 0) { modh = 12; } else if (modh > 12) { modh -= 12; } msg("It is now %d o'clock.", modh); } } } void cantdrink(enum ERROR reason) { object_t *oo; char buf[BUFLEN]; switch (reason) { case E_INSUBSTANTIAL: msg("You need a physical body to do that!"); break; case E_UNDEAD: msg("You are undead and don't need to drink."); break; case E_VEGETARIAN: msg("The thought of consuming meat disgusts you."); break; case E_FACECOVERED: oo = facecovered(player); assert(oo); getobname(oo,buf, 1); msg("You can't drink through your %s!", noprefix(buf)); break; default: case E_WRONGOBTYPE: msg("You can't drink that!"); 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, int forpray) { lifeform_t *lf = NULL; int i; char *longdesc; longdesc = malloc(HUGEBUFLEN * sizeof(char)); initprompt(&prompt, prompttext); prompt.maycancel = B_TRUE; addpromptq(&prompt, "Describe which god?"); for (i = 0 ; i < ngodlfs; i++) { flag_t *f; choice_t *chc; char godof[BUFLEN],buf[BUFLEN]; lf = godlf[i]; if (!lf) continue; if (onlyprayed && !lfhasflag(lf, F_PRAYEDTO)) { continue; } if (forpray && godblocked(lf->race->id)) { continue; } real_getlfname(lf, buf, NULL, B_NOSHOWALL, B_REALRACE); f = hasflag(lf->flags, F_GODOF); snprintf(godof, BUFLEN, " (%s of %s)", (getgender(lf) == G_FEMALE) ? "goddess" : "god", f->text); if (godblocked(lf->race->id)) { strcat(godof, " [exiled]"); } else if (godprayedto(lf->race->id)) { strcat(godof, " [worshipped]"); } strcat(buf, godof); makedesc_god(lf, longdesc); chc = addchoice(&prompt, tolower(buf[0]), buf, NULL, lf, longdesc); if (godblocked(lf->race->id)) { chc->hilite = C_RED; } else if (godprayedto(lf->race->id)) { chc->hilite = C_GREEN; } } 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 { int done = B_FALSE; while (!done) { getchoice(&prompt); lf = (lifeform_t *)prompt.result; if (!lf) { break; } else if (prompt.whichq == 0) { break; } else { describegod(lf); } } } return lf; } object_t *askobject(obpile_t *op, char *prompt, char *noobtext, int *count, char action, condset_t *cs, int includenothing) { int showlong = B_TRUE; if (op->owner && isplayer(op->owner)) { showlong = B_FALSE; } return doaskobject(op, prompt, noobtext, count, showlong, B_TRUE, B_FALSE, action, NULL, SA_NONE, cs, includenothing); } 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, object_t *sellshop, enum SHOPACTION sellaction) { int lastclass = OC_NULL; int i; int useobletters = B_TRUE; flag_t *sellflag[MAXCANDIDATES]; int nsellflags = 0; if (sellshop) { // determine sell value from the shop getflags(sellshop->flags, sellflag, &nsellflags, F_SHOPACCEPTSFLAG, F_NONE); } 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 (sellshop) { int n,sellprice = 0; flag_t *curflag = NULL; char pricebuf[BUFLEN]; int markdownpct; for (n = 0; n < nsellflags; n++) { if (obmatchessellflag(mylist[i], sellflag[n], sellaction)) { curflag = sellflag[n]; break; } } // doaskobject should have already only populated mylist[] with valid objects for this store! assert(curflag); markdownpct = curflag->val[1]; // calculate sale price for 1 item if ((markdownpct != NA) && (markdownpct != 0)) { sellprice = applyshoppricemod( pctof(markdownpct, real_getobvalue(mylist[i], 1)), player, sellshop, SA_SELL); // append this. sprintf(pricebuf, " [$%d each]", sellprice); strcat(buf, pricebuf); } } strcpy(pointsbuf, ""); if (showpoints && (mylist[i]->type->id != OT_GOLD)) { long points; points = getobpoints(mylist[i]); if (points > 0) { snprintf(pointsbuf, BUFLEN, " [%ld point%s]", points, (points == 1) ? "" : "s"); } } 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_DARKYELLOW); wprintw(win, "%s", equipbuf); unsetcol(win, C_DARKYELLOW); } 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, char *noobtext, int *count, int showlong, int forpickup, int showpoints, char action, object_t *sellshop, enum SHOPACTION sellaction, condset_t *cs, int includenothing) { 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[BIGBUFLEN],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; flag_t *sellflag[MAXCANDIDATES]; int nsellflags = 0; if (sellshop) { getflags(sellshop->flags, sellflag, &nsellflags, F_SHOPACCEPTSFLAG, F_NONE); } 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; // can we include this object? ok = B_TRUE; if (!canseeob(player, o)) ok = B_FALSE; // shop flags? if (ok && nsellflags) { int n; // must match one of the sellflags ok = B_FALSE; for (n = 0; n < nsellflags; n++) { if (obmatchessellflag(o, sellflag[n], sellaction)) { ok = B_TRUE; break; } } } if (ok && cs) { ok = obmeets(o, cs); } 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; // no objects? if ((i == 0) && noobtext) { msg("%s", noobtext); return 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, sellshop, sellaction); } 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, includenothing ? "- for nothing, " : "", showlong ? "" : ",?=list", fullnumstring); wclear(msgwin); wrefresh(msgwin); 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) && (useobletters || (y < lastline)); i++) { if (useobletters) { if (mylist[i]->letter == ch) { o = mylist[i]; break; } } else { 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 == '-') && 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, condset_t *cs, int includenothing) { int c,i; object_t *mylist[MAXPILEOBS+1]; int selected[MAXPILEOBS+1]; int selcount[MAXPILEOBS+1]; char myletters[MAXPILEOBS+1]; char msghistbuf[BIGBUFLEN],numstring[BUFLEN]; char pbuf[BUFLEN]; char altprompt[BUFLEN]; int firstob = 0; int nextpage = -1; int lastline = SCREENH-4; int finished; int count = ALL; char nextlet = 'a'; int useobletters; int descmode = B_FALSE; objectclass_t *wantoc = NULL; clearretobs(); sprintf(altprompt, "Describe what"); 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 = obmeets(o, cs); } 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, NULL, SA_NONE); 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 += (getobweight(mylist[n]) * thiscount); } } // draw prompt if (nextpage != -1) { mvwprintw(mainwin, y, 0, MORESTRING); } if (descmode) { snprintf(pbuf, BUFLEN,"%s (?=sel/ESC=quit): ", altprompt); } else if (strlen(numstring) > 0) { snprintf(pbuf, BUFLEN,"%s (%s','=all, ?=desc/ESC=quit) [%s]: ", prompt, includenothing ? "- for nothing, " : "", numstring); } else { snprintf(pbuf, BUFLEN,"%s (%s?=desc/ESC=quit): ", prompt, 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) { if (descmode) { describeob(mylist[i]); } else { 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 == '-') && 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 select/describe if (descmode) descmode = B_FALSE; else descmode = 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; } int asktoclimb(object_t *o, char *promptformat) { char buf[BUFLEN]; char ch,question[BUFLEN],obname[BUFLEN]; cell_t *obcell; obcell = getoblocation(o); assert(strstr(promptformat, "%s")); // confirm... getobname(o, obname, o->amt); sprintf(question, promptformat, obname); ch = askchar(question, "yn","n", B_TRUE, B_FALSE); if (ch != 'y') { msg("Cancelled."); return B_TRUE; } snprintf(buf, BUFLEN, "the %s", noprefix(obname)); if (tryclimb(player, obcell, buf, B_ONPURPOSE)) { // failed return B_TRUE; } // success 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); } enum COMMAND chartocmd(char ch) { command_t *c; for (c = firstcommand ; c ; c = c->next) { if (c->ch == ch) return c->id; } return CMD_NONE; } 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) || noredraw) { 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; } char cmdtochar(enum COMMAND cmd) { command_t *c; for (c = firstcommand ; c ; c = c->next) { if (c->id == cmd) return c->ch; } return '\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, NULL, B_NOSHOWALL, B_REALRACE); snprintf(goddesc, BUFLEN, "(%s of %s)", (getgender(god) == G_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 describejob(enum JOB jid) { char *buf2; char buf[BUFLEN]; job_t *j; j = findjob(jid); cls(); // title snprintf(buf, BUFLEN, "%s",j->name); capitalise(buf); mvwprintw(mainwin, 0, 0, buf); wmove(mainwin, 2, 0); buf2 = malloc(HUGEBUFLEN * sizeof(char)); makedesc_job(j, 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 if (pileisinshop(o->pile)) { getobnametrue(o, buf,o->amt); } else { 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, 0, "%s", buf2); free(buf2); wrefresh(mainwin); // wait for key getch(); restoregamewindows(); } void describerace(enum RACE rid) { char buf[BUFLEN]; char *buf2; char ch; int x,y; race_t *r; cls(); r = findrace(rid); if (!r) return; // title if (gamemode == GM_GAMESTARTED) { enum SKILLLEVEL slev; slev = getlorelevel(player, r->raceclass->id); snprintf(buf, BUFLEN, "Race::%s (%s) - %s level lore",r->name, r->raceclass->name, getskilllevelname(slev)); } else { 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, B_FALSE); //textwithcol(mainwin, buf2); getyx(mainwin,y,x); ch = wrapprint(mainwin, &y, &x, 0, "%s", buf2); free(buf2); wrefresh(mainwin); // wait for key, unless we quit from the 'more' prompt if (ch != 27) { 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(int dir) { flag_t *f; cell_t *c; if (dir == D_NONE) { dir = askdir("Attack in which direction (- to cancel)", B_TRUE, B_TRUE); } if (dir == D_MYSELF) { c = player->cell; } else 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] = dir; } 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) { 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 { dir = askdir("Close door in which direction (- to cancel)", B_TRUE, B_FALSE); } if (dir == D_NONE) { msg("Cancelled."); return; } else { cell_t *c; c = getcellindir(player->cell, dir); if (c && haslos(player, c)) { failed = closedoorat(player, c); } } } */ void docommslf(lifeform_t *lf, char ch, lifeform_t *lf2, cell_t *targc) { char lfname[BUFLEN], lfname2[BUFLEN]; char buf[BUFLEN]; int count; int alignmod = 0; cell_t *c; flag_t *f; object_t *o, *givenob = NULL; object_t *godstone = NULL; int i; int askforob = B_FALSE; alignmod = getalignmod(lf); getlfname(lf, lfname); if (lf2) { getlfname(lf2, lfname2); } else { strcpy(lfname2, "?noone?"); } // process command switch (ch) { case 'a': if (lfhasflag(lf, F_RAGE) || ( (!ispetof(lf,player) && !canhear(lf, player->cell, SV_SHOUT, NULL)) ) ) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lf == lf2) { // won't attack itself if (cansee(player, lf)) 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[BIGBUFLEN]; getlfnamea(lf2, lfname2); snprintf(saybuf, BIGBUFLEN, "I can't see %s!", lfname2); say(lf, saybuf, SV_TALK); } } break; case 'c': if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } // find adjacent cell c = getrandomadjcell(player->cell, &ccwalkable, B_ALLOWEXPAND); if (c) { aigoto(lf, c, MR_OTHER, NULL, DEF_AIFOLLOWTIME); } break; case 'o': // donate // giving godstone to a god? if (godstone) { o = godstone; count = 1; askforob = B_FALSE; } else if ( (getskill(player, SK_SPEECH) >= PR_ADEPT) || (getlorelevel(player, lf->race->raceclass->id) >= PR_BEGINNER)) { object_t *oo; char ch; count = 1; // ask what to give, but only include items they want. snprintf(buf, BUFLEN, "What will you offer to %s?",lfname); initprompt(&prompt, buf); for (oo = player->pack->first ; oo ; oo = oo->next) { char ooname[BUFLEN]; char why[BUFLEN]; getobname(oo, ooname, oo->amt); if (getoboffermod(oo,lf, why) > 0) { snprintf(buf, BUFLEN, "%s (%s)", ooname, why); addchoice(&prompt, oo->letter, buf, NULL, oo, NULL); } } addchoice(&prompt, '/', "(something else)", NULL, NULL, NULL); addchoice(&prompt, '-', "(nothing)", NULL, NULL, NULL); ch = getchoice(&prompt); if (ch == '-') { o = NULL; askforob = B_FALSE; } else if (ch == '/') { askforob = B_TRUE; } else { o = (object_t *)prompt.result; askforob = B_FALSE; } } else { askforob = B_TRUE; } if (askforob) { // ask what to give snprintf(buf, BUFLEN, "What will you offer to %s?",lfname); o = askobject(player->pack, buf, NULL, &count, '\0', NULL, B_FALSE); } 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(countbuf); if (!count) { msg("Cancelled."); return; } getobname(o, buf, count); givemoney(player, lf, count); msg("You give %s to %s.", buf, lfname); } else if (isgod(lf) && (o->type->obclass->id == OC_GODSTONE)) { getobname(o, buf, o->amt); msg("You offer %s to %s.", buf, lfname); givenob = o; } else { givenob = moveob(o, lf->pack, count); if (givenob) { getobname(givenob, buf, givenob->amt); // successful - announce msg("You give %s to %s.", buf, lfname); } } } else { msg("Cancelled."); return; } if (givenob) { int wasgold = B_FALSE; if (givenob->type->id == OT_GOLD) wasgold = B_TRUE; if ((lf->race->id == R_BEGGAR) && wasgold) { // begger effects if (!countmoney(lf->pack)) { i = rnd(1,100); if (i <= 5) { // attack you sayphrase(lf, SP_BEGATTACK, SV_SHOUT, NA, NULL, player); 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, player); // 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, player); } } else { // they already had some money sayphrase(lf, SP_BEGTHANKS, SV_TALK, NA, NULL, player); } pleasegodmaybe(R_GODPURITY, 10); pleasegodmaybe(R_GODMERCY, 20); } else if (isgod(lf) && (givenob->type->obclass->id == OC_GODSTONE)) { // in heaven? if (lf->cell->map->habitat->id == H_HEAVEN) { flag_t *gf; gf = lfhasflag(lf, F_GODOF); // you win! addflag(player->flags, F_WINNER, WT_DEMIGOD, lf->race->id, NA, gf->text); wingame(); } else { say(lf, "Not here, mortal! Come to the Realm of the Gods.", SV_SHOUT); } } else { // not giving money to a begger enum ATTRBRACKET iqb; int mod = 0; int wanted = B_FALSE, covetted = B_FALSE; iqb = getattrbracket(getattr(lf, A_IQ), A_IQ, NULL); mod = getoboffermod(givenob,lf, NULL); wanted = aiwants(lf, givenob, &covetted); // only get speech bonus if humanoid (ie they can understand you) if (!cantalk(lf)) { // this will counteract the bonus given in skillcheck() mod -= (getskill(player, SK_SPEECH)*10); } // chance of calming hostile intelligent, monsters if ((getallegiance(lf) == AL_HOSTILE) && (iqb >= IQ_ANIMAL) && cansee(lf, player)) { if (skillcheckvs(player, SC_SPEECH, mod, lf, SC_SPEECH, 0)) { // if humanoid+intelligent, say thanks. if (cantalk(lf)) sayphrase(lf, SP_THANKS, SV_TALK, NA, NULL, player); // calm down makepeaceful(lf, player); // chance of becoming a pet if you gave something other than // money if (!wasgold) { f = lfhasflag(lf, F_TAMABLE); if (f && skillcheck(lf, SC_SPEECH, f->val[0], mod + alignmod)) { petify(lf, player); if (cantalk(lf)) { char *p = NULL; if (lf->race->raceclass->id == RC_HUMANOID) { p = assignnpcname(lf->flags); } sayphrase(lf, SP_RECRUIT_ACCEPT, SV_TALK, NA, p, player); } } pleasegodmaybe(R_GODTHIEVES, 10); } } } else if (wanted) { // if they WEREN'T hostile and liked the offer int min = 70,max = 90; if (covetted) { min = 50; max = 70; } // reset rejected information offers killflagsofid(lf->flags, F_NOINFO); killflagsofid(lf->flags, F_NOHIRE); f = lfhasflag(lf, F_INFOPRICE); if (f) { int newval; // reduce asking price newval = pctof(rnd(min,max),f->val[0]); limit(&newval, 1, NA); f->val[0] = newval; } f = lfhasflag(lf, F_HIREPRICE); if (f) { int newval; // reduce asking price newval = pctof(rnd(min,max),f->val[0]); limit(&newval, 1, NA); f->val[0] = newval; } // if humanoid+intelligent, say thanks. if (cantalk(lf)) sayphrase(lf, SP_THANKS, SV_TALK, NA, NULL, player); } } // yumi always likes giving things away, as long as // don't keep any for yourself. if (count == givenob->amt) { pleasegodmaybe(R_GODMERCY, 2); } } // end if givenob break; case 'g': // stop attacking all current targets first... killflagsofid(lf->flags, F_TARGETLF); if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } aigoto(lf, targc, MR_OTHER, NULL, DEF_AIFOLLOWTIME); break; case 'i': if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (askforinfo(lf, 2)) { genareaknowledge(lf->flags, 0); docomms_areainfo(lfname, lf->flags, lf); } break; case 'j': // charisma check to see if they'll join you. if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } recruit(lf); break; case 'k': // trade Knowledge if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } tradeknowledge(lf); break; case 'm': // mercy if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (islowhp(player) && cantalk(lf) && canhear(lf, player->cell, SV_SHOUT, NULL) && (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) && !isundead(lf)) { if (skillcheck(player, SC_SPEECH, 150, alignmod)) { // passed! sayphrase(lf, SP_MERCYACCEPT, SV_TALK, NA, player->race->name, player); // 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': if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } f = isresting(lf); if (f) { stopresting(lf); } else { if (needstorest(lf, NULL)) { enum ERROR why; if (safetorest(lf, &why) || (why == E_TOOSOON)) { 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': if (lfhasflag(lf, F_PHANTASM) || lfhasflag(lf, F_SUMMONEDBY)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } // 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 'x': if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (askforinfo(lf, 4)) { genareaknowledge(lf->flags, 0); docomms_areadangers(lfname, lf->flags, lf); } break; case 'y': noise(player->cell, player, NC_OTHER, 3, "someone shouting!", NULL); break; case '<': if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } setfollowdistance(lf, 1, 3); break; case '>': if (lfhasflag(lf, F_RAGE) || !canhear(lf, player->cell, SV_SHOUT, NULL)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } if (lfhasflag(lf, F_PHANTASM)) { if (cansee(player, lf)) msg("%s doesn't respond.", lfname); break; } setfollowdistance(lf, 3, 5); break; } } void docommsmulti(void) { lifeform_t *ally[MAX_MAPW*MAX_MAPH],*l,*lfarg; cell_t *cellarg,*origc = NULL; int nallies = 0,i; char buf[BUFLEN],ch; snprintf(buf, BUFLEN, "What will you command your allies to do?"); initprompt(&prompt, buf); prompt.maycancel = B_TRUE; // find all allies on the map who can hear the player for (l = player->cell->map->lf ; l ; l = l->next) { if ((l != player) && (getallegiance(l) == AL_FRIENDLY)) { ally[nallies] = l; nallies++; // add options to say to this person makecommslist(&prompt, l, B_TRUE); } } // ask what to say to them all ch = getchoice(&prompt); if ((ch == 'n') || (ch == '\0')) { msg("Cancelled."); return; } if (getcommsopts(ch, "Allies", &lfarg, &cellarg)) { msg("Cancelled."); return; } announcecomms(ch, "your allies", lfarg, cellarg); origc = cellarg; for (i = 0; i < nallies; i++) { docommslf(ally[i], ch, lfarg, cellarg); if (ch == 'g') { // pick a new cell cellarg = getrandomadjcell(cellarg, &ccwalkable, B_ALLOWEXPAND); if (!cellarg) cellarg = origc; } } taketime(player, getactspeed(player)); } void announcecomms(char ch, char *talkto, lifeform_t *lfarg, cell_t *cellarg) { char lfname2[BUFLEN]; if (lfarg) { getlfname(lfarg, lfname2); } switch (ch) { case 'a': msg("You say \"Attack %s!\" to %s.",isplayer(lfarg) ? "me" : lfname2, talkto); break; case 'c': msg("You say \"Come here!\" to %s.",talkto); break; case 'g': msg("You say \"Go over there!\" to %s.", talkto); break; case 'i': msg("You say \"What can you tell me about this area?\" to %s.", talkto); break; case 'j': msg("You say \"Join me on my quest!\" to %s.", talkto); break; case 'k': // trade Knowledge msg("You say \"Care to trade knowledge?\" to %s.", talkto); break; case 'm': // mercy msg("You say \"Have mercy!\" to %s.", talkto); break; case 'r': msg("You say \"Get some rest.\" to %s.", talkto); break; case 'x': msg("You say \"Any dangers nearby that I should look out for?\" to %s.", talkto); break; case 'y': msg("You shout at %s!", talkto); break; case '<': msg("You say \"Stay close!\" to %s.", talkto); break; case '>': msg("You say \"Keep your distance!\" to %s.", talkto); break; default: break; } } void docomms(lifeform_t *lf) { cell_t *where = NULL; char buf[BUFLEN],lfname[BUFLEN]; char ch; lifeform_t *lfarg; cell_t *cellarg; if (lfhasflag(player, F_SILENCED)) { msg("You are unable to make a sound!"); return; } //int moneyowing = 0; 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; makecommslist(&prompt, lf, B_FALSE); ch = getchoice(&prompt); if ((ch == 'n') || (ch == '\0')) { msg("Cancelled."); return; } if (getcommsopts(ch, lfname, &lfarg, &cellarg)) { msg("Cancelled."); return; } announcecomms(ch, lfname, lfarg, cellarg); docommslf(lf, ch, lfarg, cellarg); taketime(player, getactspeed(player)); } // return true on error int getcommsopts(char ch, char *talkto, lifeform_t **retlf, cell_t **retcell) { cell_t *c; char buf[BUFLEN],buf2[BUFLEN]; *retlf = NULL; *retcell = NULL; // get other options for comms... switch (ch) { case 'a': // who to attack? snprintf(buf, BUFLEN, "Tell %s to attack who?",talkto); snprintf(buf2, BUFLEN, "%s->Attack->",talkto); c = askcoords(buf, buf2, TT_MONSTER, player, UNLIMITED, LOF_DONTNEED, B_FALSE); if (c && c->lf) { *retlf = c->lf; } else { return B_TRUE; } break; case 'g': // go where? snprintf(buf, BUFLEN, "Tell %s to go where?",talkto); snprintf(buf2, BUFLEN, "%s->Goto->",talkto); *retcell = askcoords(buf, buf2, TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE); if (! (*retcell)) { return B_TRUE; } break; } return B_FALSE; } // lf is the person (if any) who you are talking to void docomms_areainfo(char *who, flagpile_t *fp, lifeform_t *lf) { int x,y,ndone; object_t *o; cell_t *c; flag_t *f,*knowflag; knowflag = hasflag(fp, F_KNOWSABOUT); if (!knowflag) { // should never happen msg("\"I don't know anything about that!\""); return; } f = hasflag(fp, F_HOMEMAP); if (f) { // (make the assumption that the player is on the // same map as the person they are talking to!) if (f->val[0] != player->cell->map->id) { msg("\"I'm not familiar with this area.\""); return; } } // shops if (strchr(knowflag->text, 's')) { ndone = 0; 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 (hasobwithflag(c->obpile, F_SHOP)) { setcellknownradius(c, PR_BEGINNER, 3, DT_ORTH); ndone++; } } } if (ndone) { needredraw = B_TRUE; msg("\"There are some shops nearby...\""); more(); } } // veryrare objects if (strchr(knowflag->text, 'o')) { ndone = 0; 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); for (o = c->obpile->first ; o ; o = o->next) { if (hasflag(o->flags, F_SHOP)) continue; // shops were already handled f = hasflag(o->type->flags, F_RARITY); if (f && (f->val[2] == RR_VERYRARE)) { msg("\"I hear there is a rare %s nearby...\"", o->type->name); more(); setcellknown(c, PR_MASTER); ndone++; } } } } if (ndone) needredraw = B_TRUE; } // staircases if (strchr(knowflag->text, 'e')) { ndone = 0; 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 (hasobwithflag(c->obpile, F_CLIMBABLE)) { setcellknownradius(c, PR_BEGINNER, 3, DT_ORTH); ndone++; } } } if (ndone) { needredraw = B_TRUE; msg("\"I can show you the ways out of this level...\""); more(); } } msg("\"That's all I know about this area.\""); } // lf is the person (if any) who you are talking to void docomms_areadangers(char *who, flagpile_t *fp, lifeform_t *lf) { int ndone = 0; int totdone = 0; int x,y,min,max; cell_t *c; flag_t *f,*knowflag; object_t *o; knowflag = hasflag(fp, F_KNOWSABOUT); if (!knowflag) { // should never happen msg("\"I don't know anything about that!\""); return; } f = hasflag(fp, F_HOMEMAP); if (f) { // (make the assumption that the player is on the // same map as the person they are talking to!) if (f->val[0] != player->cell->map->id) { msg("\"I'm not familiar with this area.\""); return; } } // traps or trapped objects if (strchr(knowflag->text, 't')) { ndone = 0; 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); for (o = c->obpile->first ; o ; o = o->next) { if (killflagsofid(o->flags, F_TRAP)) { setcellknown(c, PR_MASTER); ndone++; } else { f = hasflag(o->flags, F_TRAPPED); if (f && (f->val[2] != B_TRUE)) { f->val[2] = B_TRUE; setcellknown(c, PR_MASTER); ndone++; } } } } } if (ndone) { needredraw = B_TRUE; msg("\"There are hidden traps nearby...\""); more(); } totdone += ndone; } // veryrare monsters if (strchr(knowflag->text, 'm')) { gettrrange(getmapdifficulty(player->cell->map), &min,&max, RARITYVARIANCELF, B_FALSE); ndone = 0; 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->lf && !isplayer(c->lf) && (c->lf != lf) && areenemies(c->lf, player)) { int showit = B_FALSE; enum RARITY rr; getracerarity(H_ALL, c->lf->race->id, &rr); if (rr == RR_VERYRARE) { showit = B_TRUE; } else { // out of depth monsters? int hd; hd = gettrrace(c->lf->race); if (hd > max) { showit = B_TRUE; } } if (showit) { char lfname[BUFLEN]; char *p; char text[BIGBUFLEN]; real_getlfnamea(c->lf, lfname, NULL, B_SHOWALL, B_REALRACE); if (lfhasflag(c->lf, F_NAME)) { switch(rnd(1,2)) { case 1: snprintf(text, BIGBUFLEN, "\"%s is living nearby...\"", lfname); break; case 2: snprintf(text, BIGBUFLEN, "\"%s dwells nearby...\"", lfname); break; } } else { switch(rnd(1,4)) { case 1: snprintf(text, BIGBUFLEN, "\"There is %s living nearby...\"", lfname); break; case 2: snprintf(text, BIGBUFLEN, "\"%s dwells nearby...\"", lfname); break; case 3: snprintf(text, BIGBUFLEN, "\"%s has made its lair here...\"", lfname); break; case 4: snprintf(text, BIGBUFLEN, "\"I spotted %s nearby...\"", lfname); break; } } capitalise(text); p = strdup(text); strrep(&p, "NAME", lfname, NULL); msg("%s",p); more(); free(p); ndone++; } } } } totdone += ndone; } msg("\"I know of no %sdangers in this area.\"", (totdone) ? "other " : ""); } void docountmoney(lifeform_t *lf) { int goldamt = 0,gemamt = 0,credit = 0; int unknowncredit = 0; char goldbuf[BUFLEN], gembuf[BUFLEN],creditbuf[BUFLEN]; object_t *o; goldamt = countmoney(lf->pack); for (o = lf->pack->first ; o ; o = o->next) { if (hasflag(o->flags, F_GEM)) { gemamt += getobvalue(o); } else if (o->type->id == OT_CREDITCARD) { if (isidentified(o)) { credit += getcharges(o); } else { unknowncredit++; } } } if (gemamt) { snprintf(gembuf, BUFLEN, ", $%d worth of gemstones", gemamt); } else { strcpy(gembuf, ""); } if (credit) { if (unknowncredit) { snprintf(creditbuf, BUFLEN, " and at least $%d credit", credit); } else { snprintf(creditbuf, BUFLEN, " and $%d credit", credit); } } else if (unknowncredit) { if (unknowncredit == 1) { snprintf(creditbuf, BUFLEN, " and a stolen credit card"); } else { snprintf(creditbuf, BUFLEN, " and %d stolen credit cards", unknowncredit); } } else { strcpy(creditbuf, ""); } if (goldamt == 0) { sprintf(goldbuf, "no money"); } else { sprintf(goldbuf, "$%d", goldamt); } msg("You have %s%s%s.", goldbuf, gembuf, creditbuf); } 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, NULL, B_FALSE); } else { o = askobject(op, buf, NULL, &count, '\0', NULL, B_FALSE); 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]; if (isdeadob(o)) continue; 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) { condset_t cs; if (!hasedibleob(player->pack)) { msg("You have nothing to eat!"); return; } initcondv(&cs, CC_EDIBLE, B_TRUE, NA, CC_NONE); eatob = askobject(op, "Eat what", "You have nothing to eat!", NULL, 'e', &cs, B_FALSE); } if (eatob) { if (isunknownbadobject(eatob) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) { if (!confirm_badfeeling(eatob)) { msg("Cancelled."); return; } } eat(player, eatob); } } int dowear(obpile_t *op) { object_t *o; int rv = B_FALSE; condset_t cs; initcondv(&cs, CC_WEARABLE, B_TRUE, NA, CC_NONE); o = askobject(op, "Wear what", "You have nothing to wear!", NULL, '\0', &cs, B_FALSE); if (o) { if (isunknownbadobject(o) && skillcheck(player, SC_WIS, D_BADFEELING, 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; condset_t cs; // include _anything_ which could be weilded, even if not neccesarily a weapon. initcondv(&cs, CC_WEILDABLE, B_TRUE, NA, CC_NONE); o = askobject(op, "Weild what", "You have nothing to weild.", &count, 'w', &cs, B_TRUE); if (o) { if (isunknownbadobject(o) && skillcheck(player, SC_WIS, D_BADFEELING, 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%s","???", k->hiddenname, k->triedon ? "," : ")"); if (k->triedon) { y++; mvwprintw(mainwin, y, 0, " %-25s tried on %s)"," ", k->triedon); } } 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; // first search for any non-trail objects. for (o = where->obpile->first ; o ; o = o->next) { if (!canseeob(player, o)) continue; if (hasflag(o->flags, F_COSMETIC) && !onpurpose) 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; break; } } // now go through eech object... 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) && !onpurpose) continue; if (hasflag(o->flags, F_TRAIL)) { if (!includetrails) continue; // ignore it if we're have 'show trails' turned off if (!onpurpose && !getoption(OPT_ALWAYSSHOWTRAILS)) continue; //if (!onpurpose) 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 && onpurpose) { // just clear the message buffer //clearmsg(); if (isblind(player)) { msg("There does not seem to be anything here."); } else { msg("There is nothing here."); } } } void lfstatheading(char *headstr, int offset) { char buf[BUFLEN]; snprintf(buf, BUFLEN, "%s%s", headstr, offset ? " (continued)" : ""); wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, 0, "SKILLS"); wattroff(mainwin, A_UNDERLINE); } char *makedesc_god(lifeform_t *god, char *retbuf) { char thisline[BIGBUFLEN]; char godname[BUFLEN]; flag_t *f, *retflag[MAXCANDIDATES]; int nretflags,i; f = hasflag(god->flags, F_GODOF); real_getlfname(god, godname, NULL, B_SHOWALL, B_REALRACE); strcpy(retbuf, ""); // title snprintf(thisline, BIGBUFLEN, "%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); snprintf(thisline, BIGBUFLEN, "%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); if (hasflag(god->flags, F_GODBATTLE)) { snprintf(thisline, BIGBUFLEN, "During battle, %s will respond to prayers by ", godname); getflags(god->flags, retflag, &nretflags, F_GODBATTLE, 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); } } } else { snprintf(thisline, BIGBUFLEN, "During battle, %s will not respond to prayers", godname); } strcat(thisline, ".\n\n"); strncat(retbuf, thisline, HUGEBUFLEN); if (hasflag(god->flags, F_GODNOBATTLE)) { snprintf(thisline, BIGBUFLEN, "Outside of battle, %s will respond to prayers by ", godname); getflags(god->flags, retflag, &nretflags, F_GODNOBATTLE, 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); } } } else { snprintf(thisline, BIGBUFLEN, "Outside of battle, %s will not respond to prayers", godname); } strcat(thisline, ".\n\n"); strncat(retbuf, thisline, HUGEBUFLEN); // note: we manually handle SACRIFICEOBWITHFLAG getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_SACRIFICEOBCLASS, F_SACRIFICEOBBLESSED, F_SACRIFICEOBWITHFLAG,F_NONE); if (nretflags == 0) { snprintf(thisline, BIGBUFLEN, "%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; char name[BUFLEN]; oc = findoc(retflag[i]->val[0]); if (oc->id == OC_MONEY) { sprintf(name, "money ($100 or more preferred)."); } else { sprintf(name, "all %s", oc->name); } snprintf(thisline, BIGBUFLEN, "%s accepts the sacrifice of %s.\n",godname, name); strncat(retbuf, thisline, HUGEBUFLEN); } getflags(god->flags, retflag, &nretflags, F_SACRIFICEOB, F_NONE); for (i = 0; i < nretflags; i++) { if (i == 0) { snprintf(thisline, BIGBUFLEN, "%s accepts the sacrifice of:\n", godname); strncat(retbuf, thisline, HUGEBUFLEN); } if (retflag[i]->val[1] == NA) { objecttype_t *ot; char *text; ot = findot(retflag[i]->val[0]); text = strdup(ot->name); makeplural(&text); snprintf(thisline, BIGBUFLEN, "- %s", text); free(text); if ((god->race->id == R_GODPURITY) && (retflag[i]->val[0] == OT_CORPSE)){ strcat(thisline, " of evil creatures"); } strcat(thisline, "\n"); strncat(retbuf, thisline, HUGEBUFLEN); } else { raceclass_t *rc; rc = findraceclass(retflag[i]->val[1]); snprintf(thisline, BIGBUFLEN, "- %s corpses\n", rc->name); strncat(retbuf, thisline, HUGEBUFLEN); } } getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBBLESSED, F_NONE); for (i = 0; i < nretflags; i++) { if (i == 0) { snprintf(thisline, BIGBUFLEN, "%s accepts the sacrifice of:\n", godname); strncat(retbuf, thisline, HUGEBUFLEN); } switch (retflag[i]->val[0]) { case B_BLESSED: snprintf(thisline, BIGBUFLEN, "- known blessed objects\n"); break; case B_CURSED: snprintf(thisline, BIGBUFLEN, "- known cursed objects\n"); break; default: snprintf(thisline, BIGBUFLEN, "- known uncursed objects\n"); break; } strncat(retbuf, thisline, HUGEBUFLEN); } getflags(god->flags, retflag, &nretflags, F_SACRIFICEOBWITHFLAG, F_NONE); for (i = 0; i < nretflags; i++) { if (i == 0) { snprintf(thisline, BIGBUFLEN, "%s accepts the sacrifice of:\n", godname); strncat(retbuf, thisline, HUGEBUFLEN); } strcpy(thisline, ""); switch (retflag[i]->val[0]) { case F_BATTLESPOILS: snprintf(thisline, BIGBUFLEN, "- untouched battle spoils\n"); break; case F_FLAMMABLE: snprintf(thisline, BIGBUFLEN, "- flammable objects\n"); break; case F_GEM: snprintf(thisline, BIGBUFLEN, "- gems\n"); break; default: break; } if (strlen(thisline)) { strncat(retbuf, thisline, HUGEBUFLEN); } } if (hasflag(god->flags, F_SACRIFICEOBMAGIC)) { snprintf(thisline, BIGBUFLEN, "%s accepts the sacrifice of all magical objects.\n",godname); strncat(retbuf, thisline, HUGEBUFLEN); } } return retbuf; } char *makedesc_job(job_t *j, char *retbuf) { char thisline[BIGBUFLEN]; skill_t *sk; enum ATTRIB a; int count = 0; flag_t *f; // start with job description strcpy(retbuf, j->desc); strcat(retbuf, "\n\n"); strcat(retbuf, "STARTING ATTRIBUTES\n"); f = hasflag(j->flags, F_ALIGNMENT); if (f) { if (f->val[0] == AL_NONE) { int count = 0; char *p; char choices[BUFLEN]; strcpy(choices, ""); for ( p = f->text; *p; p++) { if (strlen(choices)) strcat(choices, "/"); switch (*p) { case 'g': strcat(choices, "Good"); count++; break; case 'n': strcat(choices, "Neutral"); count++; break; case 'e': strcat(choices, "Evil"); count++; break; } } if (count == 3) { snprintf(thisline, BIGBUFLEN, "Alignment:Any"); } else { snprintf(thisline, BIGBUFLEN, "Alignment:%s", choices); } } else { char *p; p = strdup(getalignmentname(f->val[0])); capitalise(p); snprintf(thisline, BIGBUFLEN, "Alignment:%s",p); free(p); } } else { snprintf(thisline, BIGBUFLEN, "Alignment:Any"); } strcat(thisline, " "); if (hasflag(j->flags, F_JOBATTRMOD)) { for (a = 0; a < MAXATTS; a++) { char buf[BUFLEN]; f = hasflagval(j->flags, F_JOBATTRMOD, a, NA, NA, NULL); if (f && (f->val[1] != 0)) { char buf2[BIGBUFLEN]; if (f->val[1] > 0) { sprintf(buf, "^%d+%d^n", C_GREEN, f->val[1]); } else if (f->val[1] < 0) { sprintf(buf, "^%d%d^n", C_RED, f->val[1]); } snprintf(buf2, BIGBUFLEN, "%s:%s ", getattrabbrev(a), buf); strcat(thisline, buf2); } } } strncat(retbuf, thisline, HUGEBUFLEN); strncat(retbuf, "\n\n", HUGEBUFLEN); // skills // max skillname length: 21 (sorcery:translocation) // use blocks of 26 // NAME:Nvc NAME:Beg NAME:Adp // NAME:Beg // NAME:Adp // NAME:Skl // NAME:Exp // NAME:Mas // -21- // == 3 per line // == need 17 lines strcat(retbuf, "STARTING SKILLS\n"); count = 0; strcpy(thisline, ""); for (sk = firstskill ; sk ; sk = sk->next) { char *lev = NULL; enum SKILLLEVEL slev = PR_INEPT; f = hasflagval(j->flags, F_STARTSKILL, sk->id, NA, NA, NULL); if (f) { slev = f->val[1]; lev = getskilllevelabbr(slev); /* switch (slev) { case PR_INEPT: strcpy(lev, "---"); break; case PR_NOVICE: strcpy(lev, "Nov"); break; case PR_BEGINNER: strcpy(lev, "Beg"); break; case PR_ADEPT: strcpy(lev, "Adp"); break; case PR_SKILLED: strcpy(lev, "Skl"); break; case PR_EXPERT: strcpy(lev, "Exp"); break; case PR_MASTER: strcpy(lev, "Mst"); break; } */ } if (lev) { char *p; char buf[BUFLEN]; //char bufpad[BUFLEN]; count++; sprintf(buf, "%13s:^%d%s^n ",sk->shortname, getskilllevelcolour(slev), lev); //sprintf(buf, "%19s:^%d%3s^n ",sk->name, getskilllevelcolour(slev), lev); //sprintf(bufpad, "%18s",buf); // strip trailing spaces p = buf + strlen(buf) - 2; // ie. last char while (*p == ' ') { *p = '\0'; p--; } strcat(thisline, buf); if (count == 4) { count = 0; // should use getmaxx(win) here instead... //assert(strlen_without_colours(thisline) < 78); // print it. strcat(thisline, "\n"); strcat(retbuf, thisline); strcpy(thisline, ""); } } // end if strlen(lev) } // end foreach skill // print out any remaining lines if (count != 0) { strcat(thisline, "\n"); strcat(retbuf, thisline); strcpy(thisline, ""); } return retbuf; } char *makedesc_ob(object_t *o, char *retbuf) { char buf[HUGEBUFLEN]; 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; char *loctext,*p; char retalname[BUFLEN],dicetext[BUFLEN]; // 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 = getouterequippedob(player, 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 = getobmass(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(getobweight(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 = getobmass(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); if (o->type->obclass->id != OC_EFFECT) { 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; flag_t *ff; 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); ff = hasflag(o->flags, F_DECAY); if (ff && (ff->val[2] >= 1)) { // 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,*twohandf; twohandf = hasflag(o->flags, F_TWOHANDED); sprintf(buf, "It is a %s firearm.\n", twohandf ? "two-handed" : "single handed"); strncat(retbuf, buf, HUGEBUFLEN); if (twohandf && (twohandf->val[0] > 0) && (twohandf->val[0] < SZ_ENORMOUS)) { char sizebuf[BUFLEN]; sprintf(sizebuf, "%s", getsizetext(twohandf->val[0] + 1)); capitalise(sizebuf); snprintf(buf2, BUFLEN, "@%s creatures can weild it in one hand.\n", sizebuf); strncat(retbuf, buf2, HUGEBUFLEN); } f = hasflag(o->flags, F_ACCURACY); if (f) { int acc,accnum; acc = getobaccuracy(o, NULL, B_FALSE); 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,*twohandf; float stamcost = STAMTOATTACK; int delay; int critchance; twohandf = hasflag(o->flags, F_TWOHANDED); snprintf(buf, BUFLEN, "%s %s weapon", (o->type->obclass->id == OC_WEAPON) ? "It is a" : "It can be used as a", twohandf ? "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); if (twohandf && (twohandf->val[0] > 0) && (twohandf->val[0] < SZ_ENORMOUS)) { char sizebuf[BUFLEN]; sprintf(sizebuf, "%s", getsizetext(twohandf->val[0] + 1)); capitalise(sizebuf); snprintf(buf2, BUFLEN, "@%s creatures can weild it in one hand.\n", sizebuf); strcat(buf, buf2 ); } snprintf(buf2, BUFLEN, "@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_HOT); if (f) { sprintf(buf,"@It also inflicts %s extra burning damage.\n", strlen(f->text) ? f->text : "1-2"); 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); } if (chargesknown(o)) { getflags(o->flags, retflag, &nretflags, F_EXTRADAMWITHCHARGES, F_NONE); for (i = 0 ; i < nretflags; i++) { f = retflag[i]; sprintf(buf,"@It also inflicts %s extra %s damage while charged%s.\n", f->text, getdamname(f->val[0]), (f->val[2] == IFACTIVE) ? " and activated" : ""); strncat(retbuf, buf, HUGEBUFLEN); } } getflags(o->flags, retflag, &nretflags, F_EXTRADAM, F_NONE); for (i = 0 ; i < nretflags; i++) { f = retflag[i]; if (f->val[2] == NA) { sprintf(buf,"@It also inflicts %s extra %s damage.\n", f->text, getdamname(f->val[0])); } else { sprintf(buf,"@It also inflicts %d extra %s damage.\n", f->val[2], getdamname(f->val[0])); } 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); } } else { strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } f = hasflag(o->flags, F_ACCURACY); if (f) { int acc,accnum; acc = getobaccuracy(o, NULL, B_FALSE); 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, B_FALSE); 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); } } stamcost = getattackstamloss(o); snprintf(buf2, BUFLEN, ", and Stamina cost is %0.2f",stamcost); strcat(buf, buf2); if (compareob) { float cstamcost,diff; cstamcost = getattackstamloss(compareob); diff = stamcost - cstamcost; if (diff == 0) { strcat(buf, " (=)"); } else { // lower stamina loss is better snprintf(buf2, BUFLEN, " %s(%c%0.1f)^n", (diff > 0) ? "^B" : "^g", (diff > 0) ? '+' : '-', fabs(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 can be 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) ) { char hpbuf[BUFLEN]; f = hasflag(o->flags, F_OBHP); if (isdamaged(o)) { snprintf(buf, BUFLEN, "It has been damaged."); } else if (hasflag(o->flags, F_RUSTED)) { // technically not 'perfect' snprintf(buf, BUFLEN, "It is undamaged."); } else { snprintf(buf, BUFLEN, "It is in perfect condition."); } if (obhpknown(o)) { // show exact hp numbers 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)) { // show percentage 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, hpbuf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } f = hasflag(o->flags, F_ARMOURSIZE); if (f) { char sizetext[BUFLEN]; switch (f->val[0]) { case SZ_MINI: snprintf(sizetext, BUFLEN, "miniature"); break; case SZ_TINY: snprintf(sizetext, BUFLEN, "tiny"); break; case SZ_SMALL: snprintf(sizetext, BUFLEN, "small"); break; case SZ_MEDIUM: snprintf(sizetext, BUFLEN, "medium"); break; case SZ_HUMAN: snprintf(sizetext, BUFLEN, "human"); break; case SZ_LARGE: snprintf(sizetext, BUFLEN, "large"); break; case SZ_HUGE: snprintf(sizetext, BUFLEN, "huge"); break; case SZ_ENORMOUS: snprintf(sizetext, BUFLEN, "enormous"); break; default: snprintf(sizetext, BUFLEN, "irregular"); // should never happen 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); } 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); } getflags(o->flags, retflag, &nretflags, F_HELPSREPAIR, F_NONE); for (i = 0; i < nretflags; i++) { material_t *m; m = findmaterial(retflag[i]->val[0]); sprintf(buf, "It provides a +%d bonus whenrepairing %s objects.", retflag[i]->val[1], m->name); 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->flags, F_INVULNERABLE) && !hasflag(o->flags, F_DAMAGABLE)) { strncat(retbuf, "It is invulnerable to most damage.\n", HUGEBUFLEN); } else if (hasflag(o->flags, F_IMMUTABLE)) { strncat(retbuf, "Powerful magic has made its current condition permenant.\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 // charges remaining //if ((o->type->obclass->id == OC_WAND) || (o->type->id == OT_BATTERY)) { if (!hasflag(o->flags, F_DONTSHOWCHARGES)) { 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); } } else if ((o->type->obclass->id == OC_WAND) || hasflag(o->flags, F_CHARGES)) { if (isidentified(o) || chargesknown(o)) { int charges; charges = getcharges(o); if (charges) { sprintf(buf, "It has %d charge%s left.\n",charges, (charges == 1) ? "" : "s"); } else { sprintf(buf, "It has no charges left.\n"); } strncat(retbuf, buf, HUGEBUFLEN); } } } // 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); } f = hasflagknown(o->flags, F_HOT); if (f) { sprintf(buf, "It is extremely hot.\n"); strncat(retbuf, buf, HUGEBUFLEN); } i = obproduceslight(o); if (i > 0) { sprintf(buf, "It is producing light (%d metre%s).\n", i, (i == 1) ? "" : "s"); strncat(retbuf, buf, HUGEBUFLEN); } f = hasflag(o->flags, F_RUSTED); if (f) { char rustbuf[BUFLEN]; switch (f->val[0]) { case R_TRUSTY: strcpy(rustbuf, "thouroughly rusty"); break; case R_VRUSTY: strcpy(rustbuf, "very rusty"); break; case R_RUSTY: default: strcpy(rustbuf, "rusty"); break; } if (isweapon(o)) { sprintf(buf, "It is %s (-%d%% damage).\n", rustbuf, 100 - getrustdampct(o)); } else { sprintf(buf, "It is %s (no damage resistance).\n", rustbuf); } 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); } f = hasflag(o->flags, F_OPERABLE); if (f) { flag_t *f2; f2 = hasflag(o->flags, F_OPERNEEDSKILL); if (f2) { sprintf(buf, "It requires %s %s skill to operate.\n", getskilllevelname(f2->val[1]), getskillname(f2->val[0])); } else { sprintf(buf, "It can be operated.\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_ARMOURIGNORE); if (f && f->known) { sprintf(buf, "Armour will not reduce %s damage at all.\n",OB1(o,"its","their")); strncat(retbuf, buf, HUGEBUFLEN); } f = hasflag(o->flags, F_ARMOURPIERCE); if (f && f->known) { if (f->val[0] < 0) { sprintf(buf, "Armour will not reduce %s damage at all.\n",OB1(o,"its","their")); } else { sprintf(buf, "Armour will not reduce %s damage below %d.\n",OB1(o,"its","their"), f->val[0]); } 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 && f->known) { 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) { snprintf(buf2, BUFLEN, "^B%s lowers your accuracy by %d. (Armour skill penalty)^n\n", buf, getaccuracymodnum(amt)); strncat(retbuf, buf2, HUGEBUFLEN); } if (amt2 > 0) { snprintf(buf2, BUFLEN, "^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) { snprintf(buf2, BUFLEN, "^B%s lowers your attack accuracy by %d. (Shields skill too low)^n\n", buf, getaccuracymodnum(amt)); strncat(retbuf, buf2, HUGEBUFLEN); } if (amt2 > 0) { snprintf(buf2, BUFLEN, "^B%s lowers your evasion by %d. (Shields skill penalty)^n\n", buf, amt2); strncat(retbuf, buf2, HUGEBUFLEN); } break; case F_ANONYMOUS: snprintf(buf2, BUFLEN, "%s obscures your identity.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_ARBOOST: snprintf(buf2, BUFLEN, "%s %s your Armour Rating.\n", buf, (f->val[0] >= 0) ? "increases" : "decreases"); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_ATTRMOD: snprintf(buf2, BUFLEN, "%s %s your %s.\n", buf, (f->val[2] > 0) ? "increases" : "decreases", getattrname(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_ATTRSET: snprintf(buf2, BUFLEN, "%s modifies your %s.\n", buf, getattrname(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_AWARENESS: snprintf(buf2, BUFLEN, "%s grants you heightened awareness.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_BLIND: snprintf(buf2, BUFLEN, "%s prevents you from seeing anything.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_BREATHWATER: snprintf(buf2, BUFLEN, "%s allows you to breath normally while underwater.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_CONTROL: snprintf(buf2, BUFLEN, "%s lets you control teleportation and polymorphic effects.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_CONSUMESOULS: snprintf(buf2, BUFLEN, "%s allows you to consume the souls of nearby dead.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DEAF: snprintf(buf2, BUFLEN, "%s prevents you from hearing anything.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTLIFE: snprintf(buf2, BUFLEN, "%s lets you detect nearby lifeforms.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTOBS: snprintf(buf2, BUFLEN, "%s lets you detect nearby objects.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTMAGIC: snprintf(buf2, BUFLEN, "%s will detect magical enchantments on objects.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DETECTMETAL: snprintf(buf2, BUFLEN, "%s will detect nearby metal.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DODGES: snprintf(buf2, BUFLEN, "%s lets you use remaining stamina to dodge fatal attacks.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_ENHANCESEARCH: snprintf(buf2, BUFLEN, "%s enhances your searching ability.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_ENHANCESMELL: snprintf(buf2, BUFLEN, "%s enhances your sense of smell.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DISEASEIMMUNE: snprintf(buf2, BUFLEN, "%s makes you immune to disease.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DTIMMUNE: snprintf(buf2, BUFLEN, "%s makes you immune to %s.\n", buf, getdamnamenoun(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DTRESIST: snprintf(buf2, BUFLEN, "%s makes you resistant to %s.\n", buf, getdamnamenoun(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DTVULN: snprintf(buf2, BUFLEN, "%s renders you vulnerable to %s.\n", buf, getdamnamenoun(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_DRUNK: snprintf(buf2, BUFLEN, "%s makes you tipsy.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_EXTRAINFO: snprintf(buf2, BUFLEN, "%s provides enhanced knowledge to you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_EXTRADAM: snprintf(buf2, BUFLEN, "%s will cause you to deal additional %s damage on each attack.\n", buf, getdamname(f->val[0])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_WOUNDING: snprintf(buf2, BUFLEN, "%s will grant +%d extra damage on all attacks.\n", buf, f->val[0]); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_EXTRALUCK: snprintf(buf2, BUFLEN, "%s will give you a bonus to all skill checks.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_EXTRAMP: snprintf(buf2, BUFLEN, "%s will increase your mana pool by %d%%.\n", buf, f->val[0]); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FEARLESS: snprintf(buf2, BUFLEN, "%s will reder you fearless.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FASTACT: snprintf(buf2, BUFLEN, "%s will speed up your actions.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FASTMETAB: snprintf(buf2, BUFLEN, "%s will increase your metabolic rate.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FASTMOVE: snprintf(buf2, BUFLEN, "%s will speed up your movement.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FLYING: snprintf(buf2, BUFLEN, "%s will allow you to fly.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FREEZINGTOUCH: snprintf(buf2, BUFLEN, "%s will cause objects you touch to turn to ice.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_FROZEN: snprintf(buf2, BUFLEN, "%s turns you to ice.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_GRAVBOOSTED: snprintf(buf2, BUFLEN, "%s increases gravity around you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_GRAVLESSENED: snprintf(buf2, BUFLEN, "%s decreases gravity around you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_HOTFEET: snprintf(buf2, BUFLEN, "%s causes your feet to constantly burn.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_INVISIBLE: snprintf(buf2, BUFLEN, "%s renders you invisible to normal sight.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_INVULNERABLE: snprintf(buf2, BUFLEN, "%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); snprintf(buf2, BUFLEN, "%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: snprintf(buf2, BUFLEN, "%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); snprintf(buf2, BUFLEN, "%s allows you to cast '%s'.\n", buf, sname); strncat(retbuf, buf2, HUGEBUFLEN); } break; case F_DAYBOOST: if (f->val[0] > 0) { snprintf(buf2, BUFLEN, "%s grants a +%d accuracy bonus during daytime.\n", buf,getaccuracymodnum(f->val[0])); } else { snprintf(buf2, BUFLEN, "%s imposes a -%d accuracy penalty during daytime.\n", buf, getaccuracymodnum(abs(f->val[0]))); } break; case F_DETECTAURAS: snprintf(buf2, BUFLEN, "%s allows you to detect blessings or curses.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_HOLYAURA: snprintf(buf2, BUFLEN, "%s surrounds you with a holy aura.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_LEARNBOOST: snprintf(buf2, BUFLEN, "%s grants a bonus to earned experience points.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_LEVITATING: snprintf(buf2, BUFLEN, "%s causes you to levitate.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MAGICBOOST: snprintf(buf2, BUFLEN, "%s boosts the power of your spells by %d.\n", buf, f->val[1]); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MINDSHIELD: snprintf(buf2, BUFLEN, "%s protects you from psionic attacks.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MISCASTCHANCE: snprintf(buf2, BUFLEN, "%s causes your spells to become unreliable.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MEDITATES: snprintf(buf2, BUFLEN, "%s allows you to retain awareness while resting.", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MAGSHIELD: snprintf(buf2, BUFLEN, "%s surrounds you with a magnetic shield.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_MUTABLE: snprintf(buf2, BUFLEN, "%s allows your body to mutate.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_NAUSEATED: snprintf(buf2, BUFLEN, "%s causes you to feel nauseated.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_NIGHTBOOST: if (f->val[0] > 0) { snprintf(buf2, BUFLEN, "%s grants a +%d accuracy bonus at night.\n", buf,getaccuracymodnum(f->val[0])); } else { snprintf(buf2, BUFLEN, "%s imposes a -%d accuracy penalty at night.\n", buf, getaccuracymodnum(abs(f->val[0]))); } break; case F_NONCORPOREAL: snprintf(buf2, BUFLEN, "%s makes you non-corporeal.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_PAIN: snprintf(buf2, BUFLEN, "%s causes you intense pain.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_PARALYZED: snprintf(buf2, BUFLEN, "%s paralyzes you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_PHOTOMEM: snprintf(buf2, BUFLEN, "%s prevents you from forgetting your surroundings.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_POLYIMMUNE: snprintf(buf2, BUFLEN, "%s prevents you from being polymorphed.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SIXTHSENSE: snprintf(buf2, BUFLEN, "%s warns you about nearby enemies.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_STABILITY: snprintf(buf2, BUFLEN, "%s prevents you from slipping over.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_STAMBOOST: snprintf(buf2, BUFLEN, "%s boosts your stamina by %d.\n", buf, f->val[1]); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_STENCH: snprintf(buf2, BUFLEN, "%s makes you smell bad.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_PRODUCESLIGHT: snprintf(buf2, BUFLEN, "%s produces light out to %d metre%s.\n", buf, f->val[1], (f->val[1] == 1) ? "" : "s"); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_RETALIATE: loctext = strdup(f->text); p = readuntil(dicetext, loctext, '^'); readuntil(retalname, p, '^'); snprintf(buf2, BUFLEN, "%s protects you with %s.\n", buf, retalname); strncat(retbuf, buf2, HUGEBUFLEN); free(loctext); break; case F_PROTALIGN: snprintf(buf2, BUFLEN, "%s repels attacks from %s aligned creatures.\n", buf, getalignmentname(f->val[1])); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_RAGE: snprintf(buf2, BUFLEN, "%s makes you enraged.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_REFLECTION: snprintf(buf2, BUFLEN, "%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"); } snprintf(buf2, BUFLEN, "%s allows you to regenerate health%s.\n", buf,buf3); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_RESISTMAG: snprintf(buf2, BUFLEN, "%s grants you %s immunity to magic.\n", buf, (f->val[0] >= 10) ? "strong" : "minor"); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_RISEASGHOST: snprintf(buf2, BUFLEN, "%s cause you to rise as a ghost after death.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SEEINVIS: snprintf(buf2, BUFLEN, "%s allows you to see invisible things.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SEEINDARK: snprintf(buf2, BUFLEN, "%s allows you to see in the dark.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SHADOWED: snprintf(buf2, BUFLEN, "%s prevents distant creatures from seeing you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SILENCED: snprintf(buf2, BUFLEN, "%s prevents you from making sounds.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SILENTMOVE: snprintf(buf2, BUFLEN, "%s allows you to move silently.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SLOWACT: snprintf(buf2, BUFLEN, "%s will slow down your actions.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SLOWMETAB: snprintf(buf2, BUFLEN, "%s will decrease your metabolic rate.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SLOWMOVE: snprintf(buf2, BUFLEN, "%s will slow down your movement.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_SPIDERCLIMB: snprintf(buf2, BUFLEN, "%s allows you to adhere to walls.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_TREMORSENSE: snprintf(buf2, BUFLEN, "%s allows you to 'see' by sensing vibrations around you.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_TRUESTRIKE: snprintf(buf2, BUFLEN, "%s makes your attacks automatically hit.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_WINDSHIELD: snprintf(buf2, BUFLEN, "%s will surround you with a cyclonic shield.\n", buf); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_VISRANGEMOD: snprintf(buf2, BUFLEN, "%s %s your vision range by %d metre%s.\n", buf, (f->val[1] > 0) ? "increases" : "decreases", abs(f->val[1]), (abs(f->val[1]) == 1) ? "" : "s" ); strncat(retbuf, buf2, HUGEBUFLEN); break; case F_XRAYVIS: snprintf(buf2, BUFLEN, "%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; } if (f->val[1] != NA) { sprintf(buf, "^%dMinimum %s to use%s: %d", col, getattrname(f->val[0]), strlen(f->text) ? " effectively" : "", f->val[1]); } if (f->val[2] != NA) { char addon[BUFLEN]; if (f->val[1] == NA) { sprintf(addon, "It gains a bonus at at %d %s.\n", f->val[2], getattrname(f->val[0])); } else { sprintf(addon, " (bonus at %d)^n.\n", f->val[2]); } strcat(buf,addon); } else { strcat(buf, "\n"); } strncat(retbuf, buf, HUGEBUFLEN); if (usable && isweapon(o)) { if (pctmod > 0) { char howmuch[BUFLEN]; if ((f->val[0] == A_AGI) && (pctmod < 5)) { sprintf(howmuch, "fractionally"); } else { sprintf(howmuch, "by %d%s", (f->val[0] == A_AGI) ? getaccuracynum(100 + pctmod) : pctmod, (f->val[0] == A_AGI) ? "" : "%"); } sprintf(buf, "^%dYour high %s will increase your %s with this weapon %s.^n\n", C_GREEN, getattrname(f->val[0]), (f->val[0] == A_AGI) ? "accuracy" : "damage", howmuch); strncat(retbuf, buf, HUGEBUFLEN); } else if (pctmod < 0) { char howmuch[BUFLEN]; if ((f->val[0] == A_AGI) && (pctmod > -5)) { sprintf(howmuch, "fractionally"); } else { sprintf(howmuch, "by %d%s", (f->val[0] == A_AGI) ? getaccuracynum(100 + abs(pctmod)) : abs(pctmod), (f->val[0] == A_AGI) ? "" : "%"); } sprintf(buf, "^%dYour low %s will decrease your %s with this weapon %s.^n\n", C_DARKYELLOW, getattrname(f->val[0]), (f->val[0] == A_AGI) ? "accuracy" : "damage", howmuch); 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) || (o->type->id == OT_GRIMOIRE)) { if (!isknown(o)) { showcontents = B_FALSE; } } if (hasflag(o->flags, F_CONTAINER)) { // only show contents of containers if you are holding them // and you have previously opened it. if (!hasflag(o->flags, F_BEENOPENED) || (o->pile->owner == player)) { showcontents = B_FALSE; } } if (showcontents) { if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { 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]; // don't show spells from schools we don't know if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { if (getspellschoolknown(player, oo->type->id) == SS_NONE) { continue; } } getobname(oo, contentname, oo->amt); sprintf(buf, " - %s", contentname); if ((o->type->id == OT_SPELLBOOK) || (o->type->id == OT_GRIMOIRE)) { char lbuf[BUFLEN]; sprintf(lbuf, " (Lv %d %s)%s", getspelllevel(oo->type->id), getschoolname(getspellschool(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, int forplayersel) { race_t *r; char buf[HUGEBUFLEN]; flag_t *retflag[MAXCANDIDATES],*f; int nretflags,i; flagpile_t *doneflags; enum SKILLLEVEL lorelev; r = findrace(rid); if (forplayersel) { lorelev = PR_MASTER; } else { lorelev = getlorelevel(player, r->raceclass->id); } // TODO: add this to doco. // Your Lore skill for this race will determine how much information is shown. // // NOVICE: // common knowledge // eg: whether it breathes water, can fly, etc. // skills // BEGINNER: // spells/powers // knowledge known by studying this creature a little. // eg: sleeping times, damage resist/vuln, silentmovement, morale // ADEPT: // nearly everything. except.... // SKILLED: // what their blood bottles to. doneflags = addflagpile(NULL, NULL); strcpy(retbuf, ""); if (showextra) { int a,n; int curidx,donesomething; char bonheading[BUFLEN],penheading[BUFLEN],mischeading[BUFLEN]; int donemischeading = B_FALSE; enum OBCLASS spellorabil[2]; sprintf(bonheading, "^%dStrengths^n:\n", C_WHITE); sprintf(penheading, "^%dWeaknesses^n:\n", C_WHITE); sprintf(mischeading, "^%dOther^n:\n", C_WHITE); // stats snprintf(buf, HUGEBUFLEN, "HD: %-3d ", gettrrace(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_LIGHTBLUE; 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) { if ((f->val[1] == B_TRUE) && forplayersel) { } else { snprintf(buf, HUGEBUFLEN, "@- %s\n", f->text); strncat(retbuf, buf, HUGEBUFLEN); } donesomething = B_TRUE; curidx++; break; } } } } // abilities? if (lorelev >= PR_BEGINNER) { spellorabil[0] = OC_ABILITY; spellorabil[1] = OC_SPELL; getflags(r->flags, retflag, &nretflags, F_CANWILL, F_NONE); for (n = 0; n <= 1; n++) { int nfound = 0; strcpy(buf, ""); for (i = 0; i < nretflags; i++) { objecttype_t *ot; int power = 1; f = retflag[i]; ot = findot(f->val[0]); if (ot && (ot->obclass->id == spellorabil[n])) { char templine[BUFLEN]; if (nfound == 0) { sprintf(templine, "Innate %s: %s", (spellorabil[n] == OC_ABILITY) ? "Ability" : "Spell", ot->name); strcat(buf, templine); } else { sprintf(templine, ", %s", ot->name); strcat(buf, templine); } texttospellopts(f->text, "pw:", &power, NULL); if (power) { strcat(buf, " (power "); strcat(buf, roman(power)); strcat(buf, ")"); } nfound++; } } if (strlen(buf)) { strncat(retbuf, "@- ", HUGEBUFLEN); strcat(buf, "\n"); strncat(retbuf, buf, HUGEBUFLEN); curidx++; } } } // skills? if (lorelev >= PR_NOVICE) { getflags(r->flags, retflag, &nretflags, F_STARTSKILL, F_NONE); strcpy(buf, ""); for (i = 0; i < nretflags; i++) { char nextbit[BUFLEN]; f = retflag[i]; if (i == 0) { sprintf(nextbit, "%s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); } else { sprintf(nextbit, ", %s %s", getskilllevelname(f->val[1]), getskillname(f->val[0])); } strcat(buf, nextbit); } if (strlen(buf)) { strncat(retbuf, "@- ", HUGEBUFLEN); strcat(buf, "\n"); strncat(retbuf, buf, HUGEBUFLEN); curidx++; } } // auto bonuses from flags for (f = r->flags->first ; f ; f = f->next) { char *p; strcpy(buf, ""); switch (f->id) { case F_AUTOCREATEOB: if (lorelev >= PR_NOVICE) { p = strdup(f->text); makeplural(&p); sprintf(buf, "Automatically creates %s around itself.", p); free(p); } break; case F_AUTOTANGLE: if (lorelev >= PR_BEGINNER) { sprintf(buf, "%d%% chance to entangle enemies", f->val[0]); } break; case F_ABSORBKINETIC: if (lorelev >= PR_BEGINNER) strcpy(buf, "Grows stronger through kinetic damage."); break; case F_AQUATIC: if (lorelev >= PR_NOVICE) strcpy(buf, "Moves normally through water"); break; case F_AWARENESS: if (lorelev >= PR_BEGINNER) strcpy(buf, "Can see in all directions."); break; case F_CANEATRAW: if (lorelev >= PR_ADEPT) strcpy(buf, "Can safely digest raw meat."); break; case F_CONSUMESOULS: if (lorelev >= PR_BEGINNER) { strcpy(buf, "Consumes the souls of nearby dead."); ; } break; case F_DAYBOOST: if (lorelev >= PR_ADEPT) { if (f->val[0] > 0) { sprintf(buf, "+%d accuracy during the day.", getaccuracymodnum(f->val[0])); } } break; case F_DODGES: if (lorelev >= PR_ADEPT) strcpy(buf, "Can dodge fatal attacks into adjacent locations."); break; case F_DTIMMUNE: if ((lorelev >= PR_BEGINNER) && !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) { snprintf(buf2, BUFLEN, "Immune to: %s", getdamname(n)); first = B_FALSE; } else { snprintf(buf2, BUFLEN, ", %s", getdamname(n)); } strcat(buf, buf2); } } } addflag(doneflags, F_DTIMMUNE, B_TRUE, NA, NA, NULL); } break; case F_DTRESIST: if ((lorelev >= PR_BEGINNER) && !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) { snprintf(buf2, BUFLEN, "Resistant to: %s", getdamname(n)); first = B_FALSE; } else { snprintf(buf2, BUFLEN, ", %s", getdamname(n)); } strcat(buf, buf2); } } } addflag(doneflags, F_DTRESIST, B_TRUE, NA, NA, NULL); } break; case F_ENHANCESMELL: if (lorelev >= PR_BEGINNER) sprintf(buf, "Enhanced sense of smell (range %d)", f->val[0]); break; case F_FEARLESS: if (lorelev >= PR_BEGINNER) sprintf(buf, "Fearless"); break; case F_FLYING: if (lorelev >= PR_NOVICE) sprintf(buf, "Can fly at will"); break; case F_HEAVYBLOW: if (lorelev >= PR_ADEPT) sprintf(buf, "Attacks will knock enemies backwards"); break; case F_HITCONFER: if (lorelev >= PR_BEGINNER) { if (f->val[0] == F_POISONED) { flag_t *f2; f2 = hasflag(r->flags, F_HITCONFERVALS); if (f2) { poisontype_t *pt; pt = findpoisontype(f2->val[0]); sprintf(buf, "Attacks inflict %s.", pt->name); } } } break; case F_HUMANOID: if (!forplayersel) sprintf(buf, "Can use weapons and armour."); break; case F_LEARNBOOST: if ((lorelev >= PR_BEGINNER) && (f->val[0] >= 0)) { sprintf(buf, "Gains XP %d%% faster.", f->val[0]); } break; case F_LEVITATING: if (lorelev >= PR_NOVICE) sprintf(buf, "Can levitate at will"); break; case F_MEDITATES: if (lorelev >= PR_ADEPT) 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_NIGHTBOOST: if (lorelev >= PR_ADEPT) { if (f->val[0] > 0) { sprintf(buf, "+%d accuracy at night.", getaccuracymodnum(f->val[0])); } } break; case F_NONCORPOREAL: if (lorelev >= PR_NOVICE) sprintf(buf, "Only affected by blessed, magic or silver weapons"); break; case F_NOSLEEP: if (lorelev >= PR_BEGINNER) sprintf(buf, "Does not sleep"); break; case F_PHALANX: if (lorelev >= PR_ADEPT) sprintf(buf, "Gains extra defence when in a pack."); break; case F_PHOTOMEM: sprintf(buf, "Photographic memory"); break; case F_POLYIMMUNE: if (lorelev >= PR_BEGINNER) sprintf(buf, "Immune to polymophic effects."); break; case F_REGENERATES: if (lorelev >= PR_BEGINNER) sprintf(buf, "Automatically regenerates health."); break; case F_RESISTMAG: if (lorelev >= PR_BEGINNER) sprintf(buf, "Magic-resistant"); break; case F_SEEINDARK: if (lorelev >= PR_BEGINNER) sprintf(buf, "Darkvision (range %d)", f->val[0]); break; case F_SEEINVIS: if (lorelev >= PR_ADEPT) sprintf(buf, "Can see invisible things"); break; case F_SHADOWED: if (lorelev >= PR_BEGINNER) sprintf(buf, "Cannot be seen from a distance."); break; case F_SILENTMOVE: if (lorelev >= PR_BEGINNER) sprintf(buf, "Moves silently"); break; case F_SPIDERCLIMB: if (lorelev >= PR_NOVICE) sprintf(buf, "Adheres to walls"); break; case F_STABILITY: if (lorelev >= PR_BEGINNER) sprintf(buf, "Will not fall on slippery ground."); break; case F_STENCH: sprintf(buf, "Emits a foul odour which affects others"); break; case F_SWIMEVASION: if (lorelev >= PR_BEGINNER) sprintf(buf, "%d%% evasion while swimming", f->val[0]); break; case F_TREMORSENSE: if (lorelev >= PR_BEGINNER) sprintf(buf, "Can sense vibrations (range %d)", f->val[0]); break; case F_VISRANGEMOD: if (lorelev >= PR_BEGINNER) 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 known.\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) { if ((f->val[1] == B_TRUE) && forplayersel) { } else { 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: if (lorelev >= PR_BEGINNER) sprintf(buf, "Will only eat meat."); break; case F_DAYBOOST: if (lorelev >= PR_ADEPT) { if ((f->val[0] != NA) && (f->val[0] < 0)) { sprintf(buf, "-%d accuracy during the day.", getaccuracymodnum(abs(f->val[0]))); } } break; case F_DEAF: if (lorelev >= PR_BEGINNER) sprintf(buf, "Deaf"); break; case F_DIURNAL: if ((lorelev >= PR_BEGINNER) && !forplayersel) sprintf(buf, "Sleeps at night."); break; case F_DTVULN: if ((lorelev >= PR_BEGINNER) && !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) { snprintf(buf2, BUFLEN, "Vulnerable to: %s", getdamname(n)); first = B_FALSE; } else { snprintf(buf2, BUFLEN, ", %s", getdamname(n)); } strcat(buf, buf2); } } } addflag(doneflags, F_DTVULN, B_TRUE, NA, NA, NULL); } break; case F_FASTMETAB: if (lorelev >= PR_BEGINNER) sprintf(buf, "Fast metabolism (needs to eat often)"); break; case F_LEARNBOOST: if ((lorelev >= PR_BEGINNER) && (f->val[0] < 0)) { sprintf(buf, "Gains XP %d%% slower.", abs(f->val[0])); } break; case F_MATVULN: if (lorelev >= PR_ADEPT) { 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: if (lorelev >= PR_NOVICE) sprintf(buf, "Will suffocate without water"); break; case F_NIGHTBOOST: if (lorelev >= PR_ADEPT) { if ((f->val[0] != NA) && (f->val[0] < 0)) { sprintf(buf, "-%d accuracy at night.", getaccuracymodnum(abs(f->val[0]))); } } break; case F_NOTAKECRITS: if (lorelev >= PR_NOVICE) sprintf(buf, "Immune to critical hits."); break; case F_NOPRAY: if (lorelev >= PR_BEGINNER) sprintf(buf, "Cannot worship gods."); break; case F_NORESTHEAL: if (lorelev >= PR_NOVICE) sprintf(buf, "Cannot restore HP by resting."); break; case F_NOSMELL: if ((lorelev >= PR_NOVICE) ) sprintf(buf, "No sense of smell."); break; case F_NOCTURNAL: if ((lorelev >= PR_BEGINNER) && !forplayersel) sprintf(buf, "Sleeps during the day."); break; case F_NOSPELLS: if (lorelev >= PR_NOVICE) sprintf(buf, "Cannot use magic."); 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: if (lorelev >= PR_ADEPT) { sprintf(buf, "Will not leave its home territory."); break; } break; case F_TAMABLE: if ((lorelev >= PR_ADEPT) && !forplayersel) { sprintf(buf, "Susceptible to bribery."); } break; case F_VEGETARIAN: if (lorelev >= PR_ADEPT) sprintf(buf, "Will not eat meat."); break; case F_VISRANGEMOD: if (lorelev >= PR_BEGINNER) { if (f->val[0] < 0) sprintf(buf, "Reduced vision range (%d)", f->val[0]); } break; case F_PARTVEGETARIAN: if (lorelev >= PR_ADEPT) 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 known.\n", HUGEBUFLEN); } ////////////////////////////////////////////// // other ////////////////////////////////////////////// // auto misc from flags for (f = r->flags->first ; f ; f = f->next) { char buf2[BUFLEN]; strcpy(buf, ""); switch (f->id) { case F_FILLPOT: if (lorelev >= PR_SKILLED) { objecttype_t *ot; ot = findot(f->val[0]); if (ot) { snprintf(buf2, BUFLEN, "Its blood can be bottled to create %s %s.", needan(ot->name) ? "an" : "a", ot->name); strcat(buf, buf2); } } break; // TODO: EATCONFER, need getflagname default: break; } if (strlen(buf)) { if (!donemischeading) { strncat(retbuf, mischeading, HUGEBUFLEN); donemischeading = B_TRUE; } strncat(retbuf, "@- ", HUGEBUFLEN); strcat(buf, "\n"); strncat(retbuf, buf, HUGEBUFLEN); curidx++; } } if (donemischeading && (curidx == 0)) { strncat(retbuf, "^n@None known.\n", HUGEBUFLEN); } } killflagpile(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; int numdescs = 0; if ((levhilite != PR_INEPT) && (slev == levhilite)) { hilitethis = B_TRUE; } for (i = 0; i < sk->nskilldesc; i++) { if (sk->skilldesclev[i] == slev) { numdescs++; if (slev == PR_INEPT) { // extra blank line after this one snprintf(buf, BUFLEN, "%s\n\n",sk->skilldesctext[i]); } else { char atxlevel[BUFLEN]; if (numdescs == 1) { snprintf(atxlevel, BUFLEN, "At %s level", getskilllevelname(sk->skilldesclev[i])); } else { snprintf(atxlevel, BUFLEN, " "); // same as last heading } 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,minrange; strcpy(retbuf, ""); if (ot->obclass->id == OC_SPELL) { power = getspellpower(player, ot->id); } else { power = -1; } range = getspellrange(player, ot->id, power, &minrange); 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)); snprintf(buf, BUFLEN, "It is a level %d %s spell.\n",f->val[0], schoollist); strncat(retbuf, buf, BUFLEN); } if (getmpcost(player, ot->id) == 0) { f = lfhasflagval(player, F_CANWILL, ot->id, NA, NA ,NULL); if (f && (f->val[2] > 0)) { sprintf(buf, "You can use this %s at will, every %d turns.\n", (ot->obclass->id == OC_ABILITY) ? "ability" : "spell", f->val[2]); strncat(retbuf, buf, BUFLEN); if (f->val[1] >= f->val[2]) { sprintf(buf, "^%dIt is currently ready to use.\n", C_GREEN); } else { sprintf(buf, "^%dIt is currently exhausted (rechage timer: %d/%d).\n", C_RED, f->val[1], f->val[2]); } strncat(retbuf, buf, BUFLEN); } else { 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); getflags(ot->flags, retflag, &nretflags, F_PLEASESGOD, F_NONE); for (i = 0; i < nretflags; i++) { lifeform_t *god; flag_t *f; god = findgod(retflag[i]->val[0]); f = lfhasflag(god, F_GODOF); sprintf(buf, "Successfully casting this spell will please %s (%s of %s).\n",god->race->name, (getgender(god) == G_FEMALE) ? "Goddess" : "God", f->text); strncat(retbuf, buf, BUFLEN); } if (nretflags) { 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\n",power, getspellmaxpower(ot->id)); } else { sprintf(buf, "^BIt is too powerful for you to cast (maximum power %d).^n\n", getspellmaxpower(ot->id)); } strncat(retbuf, buf, BUFLEN); if (range != UNLIMITED) { if (getspellmaxpower(ot->id) == 1) { sprintf(buf, "It has a range of %d cell%s",range, (range == 1) ? "" : "s"); } else { sprintf(buf, "At this power, it has a range of %d cell%s",range, (range == 1) ? "" : "s"); } if (minrange != 0) { char buf2[BUFLEN]; snprintf(buf2, BUFLEN, " (minimum %d)", minrange); strcat(buf, buf2); } strcat(buf, ".\n"); 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]; enum SPELLSCHOOL school[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 from this level 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 in the list. 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; } } // if we can "will" this, it's an ability, not a spell. school[nposs] = SS_ABILITY; nposs++; } } } } // end if level ok } // end if spell/ability } // end foreach objecttype // otherwise see if we can cast it using MP 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? int includeit = B_FALSE; // 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) { includeit = B_TRUE; } else if (f && !wantunknown) { // ignore this if we are unskilled in this school, unless it's a // racial ability. if ((f->lifetime != FROMRACE) && (getschoolskill(i) != SK_NONE) && !getskill(lf, getschoolskill(i))) { includeit = B_FALSE; } else { includeit = B_TRUE; } } if (includeit) { 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) { if (f) { if (f->val[2] == NA) { // no timer. validspell[nposs] = B_TRUE; err[nposs] = E_OK; } if (f->val[1] == f->val[2]) { // timer is full. snprintf(mpdesc[nposs], BUFLEN, "(ready)"); validspell[nposs] = B_TRUE; err[nposs] = E_OK; } else { // not ready yet snprintf(mpdesc[nposs], BUFLEN, "(%d/%d)",f->val[1],f->val[2]); validspell[nposs] = B_FALSE; err[nposs] = E_NOTREADY; } } else { 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; } school[nposs] = getspellschoolknown(lf, ot->id); 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 = school[i]; if (thisschool != lastschool) { lastschool = thisschool; addheading(pr, getschoolname(lastschool)); } getspellname(ot->id, player, buf2, B_FALSE); 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; choice_t *thisch; // letter doesn't matter longdesc = malloc(HUGEBUFLEN * sizeof(char)); makedesc_spell(ot, longdesc); thisch = addchoice(pr, 'a', buf2, buf, ot, longdesc); // do we ahve a shortcut defined for this spell/ability? if (lf && isplayer(lf)) { flag_t *f; f = lfhasflagval(lf, F_SHORTCUT, NA, NA, NA, ot->name); if (f) { thisch->shortcutslot = f->val[0]; } } 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; condset_t cs; // ask which object to read initcondv(&cs, CC_OPERABLE, B_TRUE, NA, CC_NONE); o = askobject(op, "Operate what", "You have nothing to operate.", NULL, 'o', &cs, B_FALSE); if (o) { operate(player, o, NULL); } } void dooptions(void) { char buf[BUFLEN]; char part1[BUFLEN]; char promptstr[BUFLEN],cmdchars[BUFLENSMALL]; char ch; int headinglines = 2; int y,h,done = B_FALSE; option_t *opt; h = getmaxy(mainwin); sprintf(promptstr, "Press letters to toggle options or ESC when done"); strcpy(cmdchars, ""); for (opt = firstoption ; opt ; opt = opt->next) { char thislet[2]; sprintf(thislet, "%c", opt->letter); strcat(cmdchars, thislet); } curs_set(0); while (!done) { cls(); centre(mainwin,C_WHITE, 0, "OPTIONS"); y = headinglines; ch = '\0'; for (opt = firstoption ; opt ; opt = opt->next) { sprintf(part1, "%c - %s", opt->letter, opt->text); sprintf(buf, "%-40s%s", part1, opt->enabled ? " ^gEnabled^n" : " ^BDisabled^n"); if (opt->enabled == opt->def) strcat(buf, " (default)"); wmove(mainwin, y, 0); textwithcol(mainwin, buf); if (opt->next && downline(&y, h, headinglines, NULL)) { //finished = B_TRUE; break; } } if (!ch) { centre(mainwin, C_WHITE, h-1, promptstr); ch = getch(); } if (ch == 27) { done = B_TRUE; } else { // find option with this letter for (opt = firstoption ; opt ; opt = opt->next) { if (opt->letter == ch) { // toggle it. if (opt->enabled) opt->enabled = B_FALSE; else opt->enabled = B_TRUE; break; } } } } curs_set(1); restoregamewindows(); } 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, NULL, B_FALSE); } 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); snprintf(buf, BUFLEN, "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, NULL, B_TRUE, B_FALSE, B_TRUE, '\0', NULL, SA_NONE, NULL, B_FALSE); while (o) { // describe it describeob(o); // ask for another one o = doaskobject(op, "Your final possessions were",NULL, NULL, B_TRUE, B_FALSE, B_TRUE,'\0', NULL, SA_NONE, NULL, B_FALSE); } real_clearmsg(B_TRUE); } void dofire(void) { enum ERROR why; if (!canshoot(player, &why)) { // why not? switch (why) { 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; } return; } shoot(player); } 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, 'g', "God Descriptions", NULL, NULL, NULL); addchoice(&prompt, 'j', "Job Descriptions", NULL, NULL, NULL); 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, '-', "(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 == 'j') { job_t *j; centre(mainwin,C_WHITE, 0, "JOB REFERENCE"); y = 2; initprompt(&prompt, "Describe which job (ESC when done)?"); for (j = firstjob ; j ; j = j->next) { addchoice(&prompt, 'a', j->name, NULL, j, j->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 { j = (job_t *)prompt.result; if (j) describejob(j->id); } } 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, getskill(player, sk->id)); 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, B_FALSE); if (!god) { done = B_TRUE; } else { describegod(god); } } } restoregamewindows(); } void dointeract(void) { cell_t *c; object_t *o; char ch = 'a'; int dir; object_t *ob[(MAXPILEOBS*8)+1]; condset_t cs; int opened = B_FALSE; int nobs,n; // operable objects here? for (o = player->cell->obpile->first; o ; o = o->next) { if (isinteractable(o) && !isdoor(o, NULL)) { // can't open/close doors you're on top of 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; } } } // nothing on our space - ask to interact elsewhere dir = askdir("Interact in which direction (- to cancel)", B_TRUE, B_TRUE); if ((dir == D_MYSELF) || (dir == D_NONE)) { msg("Cancelled."); return; } // can only interact with things we're facing if (getrelativedir(player, dir) != RD_FORWARDS) { msg("You can only interact with things in front of you."); return; } c = getcellindir(player->cell, dir); if (!c) { msg("Cancelled."); return; } // init prompt initprompt(&prompt, "Interact with what?"); prompt.maycancel = B_TRUE; // get adjacent cells // anything operable and impasssble? /* initcondv(&cs, CC_HASFLAG, B_TRUE, F_IMPASSABLE, CC_OPERABLE, B_TRUE, NA, CC_NONE); */ initcondv(&cs, CC_INTERACTABLE, B_TRUE, NA, CC_NONE); getobs(c->obpile, &cs, ob, &nobs); for (n = 0; n < nobs; n++) { char obname[BUFLEN]; getobname(ob[n], obname, ob[n]->amt); addchoice(&prompt, ch, obname, NULL, ob[n], NULL); if (ch == 'z') ch = 'A'; else ch++; } o = NULL; if (!prompt.nchoices) { msg("There is nothing there to interact with!"); return; } else if (prompt.nchoices == 1) { o = (object_t *)prompt.choice[0].data; } else { getchoice(&prompt); o = (object_t *)prompt.result; } if (!o) { msg("Cancelled."); return; } if (isdoor(o, &opened)) { if (opened) { closedoor(player, o); } else { opendoor(player, o); } } else { operate(player, o, NULL); } } 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, NULL, B_TRUE, B_TRUE, B_FALSE, '\0', NULL, SA_NONE, NULL, B_FALSE); while (o) { // describe it describeob(o); // ask for another one o = askobject(op, buf, NULL, NULL, '\0', NULL, B_FALSE); } 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) ) { 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) { condset_t cs; initcondv(&cs, CC_DRINKABLE, B_TRUE, NA, CC_NONE); liquid = askobject(op, "Quaff what", "You have nothing drinkable.", NULL, 'q', &cs, B_FALSE); } if (liquid) { if (candrink(player, liquid)) { if (isunknownbadobject(liquid) && skillcheck(player, SC_WIS, D_BADFEELING, 0)) { if (!confirm_badfeeling(liquid)) { msg("Cancelled."); return; } } quaff(player, liquid); } else { cantdrink(reason); return; } } else { msg("Cancelled."); } } 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 (haslofknown(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; condset_t cs; initcondv(&cs, CC_POURABLE, B_TRUE, NA, CC_NONE); // ask which object to read o = askobject(op, "Pour what", "You are not holding anything pourable.", NULL, 'P', &cs, B_FALSE); 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; condset_t cs; if (isblind(player)) { msg("You can't read while blind!"); return; } // ask which object to read initcondv(&cs, CC_READABLE, B_TRUE, NA, CC_NONE); o = askobject(op, "Read what", "You have nothing to read.", NULL, 'r', &cs, B_FALSE); 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; condset_t cs; // ask which object to read initcondv(&cs, CC_EQUIPPED, B_TRUE, NA, CC_WEAPON, B_FALSE, NA, CC_NONE); o = askobject(op, "Take off what", "You are not wearing anything!", NULL, 'T', &cs, B_FALSE ); 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; } // specify EITHER op or o. // returns B_TRUE on failure. int dothrow(obpile_t *op, object_t *o) { char buf[BUFLEN],buf2[BUFLEN]; if (!hasbp(player, BP_HANDS)) { msg("You have no hands to throw with!"); return B_TRUE; } // ask which object to throw if (!o) { o = askobject(op, "Throw what", "You have nothing to throw!", NULL, 't', NULL, B_FALSE); } if (o) { int maxdist; char subprompt[BUFLEN],oidbuf[BUFLENSMALL]; cell_t *where; enum ERROR why; getobname(o, buf, 1); if (!canthrow(player, o, &why)) { switch (why) { case E_EQUIPPED: msg("You'll need to take it off first."); break; case E_RAGE: msg("You are too enraged to throw anything!"); break; case E_STUNNED: msg("You cannot throw anything while stunned."); break; case E_LOWSTR: msg("You are not strong enough to throw that."); break; default: msg("For some reason, you can't throw that."); break; } return B_TRUE; } // 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 (!haslofknown(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 B_TRUE; } 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 B_TRUE; } } 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); return B_FALSE; } } } return B_TRUE; } // returns TRUE if we hit the bottom of the screen. int downline(int *y, int h, int headinglines, int *nextoffset) { /* // this is the heading we'll print after going past the 'MORE' strong snprintf(headbuf, w-1, "%s (continued)", heading); (*y)++; // are we aff the bottom of the screen? if (*y >= (h-3)) { // prompt to press a key centre(mainwin,C_WHITE, h-2, MORESTRING); if (bottomstring) { // show extra prompt if required. 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; } // clear screen and print the heading 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; */ (*y)++; // are we aff the bottom of the screen? if (*y >= (h-3)) { if (nextoffset) *nextoffset = *y - headinglines - 2; return B_TRUE; } else { if (nextoffset) *nextoffset = 0; } 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); } lf->redraws++; //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(); } } int haschoice(prompt_t *p, char ch) { int i; for (i = 0; i < p->nchoices; i++) { if (p->choice[i].ch == ch) return B_TRUE; } return B_FALSE; } choice_t *haschoicedata(prompt_t *p, void *data) { int i; for (i = 0; i < p->nchoices; i++) { if (p->choice[i].data == data) { return &(p->choice[i]); } } return NULL; } 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); } // wrapper for ncurses init_color void initcol(short c, short r, short g, short b) { int rv; rv = init_color(COLBASE+c, r, g, b); if (rv == ERR) { dblog("ERROR setting colour %d to { %d,%d,%d }",c,r,g,b); exit(1); } } // wrapper for init_pair void initcolpair(int pairidx, enum COLOUR fg, enum COLOUR bg ) { int rv; rv = init_pair(pairidx, COLBASE+fg, COLBASE+bg); if (rv == ERR) { dblog("ERROR setting colourpair %d to fg=%s bg=%s",pairidx,getcolname(fg),getcolname(bg)); exit(1); } } void initgfx(void) { int msgwinh = 2; int statwinh = 3; int i; short r,g,b; struct winsize ws; int w,h; ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); w = ws.ws_col; h = ws.ws_row; if ((w < 80) || (h < 25)) { printf("Error - Terminal size must be at least 80x25 (current: %d x %d).\n", w, h); exit(1); } setlocale(LC_CTYPE, ""); mainwin = initscr(); // colour setup if (!has_colors()) { endwin(); printf("Error - Terminal does not support colour.\n"); hascolour = B_FALSE; exit(1); } if (!can_change_color()){ wprintw(mainwin,"Error - Terminal does not support changes to colours.\n"); exit(1); } start_color(); dblog("colour pairs = %d", COLOR_PAIRS); dblog("colours = %d", COLORS); // init extra colours initcol(C_BLACK, 0, 0, 0); initcol(C_AQUA, 12, 672, 632); initcol(C_RED, 1000, 0, 0); initcol(C_GREEN, 0, 1000, 0); initcol(C_BLUE, 360, 670, 1000); initcol(C_INDIGO, 300, 0, 520); initcol(C_MAGENTA, 1000, 0, 1000); initcol(C_PINK, 820, 384, 576); initcol(C_CYAN, 0, 1000, 1000); initcol(C_GREY, 800, 800, 800); initcol(C_YELLOW, 1000, 1000, 0); initcol(C_BROWN, 584, 444, 264); initcol(C_WHITE, 1000, 1000, 1000); // specific colours initcol(C_BONE, 556, 548, 448); initcol(C_BRICK, 568, 140, 140); initcol(C_METAL, 500, 500, 500); initcol(C_FLESH, 952, 812, 608); initcol(C_FOG, 812, 808, 728); initcol(C_MOSS, 0, 748, 428); initcol(C_CARPET1, 560, 280, 136); initcol(C_CARPET2, 360, 80, 36); initcol(C_SMOKE, 250, 250, 300); initcol(C_STONE, 800, 800, 800); initcol(C_WOOD, 384, 244, 64); // dark cols initcol(C_DARKCYAN, 0, 500, 500); initcol(C_DARKBLUE, 0, 0, 500); initcol(C_DARKMAGENTA, 500, 0, 500); initcol(C_DARKGREEN, 0, 500, 0); initcol(C_ORANGE, 992, 468, 196); initcol(C_DARKGREY, 360, 360, 360); initcol(C_VDARKGREY, 300, 300, 300); initcol(C_DARKBROWN, 384, 244, 64); initcol(C_DARKYELLOW, 650, 650, 0); initcol(C_DARKRED, 500, 0, 0); // light cols initcol(C_LIGHTRED, 1000, 500, 500); initcol(C_LIGHTBLUE, 500, 500, 1000); initcol(C_LIGHTBROWN, 784, 644, 464); initcol(C_LIGHTCYAN, 500, 1000, 1000); initcol(C_LIGHTGREEN, 500, 1000, 500); initcol(C_LIGHTMAGENTA, 1000, 500, 1000); initcol(C_LIGHTYELLOW, 1000, 1000, 500); initcol(C_PINK, 1000, 584, 776); // placeholder initcol(C_LAST, 0, 0, 0); for (i = C_RED; i <= C_LAST; i++) { initcolpair(i, i, C_BLACK); init_pair(i+BLUEBG, i, COLOR_BLUE); init_pair(i+GREENBG, i, COLOR_GREEN); init_pair(i+REDBG, i, COLOR_RED); } color_content(C_WHITE,&r,&g,&b); dblog("white is %d,%d,%d",r,g,b); 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); gfxready = B_TRUE; } int drop(object_t *o, int count) { object_t *newob; obpile_t *op; char obname[BUFLEN]; enum OBTYPE origid; if (isdeadob(o)) return B_TRUE; 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)); // you get one free pickup/drop per turn if (lfhasflag(op->owner, F_DONEPICKUP)) { taketime(op->owner, SPEED_DROP); } else { addflag(op->owner->flags, F_DONEPICKUP, B_TRUE, NA, NA, NULL); } // if object wasn't changed... /* if (newob->type->id == origid) { if (op->owner) { } } */ } else if (!isdeadob(o)) { // 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 dumpcols(void) { int i; int margin = 0; int x = 0,y = 0; char buf[BUFLEN]; cls(); for (i = C_BLACK; i < C_LAST; i++) { wmove(mainwin, y, x); sprintf(buf, "^%d %d. This is %s^n\n",i,i,getcolname(i)); textwithcol(mainwin, buf); y++; x = margin; if (y >= 18) { y = 0; margin = 40; x = margin; } } getch(); restoregamewindows(); } void dumpskills(void) { skill_t *sk; char buf[BUFLEN],thisline[BIGBUFLEN]; int count = 0; // max skillname length: 21 (sorcery:translocation) // use blocks of 26 // NAME:Nvc NAME:Beg NAME:Adp // NAME:Beg // NAME:Adp // NAME:Skl // NAME:Exp // NAME:Mas // -21- // == 3 per line // == need 17 lines strcpy(thisline, ""); for (sk = firstskill ; sk ; sk = sk->next) { char lev[BUFLEN]; count++; switch (rnd(0,6)) { case 0: strcpy(lev, "---"); break; case 1: strcpy(lev, "Nov"); break; case 2: strcpy(lev, "Beg"); break; case 3: strcpy(lev, "Adp"); break; case 4: strcpy(lev, "Skl"); break; case 5: strcpy(lev, "Exp"); break; case 6: strcpy(lev, "Mst"); break; } snprintf(buf, BUFLEN, "%21s:%3s ",sk->name, lev); strcat(thisline, buf); if (count == 3) { count = 0; // print it. dblog("%s", thisline); strcpy(thisline, ""); } } } 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])); } } } } } } int effectline(int *stopnow, int *count, int offset, int *nextoffset, int headinglines, WINDOW *win, int *y, int *x, int newlineindent, char *format, ... ) { char buf[HUGEBUFLEN]; va_list args; int h; if (*stopnow) return *stopnow; h = getmaxy(win); va_start(args, format); vsnprintf( buf, HUGEBUFLEN, format, args ); va_end(args); if (!strlen(buf)) return B_FALSE; if (*count >= offset) { wrapprint_nomore(win, y, x, newlineindent, "%s", buf); if (downline(y, h, headinglines, nextoffset)) { *nextoffset += offset; *stopnow = B_TRUE; } *x = 0; } (*count)++; return *stopnow; } 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_LIGHTMAGENTA; case AT_VLOW: return C_MAGENTA; case AT_LOW: return C_RED; case AT_LTAVERAGE: return C_DARKYELLOW; 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_LIGHTCYAN; 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; char indenttext[BUFLEN]; if (prompt->choice[i].shortcutslot != -1) { if (gotheadings) { sprintf(indenttext, "%-4d",prompt->choice[i].shortcutslot); } else { sprintf(indenttext, "%d",prompt->choice[i].shortcutslot); } } else { if (gotheadings) { strcpy(indenttext, " "); } else { strcpy(indenttext, " "); } } 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) { wattron(mainwin, A_REVERSE); mvwprintw(mainwin, y, 0, "%s", prompt->choice[i].desc); wattroff(mainwin, A_REVERSE); } else { if (prompt->choice[i].hilite) setcol(mainwin, prompt->choice[i].hilite); mvwprintw(mainwin, y, 0, "%s%c - %s", indenttext, prompt->choice[i].ch, prompt->choice[i].desc); if (prompt->choice[i].hilite) unsetcol(mainwin, prompt->choice[i].hilite); } 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 == '!') || (ch == '?')) { // toggle prompts prompt->whichq++; if (prompt->whichq >= prompt->nqs) prompt->whichq = 0; } 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++) { char indenttext[BUFLEN]; if (prompt->choice[i].shortcutslot != -1) { if (gotheadings) { sprintf(indenttext, "%-4d",prompt->choice[i].shortcutslot); } else { sprintf(indenttext, "%d",prompt->choice[i].shortcutslot); } } else { if (gotheadings) { strcpy(indenttext, " "); } else { strcpy(indenttext, " "); } } 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 wattron(mainwin, A_REVERSE); mvwprintw(mainwin, y, 0, "%s", curheading); wattroff(mainwin, A_REVERSE); y++; } doneheading = B_TRUE; } // only print if we're not off the bottom if ((i >= first) && !atbottom) { if (nvalid && !foundfirstvalid) setcol(mainwin, C_LIGHTGREEN); mvwprintw(mainwin, y, 0, "%s%s", indenttext, prompt->choice[i].desc); y++; if (nvalid && !foundfirstvalid) unsetcol(mainwin, C_LIGHTGREEN); 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 wattron(mainwin, A_REVERSE); mvwprintw(mainwin, y, 0, "%s", curheading); wattroff(mainwin, A_REVERSE); y++; } doneheading = B_TRUE; } // only print if we're not off the bottom if ((i >= first) && !atbottom) { mvwprintw(mainwin, y, 0, "%s%s", indenttext, 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, 0, "%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) // if we've typed in the whole string, don't just start grabbing random memory! if (strlen(inpstring) >= strlen(prompt->choice[validchoice].text)) { strcpy(remainder, ""); } else { 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_DARKGREY; case PR_NOVICE: return C_BROWN; case PR_BEGINNER: return C_LIGHTYELLOW; case PR_ADEPT: return C_LIGHTGREEN; case PR_SKILLED: return C_LIGHTBLUE; case PR_EXPERT: return C_LIGHTCYAN; case PR_MASTER: return C_LIGHTMAGENTA; } return C_DARKGREY; } 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,walls; int stopnow = B_FALSE; int i; object_t *o; lastdir = f->val[0]; ihaveturned = f->val[1]; walls = f->val[2]; // 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_COSMETIC) && !hasflag(o->flags, F_TRAIL)) { stopnow = B_TRUE; break; } } for (i = 0; i < player->nlos; i++) { lifeform_t *thislf; thislf = player->los[i]->lf; if (thislf && !isplayer(thislf) && !areallies(player, thislf) && cansee(player, thislf)) { if (areenemies(player, player->los[i]->lf)) { // visible hostile monsters stop us stopnow = B_TRUE; break; } else if (getcelldist(player->cell, player->los[i]) <= 1) { // any non-ally lf in adjacent cells should stop us stopnow = B_TRUE; break; } } } // adjacent doors stop us. 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) && isroom(player->cell)) { // haven't turned yet and in a room? // if walls to our l+r have changed... if (getleftrightwalls(player) != walls) { stopnow = B_TRUE; } else { // otherwise 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; } // HANDLE COMMANDS switch (chartocmd(ch)) { // movement case CMD_MOVE_N: case CMD_MOVE_NE: case CMD_MOVE_E: case CMD_MOVE_SE: case CMD_MOVE_S: case CMD_MOVE_SW: case CMD_MOVE_W: case CMD_MOVE_NW: trymove(player, chartodir(ch), B_TRUE, B_FALSE); break; // run / strafe case CMD_RUN_N: case CMD_RUN_NE: case CMD_RUN_E: case CMD_RUN_SE: case CMD_RUN_S: case CMD_RUN_SW: case CMD_RUN_W: case CMD_RUN_NW: 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 CMD_TURN_N: case CMD_TURN_NE: case CMD_TURN_E: case CMD_TURN_SE: case CMD_TURN_S: case CMD_TURN_SW: case CMD_TURN_W: case CMD_TURN_NW: dir = chartodir(ch); if (dir != player->facing) { takerotationtime(player); setfacing(player, dir); drawscreen(); } break; case CMD_REST: // 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; // player commands case CMD_FORCEATTACK: // attack addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); if (wantrepeat) { doattackcell(repeatflag.val[2]); } else { doattackcell(D_NONE); } break; case CMD_GO: // go somewhere (pathfind) startpathfind(); break; case CMD_HELP: // help dohelp('?'); break; case CMD_INV: // inventory doinventory(player->pack); break; case CMD_COUNTMONEY: // count money docountmoney(player); break; case CMD_INFOPLAYER: // display player stats showlfstats(player, B_FALSE); break; case CMD_INFOARMOUR: // display armour showlfarmour(player); break; case CMD_INTERACT: // interact with adjacent objects dointeract(); break; case CMD_LOOKHERE: // look at what's here dolook(player->cell, B_TRUE); break; case CMD_MSGHIST: case CMD_MSGHIST2: domsghist(); break; case CMD_LOOKAROUND: // explain object doexplain("Select glyph to explain (v for info, ESC to cancel):"); break; case CMD_INFOKNOWLEDGE: // list knowledge doknowledgelist(); break; case CMD_RESTFULL: // rest dorest(); break; case CMD_MAGIC: // 'm'agic/abilities (magic) addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); domagic(OT_NONE, NA, NA); break; case CMD_MEMMAGIC: // 'M'emorise magic/ability shortcut domemmagic(); break; case CMD_UP: // go up if (isprone(player)) { standup(player); } else { dostairs(D_UP); } break; case CMD_DOWN: // go down doenter(player); break; // firearm functions case CMD_FIRE: // fire gun addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); dofire(); break; case CMD_FIRENEW: // aim then fire if (!doselguntarget()) { dofire(); } break; case CMD_AIM: // aim doselguntarget(); break; case CMD_GUNRELOAD: // reload Gun with current ammo loadfirearmfast(player, B_TRUE); break; case CMD_NEXTTARGET: donextguntarget(); break; /* case CMD_CLOSE: // close addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); doclose(); break; */ case CMD_COMMS: // communicate docomms(NULL); break; case CMD_COMMSALL: // communicate docommsmulti(); break; // object functions case CMD_EAT: // eat doeat(player->pack); break; case CMD_DROPMULTI: // drop multiple things //dodrop(player->pack, B_SINGLE, player->cell->obpile); dodrop(player->pack, B_MULTIPLE, player->cell->obpile); break; case CMD_OPERATE: // operate addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); dooperate(player->pack); break; case CMD_OFFER: dooffer(); break; case CMD_POUR: // Pour dopour(player->pack); break; case CMD_WEAR: // wear dowear(player->pack); break; case CMD_WEILD: // weild doweild(player->pack); break; case CMD_TAKEOFF: // takeoff dotakeoff(player->pack); break; case CMD_PICKUP: // pickup dopickup(player->cell->obpile, B_FALSE); break; case CMD_READ: // read doread(player->pack); break; case CMD_QUAFF: // quaff doquaff(player->pack); break; case CMD_THROW: // throw dothrow(player->pack, NULL); break; case CMD_EXCHANGE: // eXchange wepaon for secondary exchangeweapon(player); break; // GAME FUNCTIONS case CMD_OPTIONS: // options dooptions(); break; case CMD_QUIT: // quit doquit(); break; case CMD_SAVEQUIT: // 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(int 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_LIGHTCYAN: case C_LIGHTBLUE: case C_LIGHTMAGENTA: case C_LIGHTGREEN: 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; int height; 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) { char aimname[11]; wprintw(statwin, "Aim:"); // limit snprintf(aimname,11,"%s",f->text); 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, 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_LIGHTGREEN); wprintw(statwin, "LevUp",xpleft); unsetcol(statwin, C_LIGHTGREEN); } 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); if (player->skillpoints > 0) setcol(statwin, C_LIGHTGREEN); wprintw(statwin, "%d", player->skillpoints); if (player->skillpoints > 0) unsetcol(statwin, C_LIGHTGREEN); wprintw(statwin, "/%d%% ", (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_INJURY)) { setcol(statwin, C_RED); wprintw(statwin, " Injured"); 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_LIGHTBLUE); wprintw(statwin, " LoGrv"); unsetcol(statwin, C_LIGHTBLUE); } if (hasactivespell(player, OT_S_DELAYDEATH)) { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " DelayDeath"); unsetcol(statwin, C_LIGHTBLUE); } if (lfhasflag(player, F_RAGE)) { setcol(statwin, C_RED); wprintw(statwin, " Rage"); unsetcol(statwin, C_RED); } if (lfhasflag(player, F_SILENCED)) { setcol(statwin, C_RED); wprintw(statwin, " Mute"); unsetcol(statwin, C_RED); } if (isswimming(player)) { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " Swim"); unsetcol(statwin, C_LIGHTBLUE); } if (isclimbing(player)) { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " Climb"); unsetcol(statwin, C_LIGHTBLUE); } if (isairborne(player, &height)) { if (lfhasflag(player, F_FLYING)) { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " Fly:%d",height); unsetcol(statwin, C_LIGHTBLUE); } else if (lfhasflag(player, F_LEVITATING)) { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " Lev"); unsetcol(statwin, C_LIGHTBLUE); } else { setcol(statwin, C_LIGHTBLUE); wprintw(statwin, " Hov"); // "hov"ering unsetcol(statwin, C_LIGHTBLUE); } } 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) && !isdead(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_DARKYELLOW); wprintw(statwin, " Burdened"); unsetcol(statwin, C_DARKYELLOW); 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_DARKYELLOW); //wprintw(statwin, " %s(%d)", dstring,f->lifetime); wprintw(statwin, " %s", dstring); unsetcol(statwin, C_DARKYELLOW); } f = ispoisoned(player); if (f) { poisontype_t *pt; pt = findpoisontype(f->val[0]); // find highest amount of poison if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) { if (pt->severity == PS_CURSE) { setcol(statwin, C_RED); wprintw(statwin, " %s", pt->desc); unsetcol(statwin, C_RED); } else if (poisonthreatenslife(player, f)) { setcol(statwin, C_RED); wprintw(statwin, " %s(bad)", pt->desc); unsetcol(statwin, C_RED); } else { setcol(statwin, C_DARKYELLOW); wprintw(statwin, " %s(mild)", pt->desc); unsetcol(statwin, C_DARKYELLOW); } } else { setcol(statwin, C_RED); wprintw(statwin, " %s", pt->desc); 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_DARKYELLOW); wprintw(statwin, " %s", buf2); if (hlev == H_STARVING) unsetcol(statwin, C_RED); else unsetcol(statwin, C_DARKYELLOW); } // 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); } f = lfhasflag(player, F_FULLSHIELD); if (f) { setcol(statwin, C_MAGENTA); wprintw(statwin, " FullShld"); unsetcol(statwin, C_MAGENTA); } // construct waiting string strcpy(waitbuf, ""); /* // timespent > 0? if (player->timespent) { snprintf(buf, BUFLEN, "busy: %d", player->timespent); strcat(waitbuf, buf); } */ switch (getlftemp(player)) { case T_VCOLD: setcol(statwin, C_MAGENTA); wprintw(statwin, " V.Cold"); unsetcol(statwin, C_MAGENTA); break; case T_COLD: setcol(statwin, C_RED); wprintw(statwin, " Cold"); unsetcol(statwin, C_RED); break; case T_CHILLY: setcol(statwin, C_YELLOW); wprintw(statwin, " Chilly"); unsetcol(statwin, C_YELLOW); break; case T_NORMAL: break; case T_WARM: setcol(statwin, C_YELLOW); wprintw(statwin, " Warm"); unsetcol(statwin, C_YELLOW); break; case T_HOT: setcol(statwin, C_YELLOW); wprintw(statwin, " Hot"); unsetcol(statwin, C_YELLOW); break; case T_VHOT: setcol(statwin, C_MAGENTA); wprintw(statwin, " V.Hot"); unsetcol(statwin, C_MAGENTA); break; } 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_DARKYELLOW); // ooooooooooooo fix. setcol(statwin, C_WHITE); getregionname(buf, player->cell->map, NULL, RF_WITHLEVEL); capitalise(buf); wprintw(statwin, "%s", buf); //unsetcol(statwin, C_DARKYELLOW); unsetcol(statwin, C_WHITE); } 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++; } void redrawresume(void) { /* noredraw = B_FALSE; if (needredraw) { drawlevelfor(player); } */ if (noredraw > 0) { noredraw--; } } 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; } // prompts the player to learn a new spell from school 'ss' (ss_none means any) void select_new_spell(enum SPELLSCHOOL ss, int lev) { int done = B_FALSE; char qbuf[BUFLEN]; sprintf(qbuf, "Learn which new spell (maxmp=%d):", getmaxmp(player)); while (!done) { makespellchoicelist(&prompt, player, qbuf, "Describe which spell:", ss, B_TRUE, B_FALSE, B_FALSE, player->maxmp); if (prompt.nchoices > 0) { objecttype_t *ot; getchoicestr(&prompt, B_TRUE, B_TRUE); ot = prompt.result; if (ot) { if (prompt.whichq == 0) { // learn the spell flag_t *ff; ff = addtempflag(player->flags, F_CANCAST, ot->id, NA, NA, NULL, FROMJOB); if (lev >= 1) { ff->fromlev = lev; } done = B_TRUE; } else { describespell(ot); } } } else { msg("There are no new spells for you to learn at this time."); done = 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_LIGHTGREEN); return; } } // dump out a single hiscore line int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname) { int i,x,y,origy; 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 (gfxready) { if (streq(score, (char *)hilitescore)) setcol(mainwin, C_LIGHTGREEN); wprintw(mainwin, HISCOREFORMAT, rank, score, name, job); // last field should be wrapped with lines 2+ indented getyx(mainwin, y, x); origy = y; wrapprint(mainwin, &y, &x, x, "%s", killer); if (streq(score, (char *)hilitescore)) unsetcol(mainwin, C_LIGHTGREEN); if (y == origy) { wprintw(mainwin, "\n\n"); } else { wprintw(mainwin, "\n"); } } else { // regular text with no hilighting printf(HISCOREFORMAT, rank, score, name, job); // last field should be wrapped with lines 2+ indented, but just // print it without wrapping. printf("%s\n",killer); } if (rank) free(rank); if (job) free(job); if (name) free(name); if (score) free(score); if (killer) free(killer); return B_FALSE; } void showlfarmour(lifeform_t *lf) { enum BODYPART bp; object_t *o; object_t *arm[MAXBODYPARTS*2]; int narm = 0; int y,i; char buf[BUFLEN],ch; int keepgoing = B_TRUE; for (i = 0; i < MAXBODYPARTS*2; i++) { arm[i] = NULL; } 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; object_t *oo; int nhere = 0; snprintf(buf, BUFLEN, "%13s:%1s",getbodypartname(lf, bp), " "); // get outermost armour here so that we can show 'covered' if needed outerob = getouterequippedob(lf, bp); for (oo = lf->pack->first ;oo ; oo = oo->next) { flag_t *f; int thisar = 0,showar = B_FALSE; char obname[BUFLEN]; o = NULL; // is this object equipped in the right place? if (hasflagval(oo->flags, F_EQUIPPED, bp, NA, NA, NULL)) { o = oo; nhere++; } if (!o) continue; arm[narm++] = o; // remember for later // two handed weapons. if ((bp == BP_SECWEAPON ) && (o == arm[BP_WEAPON])) { sprintf(rhs, "(using two-handed weapon)"); } else { getobname(o, obname, o->amt); snprintf(rhs, BUFLEN, "%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])) { thisar += f->val[0]; thisar += getobbonus(o, B_TRUE); showar = B_TRUE; } f = hasflagvalknown(o->flags, F_EQUIPCONFER, F_ARBOOST, NA, NA, NULL); if (f) { thisar += f->val[1]; showar = B_TRUE; } if (showar) { char numbuf[BUFLENSMALL]; 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); } } mvwprintw(mainwin, y, 0, "%s", buf); setobcolour(mainwin, o, B_TRUE); //wprintw(mainwin, "%s", rhs); textwithcol(mainwin, rhs); setobcolour(mainwin, o, B_FALSE); y++; } // no armour in this body part? if (!nhere) { strcpy(rhs, "-"); mvwprintw(mainwin, y, 0, "%s", buf); //wprintw(mainwin, "%s", rhs); textwithcol(mainwin, rhs); 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 (o = 0; i < MAXBODYPARTS*2; i++) { if (arm[i] && (arm[i]->letter == ch)) { describeob(arm[i]); } } keepgoing = B_TRUE; } } restoregamewindows(); } void showlfstats(lifeform_t *lf, int showall) { int y = 0, y2 = 0, x2 = 40; int startx,starty; int headinglines = 2; 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; int dammod; //int accmod; enum BODYPART bp; enum BODYPART missingbp[MAXBODYPARTS]; int nmissingbp; obpile_t *op = NULL; char ch; char mode = '@'; char promptstr[BUFLEN],navstr[BUFLEN]; char cmdchars[BUFLEN]; int done = B_FALSE; enum SKILLLEVEL lorelev; enum COLOUR lorecol; int min,max; flag_t *retflag[MAXCANDIDATES]; int nretflags,offset = 0, nextoffset = 0; 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_DARKYELLOW; } // 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; } while (!done) { cls(); y = 0; ch = '\0'; if (mode == '@') { object_t *tempob = NULL; int amt; int temp,ctemp; getcelltemp(lf->cell, &ctemp); temp = getlftemp(lf); wattron(mainwin, A_UNDERLINE); if (isplayer(lf)) { centre(mainwin, C_WHITE, 0, "CHARACTER DETAILS"); } else{ centre(mainwin, C_WHITE, 0, "MONSTER DETAILS"); } wattroff(mainwin, A_UNDERLINE); x = 0; //centre(mainwin, C_MAGENTA, 1, "[Press ? for a full description]"); y = headinglines; y2 = headinglines; 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, getjobname(lf)); } else { snprintf(buf, BUFLEN, "%s", getjobname(lf)); } wprintw(mainwin, "%-20s", buf); y++; } if (isplayer(lf) || (lorelev >= PR_BEGINNER) ) { doheadingsmall(mainwin, y, 0, ftext, "Alignment"); wprintw(mainwin, "%-20s", getalignmentname(getalignment(lf))); 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 , getmaxmp(lf),maxmpstr); y++; } if (showall || (lorelev >= PR_ADEPT)) { if (isplayer(lf)) { doheadingsmall(mainwin, y, 0, ftext, "Exp Level"); } else { doheadingsmall(mainwin, y, 0, ftext, "Threat Rating"); } 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", gettr(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", dammod); strcat(buf, buf2); } else if (dammod <= -1) { snprintf(buf2, BUFLEN, ", -%d dmg", abs(dammod)); strcat(buf, buf2); } break; case A_CON: mod = getstatmod(lf, i); 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(after move)/%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; int edam[100]; enum DAMTYPE edt[100]; int ndam = 0; // weapon if (showall) { char buf2[BUFLEN]; int n; // 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]); // include extra damage for flaming, f_extradam, etc. edam[0] = maxdam; // doesn't matter what this is edt[0] = DT_NONE; // ndam = 1; getextradamwep(w[i], edam, edt, &ndam, B_TRUE); for (n = 1; n < ndam; n++) { mindam += edam[n]; maxdam += edam[n]; } 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); getflags(lf->flags, retflag, &nretflags, F_HASATTACK, F_NONE); for (i = 0; i < nretflags; i++) { object_t *o; objecttype_t *ot; int instances = 1; int n; f = retflag[i]; for (n = i+1 ; n < nretflags; n++) { if ((retflag[n]->val[0] == f->val[0]) && (retflag[n]->val[1] == f->val[1]) && (retflag[n]->val[2] == f->val[2]) && streq(retflag[n]->text, f->text)) { instances++; } } 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"); // add '2 x whatever' for multiples. if (instances == 1) { wprintw(mainwin, "%s", buf); } else { wprintw(mainwin, "%d x %s", instances, 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 // now skip over multiple instances of the same flag if (instances >= 2) { i += (instances-1); } } // 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, 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; } wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, y, "THREAT ASSESSMENT"); wattroff(mainwin, A_UNDERLINE); y++; starty = y; startx = x; /* 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, 0, "%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; // append behaviour text f = lfhasflag(lf, F_BEHAVIOUR); if (f) { behaviour_t *b; b = findbehaviour(f->val[0]); if (b) { char bhtext[BUFLEN]; switch (b->id) { case BH_INSANE: sprintf(bhtext, "It is insane, and will attack anyone who comes close. "); break; case BH_TIMID: sprintf(bhtext, "It is timid, and will flee upon taking damage. "); break; case BH_DRUGGED: sprintf(bhtext, "It is drugged, and will never flee. "); break; case BH_DETERMINED: sprintf(bhtext, "It is determined, and will chase you for longer. "); break; case BH_LAZY: sprintf(bhtext, "It is lazy, and won't chase you very far. "); break; case BH_MUSCLED: sprintf(bhtext, "It is muscled, and has extra hit points. "); break; case BH_SCRAWNY: sprintf(bhtext, "It is scrawy, and has lowered hit points. "); break; default: strcpy(bhtext, ""); break; } if (strlen(bhtext)) { setcol(mainwin, lorecol); wrapprint(mainwin, &y, &x, 0, "%s", bhtext); unsetcol(mainwin, lorecol); } } } 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, 0, "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, 0, "Neither of you would be able to kill the other. "); unsetcol(mainwin, lorecol); } } else { if (hitstokillit) { setcol(mainwin, lorecol); wrapprint(mainwin, &y, &x, 0, "You could kill it in %d hit%s. ", hitstokillit, (hitstokillit == 1) ? "" : "s"); unsetcol(mainwin, lorecol); } else { setcol(mainwin, lorecol); wrapprint(mainwin, &y, &x, 0, "You probably couldn't kill it. "); unsetcol(mainwin, lorecol); } if (hitstokillyou) { setcol(mainwin, lorecol); wrapprint(mainwin, &y, &x, 0, "It could kill you in %d hit%s. ", hitstokillyou, (hitstokillyou == 1) ? "" : "s"); unsetcol(mainwin, lorecol); } else { setcol(mainwin, lorecol); wrapprint(mainwin, &y, &x, 0, "It probably couldn't 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 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, 0, "%s ", buf); unsetcol(mainwin, lorecol); y++; x = 0; } } // TODO: move this to 'effects' ?? // obvious physical effects here. f = lfhasknownflag(lf, F_SWARM); if (f) { wrapprint(mainwin, &y, &x, 0, "%s %s a swarm, gaining EV and losing strength as its health drops.", you(lf), is(lf) ); } 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, 0, "%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, 0, "%s ", buf); } if (isbleeding(lf)) { wrapprint(mainwin, &y, &x, 0, "%s %s bleeding. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_CLIMBING); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s climbing on a wall. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_FEIGNINGDEATH); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s pretending to be dead. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_FEARLESS); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s fearless. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_FLYING); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s flying. ", you(lf), is(lf)); } if (isswimming(lf)) { wrapprint(mainwin, &y, &x, 0, "%s %s swimming. ", you(lf), is(lf)); } if (isclimbing(lf)) { wrapprint(mainwin, &y, &x, 0, "%s %s currently climbing. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_PRONE); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s lying on the ground. ", you(lf), is(lf)); } f = lfhasflag(lf, F_FROZEN); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%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, 0, "%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, 0, "%s ", buf); } f = lfhasknownflag(lf, F_HIDING); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%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, 0, "^%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, 0, "%s %s invisible. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_LEVITATING); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s levitating. ", you(lf), is(lf)); } f = lfhasflag(lf, F_NONCORPOREAL); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s %s noncorporeal and can walk through walls. ", you(lf), is(lf)); } amt = lfproduceslight(lf,&tempob); if (amt > 0) { char obname[BUFLEN]; char youstr[BUFLEN]; if (tempob) { getobname(tempob, obname, 1); sprintf(youstr, "%s %s",your(lf),noprefix(obname)); } else { sprintf(youstr, "%s",you(lf)); } wrapprint(mainwin, &y, &x, 0, "%s produce%s light (minimum vision range: %d).", youstr, (!tempob && isplayer(lf)) ? "" : "s", amt); } f = lfhasknownflag(lf, F_SLOWMETAB); if (f && (f->known)) { wrapprint(mainwin, &y, &x, 0, "%s metabolic rate has been decreased. ", your(lf), getpossessive(you(lf))); } f = lfhasknownflag(lf, F_SPRINTING); if (f) { wrapprint(mainwin, &y, &x, 0, "%s %s sprinting. ", you(lf), is(lf)); } if (!getstamina(lf)) { wrapprint(mainwin, &y, &x, 0, "%s %s exhausted. ", you(lf), is(lf)); } f = lfhasknownflag(lf, F_UNDEAD); if (f) { wrapprint(mainwin, &y, &x, 0, "%s %s undead. ", you(lf), is(lf)); } // non-intrinsic effecst like polymorph, eye shading if (isplayer(lf)) { 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, 0, "%s ", buf); } } if (!canuseweapons(lf)) { wrapprint(mainwin, &y, &x, 0, "%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 (retflag[i]->lifetime != FROMINJURY) { 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, 0, "%s ", buf); } f = lfhasflag(lf, F_RETALIATE); if (f && (f->known)) { char *loctext,retalname[BUFLEN],dicetext[BUFLEN],*p; loctext = strdup(f->text); p = readuntil(dicetext, loctext, '^'); readuntil(retalname, p, '^'); if (showall || (lorelev >= PR_BEGINNER)) { wrapprint(mainwin, &y, &x, 0, "%s %s covered by %s (%s %s dmg to attackers). ", you(lf), is(lf), retalname, dicetext, getdamname(f->val[0])); } else { wrapprint(mainwin, &y, &x, 0, "%s %s covered by %s. ", you(lf), is(lf), retalname); } free(loctext); } // 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, 0, "%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, 0, "%s %s made out of %s. ",you(lf), is(lf), mt->name); } if (temp != T_NORMAL) { if (isplayer(lf)) { wrapprint(mainwin, &y, &x, 0, "You are feeling %s (%d degrees).", gettemperaturename(temp),ctemp); } else if (lorelev >= PR_BEGINNER) { wrapprint(mainwin, &y, &x, 0, "%s looks %s.", gettemperaturename(temp)); } } if ((y == starty) && (x == startx)) { wrapprint(mainwin, &y, &x, 0, "Nothing obvious."); } } else if (mode == 'a') { int count = 0; wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, 0, "ABILITIES"); wattroff(mainwin, A_UNDERLINE); y = headinglines; for (ot = objecttype ; ot ; ot = ot->next) { f = lfhasknownflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); if (f && (f->known)) { if (count >= offset) { 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, headinglines, &nextoffset)) { nextoffset += offset; break; } } count++; } } y++; } else if (mode == 's') { char skilltitle[BUFLEN]; enum SKILLLEVEL slev; skill_t *sk; int finished = B_FALSE,dounknown; int count = 0; lfstatheading("SKILLS", offset); y = headinglines; // construct headings 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); // go through and list each skill, known ones first. count = 0; for (dounknown = 0; dounknown <= 1; dounknown++) { for (sk = firstskill ; sk ; sk = sk->next) { char thisline[BIGBUFLEN]; int printed = B_FALSE; slev = getskill(lf, sk->id); if (!dounknown && (slev != PR_INEPT)) { if (count >= offset) { char endbit[BUFLEN]; char basecolour = 'n'; int max; if (ismaxedskill(lf, sk->id)) { basecolour = 'h'; } // known skill snprintf(thisline, BIGBUFLEN, "^%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) { char blank[2],endchar[2]; int n,blanklen; char *sn; sn = getskilllevelabbr(slev); if (ismaxedskill(lf, sk->id)) { strcpy(blank, "*"); strcpy(endchar, "*"); blanklen = 7 - strlen(sn); } else { strcpy(blank, "="); strcpy(endchar, "|"); blanklen = 7 - strlen(sn); } strcpy(toadd,""); for (n = 0; n < blanklen; n++) { strncat(toadd, blank, BUFLEN); } strncat(toadd, sn, BUFLEN); strncat(toadd, blank, BUFLEN); strncat(toadd, endchar, BUFLEN); /* 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; } count++; } else if (dounknown && !slev && lfhasflagval(lf, F_CANLEARN, sk->id, NA, NA, NULL)) { if (count >= offset) { 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; } count++; } if (printed) { if (downline(&y, h, headinglines, &nextoffset)) { nextoffset += offset; finished = B_TRUE; break; } } } if (finished) break; } } else if (mode == 'm') { char subheading[BUFLEN]; int lev; int anyfound; int exitnow = B_FALSE; int count = 0; snprintf(subheading, BUFLEN, " %-4s%-26s%-15s%-13s%s","Lv","Spell", "School", "Power", "Cost"); wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, y, "MAGIC"); y += 2; wattroff(mainwin, A_UNDERLINE); 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)) { if (count >= offset) { 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, B_FALSE); if (castable || !isplayer(lf)) 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 || !isplayer(lf)) unsetcol(mainwin, C_GREEN); else unsetcol(mainwin, C_RED); anyfound = B_TRUE; if (downline(&y, h, headinglines, &nextoffset)) { nextoffset += offset; exitnow = B_TRUE; break; } } // end if count >= offset count++; } } } } // end foreach obtype } if (!anyfound) { mvwprintw(mainwin, y, 0, "%s cannot cast any spells.", you(lf)); } } else if (mode == 'e') { int count = 0,headinglines = 2; int nfound = 0,luckmod; enum LFSIZE racesize,cursize; int stopnow = B_FALSE; char source[BUFLEN]; x = 0; // override // down a line. wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, y, "EFFECTS"); wattroff(mainwin, A_UNDERLINE); y += headinglines; count = 0; if (isplayer(lf)) { //enum ATTRIB a; // gods angry? if (godprayedto(R_GODLIFE)) { enum PIETYLEV plev; plev = getpietylev(R_GODLIFE, NULL, NULL); if (plev <= PL_ANGRY) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "You have been cut off from Life magic.", you(lf)); } if (plev == PL_ANGRY) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The Goddess of Life has slowed your body's natural healing.", you(lf)); } else if ((plev == PL_FURIOUS) || (plev == PL_ENRAGED)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The Goddess of Life has nullified your body's natural healing.", you(lf)); } } if (godprayedto(R_GODNATURE) && godisangry(R_GODNATURE)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "You have been cut off from Nature magic.", you(lf)); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The Goddess of Nature has cursed you with a rotting touch.", you(lf)); } // stats being modified by gods? /* for (a = 0; a < MAXATTS; a++) { enum RACE godid = R_NONE; int mod; mod = getattrgodmod(a, &godid); if (mod) { char godname[BUFLEN]; char attrname[BUFLEN]; getgodname(godid, godname); sprintf(attrname, getattrname(a)); capitalise(attrname); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s is %s your %s by %s%d.", godname, (mod > 0) ? "boosting" : "lowering", attrname, (mod > 0) ? "+" : "", mod ); } } */ } // ready to gain a level? if (lfhasflag(lf, F_STATGAINREADY)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s are ready to train your attributes.", you(lf)); } if (lf->skillpoints) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s are ready to learn a new skill.", you(lf)); } if (levelabilityready(lf)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s are ready to learn a new job-based ability.", you(lf)); } // temperature if (isplayer(lf) || (lorelev >= PR_BEGINNER)) { int temp; temp = getlftemp(lf); if (temp != T_NORMAL) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s feeling %s.", you(lf), is(lf), gettemperaturename(temp)); if (temp < T_NORMAL) { // cold int pen; pen = gettempaccpenalty(lf, temp); if (pen) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " %d accuracy due to exposed body parts.",pen); } if (!isimmuneto(lf->flags, DT_COLD, B_FALSE) && !isresistantto(lf->flags, DT_COLD, B_FALSE)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " Cannot sleep due to cold."); } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " Chance of shivering or getting sick due to cold."); } else { // hot int pen; if (!lfhasflag(lf, F_NOSTAM)) { pen = gettempstammod(lf, temp); if (pen != 100) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " %d%% stamina usage due to heat.",pen); } } if (!lfhasflag(lf, F_NOSLEEP) && (temp >= T_HOT)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " Chance of waking from sleep due to heat."); } if (temp >= T_HOT) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, " Reduced healing rate due to heat."); } } } } // 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) { char thisline[BIGBUFLEN]; char desc[BUFLEN]; if (nfound == 0) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s the following spells active:", you(lf), isplayer(lf) ? "have" : "has"); } snprintf(thisline, BIGBUFLEN, " - %s %s (consuming %d MP", sp->name, roman(f->val[2]), f->val[1]); getspelldesc(f->val[0], f->val[2], desc); if (strlen(desc)) { strcat(thisline, ", "); strcat(thisline, desc); } strcat(thisline, ")"); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s", thisline); nfound++; } } } //if (nfound) // obvious physical effects first. f = lfhasknownflag(lf, F_BEINGSTONED); if (f) { getflagsourcetext(f, source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s being turning to stone.%s", you(lf), is(lf), source); } if (eyesshaded(lf)) { getflagsourcetext(f, source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s eyes are shaded%s.", your(lf), buf, source); } f = lfhasflag(lf, F_FLAMMABLELF); if (f) { getflagsourcetext(f, source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s covered in %s.%s", you(lf), is(lf), f->text, source); } f = hasflag(lf->race->flags, F_SIZE); if (f) { getflagsourcetext(f, source); racesize = f->val[0]; } else { strcpy(source, ""); racesize = SZ_HUMAN; // default } cursize = getlfsize(lf); if (cursize != racesize) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s body has been magically %s.%s", your(lf), (cursize > racesize) ? "enlarged" : "shrunken", source); } // show racial effects if (hasjob(lf, J_PIRATE)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can hold %s liquor well. (%s)", you(lf), isplayer(lf) ? "Your" : "its", getsourcetext(FROMJOB)); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s missing one eye. (%s)", you(lf), is(lf), getsourcetext(FROMJOB)); } if (hasjob(lf, J_DRUID)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s spell power is boosted by nearby plants. (%s)", isplayer(lf) ? "Your" : "Its", getsourcetext(FROMJOB)); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s regenerate mana when plants are nearby. (%s)", you(lf), getsourcetext(FROMJOB)); } // if the PLAYER knows the time... if (lfhasflag(player, F_KNOWSTIME)) { enum TIMEPHASE tp; tp = gettimephase(); if ((tp == TP_TWILIGHTMORN) || (tp == TP_SUNRISE)) { if (getskill(lf, SK_SS_LIFE)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The power of %s Life magic is currently boosted because it is %s.", your(lf), gettimephasename(tp)); } } else if (tp == TP_MIDNIGHT) { if (getskill(lf, SK_SS_DEATH)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The power of %s Death magic is currently boosted because it is %s.", your(lf), gettimephasename(tp)); } } } if (lfhasflag(lf, F_CANCAST)) { int chance; chance = getmiscastchance(lf); if (chance) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s spells have a %d%% chance of failing due to cumbersome armour.", your(lf), chance); } } // show boosts to spell power if (showall) { // note: same code as in getspellpower() enum SPELLSCHOOL school[5]; int nschools = 5; school[0] = SS_WILD; school[1] = SS_MENTAL; school[2] = SS_NATURE; school[3] = SS_LIFE; school[4] = SS_ALLOMANCY; for (i = 0; i < nschools; i++) { enum ATTRIB att = A_NONE; int n,found = B_FALSE; // can you cast any spells from this school? getflags(lf->flags, retflag, &nretflags, F_CANCAST, F_CANWILL, F_NONE); for (n = 0; n < nretflags; n++) { enum SPELLSCHOOL thisschool; thisschool = getspellschool(retflag[n]->val[0]); if (thisschool == school[i]) { found = B_TRUE; break; } } if (found) { int mod; enum RACE godid = R_NONE; mod = getspellpowerstatmod(lf, school[i], &att); if (mod) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s %s will %s the power of %s %s by %d.", your(lf), (mod > 0) ? "high" : "low", getattrname(att), (mod > 0) ? "boost" : "lower", (school[i] == SS_WILD) ? "arcane" : (school[i] == SS_MENTAL) ? "Psionic" : getschoolname(school[i]), (school[i] == SS_MENTAL) ? "disciplines" : "spells", abs(mod) ); } // boosted by god? mod = getspellpowergodmod(lf, school[i], &godid); if (mod > 0) { lifeform_t *god; god = findgod(godid); if (god) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s is boosting the power of %s spells by %d.", god->race->name, your(lf), mod); } } } // end if found } // end foreach school } // 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)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s deaf.", you(lf), is(lf)); } f = hasflag_real(lf->flags, F_ENHANCESMELL, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s an enhanced sense of smell.%s", you(lf), isplayer(lf) ? "have" : "has", source); } f = lfhasknownflag(lf, F_DISEASEIMMUNE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s immune to disease.%s", you(lf), is(lf), source); } f = hasflag_real(lf->flags, F_HEAVYBLOW, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); snprintf(buf, BUFLEN,"%s%s attacks knock enemies back.%s", you(lf), getpossessive(you(lf)), source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, buf); } 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"); } getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s regenerate%s health%s.%s", you(lf),isplayer(lf) ? "" : "s", regenspeed, source); } f = lfhasknownflag(lf, F_RESISTMAG); if (f) { int mr; char adjective[BUFLEN]; mr = getmr(lf); if (mr <= 10) { strcpy(adjective, "very slightly"); } else if (mr <= 20) { strcpy(adjective, "slightly"); } else if (mr <= 30) { strcpy(adjective, "somewhat"); } else if (mr <= 40) { strcpy(adjective, "moderately"); } else if (mr <= 50) { strcpy(adjective, "quite"); } else if (mr <= 60) { strcpy(adjective, "highly"); } else if (mr <= 70) { strcpy(adjective, "very highly"); } else if (mr <= 80) { strcpy(adjective, "extremely"); } else if (mr <= 90) { strcpy(adjective, "incredibly"); } else if (mr < 100) { strcpy(adjective, "almost completely"); } else { // ie. 100 upwards strcpy(adjective, "completely"); } getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s %s resistant to magic.%s", you(lf), is(lf), adjective,source); } f = hasflag_real(lf->flags, F_FEARLESS, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s immune to the effects of fear.%s", you(lf), is(lf), source); } f = hasflag_real(lf->flags, F_FASTMETAB, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s metabolic rate has been increased.%s", your(lf), getpossessive(you(lf)), source); } f = hasflag_real(lf->flags, F_TREMORSENSE, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can 'see' by sensing vibrations around %s.%s", you(lf), you(lf),source); } f = hasflag_real(lf->flags, F_SEEINDARK, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can see in the dark.%s", you(lf),source); if (f->val[1] == B_BLINDABLE) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Bright lights will blind %s.%s", isplayer(lf) ? "you" : "it",source); } } f = hasflag_real(lf->flags, F_SEEINVIS, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can see invisible things.%s", you(lf),source); } f = hasflag_real(lf->flags, F_SHADOWED, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s hidden from distant creatures.%s", you(lf), is(lf),source); } f = hasflag_real(lf->flags, F_SPIDERCLIMB, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s adhesive skin allows you to climb walls.%s", your(lf), isplayer(lf) ? "you" : "it", source); } f = hasflag_real(lf->flags, F_SIXTHSENSE, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s will be warned about nearby enemies.%s", you(lf),source); } f = hasflag_real(lf->flags, F_STABILITY, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s will not fall on slippery ground.%s", you(lf),source); } // only show eating habits if not inherited from race f = hasflag_real(lf->flags, F_CARNIVORE, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s a carnivore (will not eat non-meat products).%s", you(lf), is(lf), source); } f = hasflag_real(lf->flags, F_VEGETARIAN, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s a vegetarian (will not eat meat).%s", you(lf), is(lf),source); } f = hasflag_real(lf->flags, F_PARTVEGETARIAN, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s a part vegetarian (will only eat meat when hungry).%s", you(lf), is(lf), source); } f = hasflag_real(lf->flags, F_VISRANGEMOD, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s vision range has been %s.%s", your(lf), (f->val[0] > 0) ? "increased" : "decreased", source); } f = hasflag_real(lf->flags, F_NIGHTVISRANGEMOD, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s night vision range has been %s.%s", your(lf), (f->val[0] > 0) ? "increased" : "decreased", source); } f = hasflag_real(lf->flags, F_XRAYVIS, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can see through walls.%s", you(lf), source); } 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) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can see through %s.%s", you(lf), m->name,source); } } } // 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"); } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "It looks %s.", moralebuf); } // 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 && !isimmuneto(lf->flags, i, B_TRUE)) { 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) && (f->lifetime > 0)) { char buf3[BUFLEN]; snprintf(buf3, BUFLEN, "[%dt]",f->lifetime); strcat(buf2, buf3); } } strcat(buf, buf2); } } } if (strlen(buf) > 0) { strcat(buf, ".\n"); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, 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"); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, 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"); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, buf); } // material vulnerabilities getflags(lf->flags, retflag, &nretflags, F_MATVULN, F_NONE); for (i = 0; i < nretflags; i++) { material_t *mt; f = retflag[i]; mt = findmaterial(f->val[0]); if (mt) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s take%s %d%% damage from %s weapons.%s", you(lf), isplayer(lf) ? "" : "s", f->val[1], mt->name,source); if (f->val[2] > 0) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Touching %s objects will hurt %s (%d dam).", mt->name, you(lf), f->val[2]); } } } } if (showall || (lorelev >= PR_BEGINNER) || (getskill(player, SK_SPEECH) >= PR_ADEPT)) { // 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 = strdup(ot->name); makeplural(&pname); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "It %s %s.", (f->val[1] == B_COVETS) ? "covets" : "wants", pname); 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 } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "It %s %s.", (f->val[1] == B_COVETS) ? "covets" : "wants", what); } else if (f->id == F_WANTSBETTERWEP) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "It %s better weapons.", (f->val[1] == B_COVETS) ? "covets" : "wants"); } else if (f->id == F_WANTSBETTERARM) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "It %s better armour.", (f->val[1] == B_COVETS) ? "covets" : "wants"); } } } } // show intrinsics f = lfhasknownflag(lf, F_ARBOOST); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s Armour Rating is being magically %s.%s", your(lf), (f->val[0] >= 0) ? "boosted" : "reduced",source); } f = lfhasknownflag(lf, F_ATTRSET); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s has been modified.%s", your(lf), getattrname(f->val[0]),source); } else { f = lfhasknownflag(lf, F_ATTRMOD); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s has been %s.%s", your(lf), getattrname(f->val[0]), (f->val[1] > 0) ? "increased" : "decreased",source); } } if (lfhasknownflag(lf, F_ANONYMOUS)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s identity is obscured.%s", your(lf),source); } f = hasflag_real(lf->flags, F_AUTOTANGLE, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s a %d%% chance to automatically entangle enemies.%s", you(lf), isplayer(lf) ? "have" : "has", f->val[0], source); } f = hasflag_real(lf->flags, F_AWARENESS, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can see things which are behind %s.%s", you(lf), you(lf), source); } f = hasflag_real(lf->flags, F_DODGES, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s will automatically use %s remaining stamina to dodge fatal attacks.%s", you(lf), your(lf), source); } getflags(lf->flags, retflag, &nretflags, F_LEARNBOOST, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; if (f && f->known) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s have a %d%% %s to earned experience points.%s", you(lf), f->val[0], (f->val[0] > 0) ? "bonus" : "penalty",source); } } f = lfhasknownflag(lf, F_MAGICARMOUR); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 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).%s",f->val[0],source); } else { wprintw(mainwin, ".%s",source); } } f = lfhasknownflag(lf, F_MAGICBOOST); if (f && (f->known)) { int boost; getflagsourcetext(f,source); sumflags(lf->flags, F_MAGICBOOST, &boost, NULL, NULL); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The power of %s spells is boosted by %d.%s", isplayer(lf) ? "your" : "its", boost,source); } f = lfhasknownflag(lf, F_TEMPMAGICBOOST); if (f && (f->known)) { int boost; sumflags(lf->flags, F_TEMPMAGICBOOST, &boost, NULL, NULL); getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "The power of %s next spell will be boosted by %d.%s", isplayer(lf) ? "your" : "its", boost,source); } f = lfhasknownflag(lf, F_MINCRITCHANCE); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s attacks are guided by the gods, granting a minimum %d%% criticial hit chance.%s", your(lf), f->val[0],source); } f = lfhasknownflag(lf, F_MINDSHIELD); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s are protected from psionic attacks.%s", you(lf),source); } f = lfhasknownflag(lf, F_MISCASTCHANCE); if (f && (f->known)) { int chance; getflagsourcetext(f,source); sumflags(lf->flags, F_MISCASTCHANCE, &chance, NULL, NULL); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s spells have a %d%% chance of failure.%s", isplayer(lf) ? "Your" : "Its", chance, source); } f = lfhasflag(lf, F_OMNIPOTENT); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s are omnipotent.%s", you(lf), source); } f = isblind(lf); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s cannot see.%s", you(lf), source); } 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); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, buf); } f = lfhasknownflag(lf, F_BREATHWATER); if (!f) f = lfhasknownflag(lf, F_AQUATIC); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can breath normally while underwater.%s", you(lf),source); } f = lfhasknownflag(lf, F_CONTROL); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can control teleportation and polymorphic effects.%s", you(lf),source); } f = lfhasknownflag(lf, F_CONFUSED); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s confused.%s", you(lf), is(lf),source); } f = lfhasknownflag(lf, F_CONSUMESOULS); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s can consume souls of those who die nearby.%s", you(lf),source); } f = lfhasknownflag(lf, F_DETECTAURAS); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s automatically detect blessings or curses.%s", you(lf),source); } f = lfhasknownflag(lf, F_DETECTLIFE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s automatically detect %snearby lifeforms.%s", you(lf), (f->val[1] == B_TRUE) ? "" : "the size of ",source); } f = lfhasknownflag(lf, F_DETECTMAGIC); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s automatically detect magical enchantments on objects.%s", you(lf),source); } f = lfhasknownflag(lf, F_DETECTMETAL); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s automatically detect nearby metal.%s", you(lf),source); } f = lfhasknownflag(lf, F_DETECTOBS); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s automatically detect nearby objects.%s", you(lf),source); } f = lfhasknownflag(lf, F_ENHANCESEARCH); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s searching ability is enhanced.%s", you(lf), isplayer(lf) ? "Your" : "Its",source); } f = lfhasknownflag(lf, F_DRUNK); if (f) { char ddesc[BUFLEN]; getflagsourcetext(f,source); getdrunkdesc(lf, f, ddesc); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s %s (%s).%s", you(lf), is(lf), getdrunktext(f), ddesc,source); } getflags(lf->flags, retflag, &nretflags, F_EXTRADAM, F_WOUNDING,F_NONE); for (i = 0; i < nretflags; i++) { if (showall || f->known) { int ndice,nsides,bonus; char dicebuf[BUFLEN]; char mmbuf[BUFLEN]; char damtypebuf[BUFLEN]; int min = 0,max = 0; f = retflag[i]; if (f->id == F_EXTRADAM) { if (f->val[2] == NA) { texttodice(f->text, &ndice,&nsides,&bonus); } else { ndice = 0; nsides = 1; bonus = f->val[2]; } 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])); } } else { // ie. f_wounding ndice = 0; nsides = 1; bonus = f->val[0]; strcpy(damtypebuf, "damage"); } getflagsourcetext(f,source); dicetotext(ndice, nsides, bonus, &min, &max, dicebuf, mmbuf); if (strcmp(dicebuf, mmbuf)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s deal%s %s (%s) extra %s each hit.%s", you(lf), isplayer(lf) ? "" : "s", dicebuf, mmbuf, damtypebuf,source); } else { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s deal%s %s extra %s each hit.%s", you(lf), isplayer(lf) ? "" : "s", dicebuf, damtypebuf,source); } } } f = lfhasflag(lf, F_EXTRALUCK); if (f) { 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; } getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s %slucky.%s", you(lf), is(lf), luckamt,source); } } f = lfhasknownflag(lf, F_EXTRAMP); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Your mana pool is being boosted.%s", you(lf),source); } f = lfhasknownflag(lf, F_EXTRAINFO); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s receive enhanced knowledge about the world.%s", you(lf),source); } for (f = lf->flags->first ; f ; f = f->next ){ if (f->known && (f->id == F_POISONED)) { int knownfatal = B_FALSE; poisontype_t *pt; pt = findpoisontype(f->val[0]); if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) { if (poisonthreatenslife(lf, f)) { knownfatal = B_TRUE; } } if (pt->id == P_LYCANTHROPY) { snprintf(buf, BUFLEN, "%s %s afflicted with %s.", you(lf), is(lf), pt->name); } else { snprintf(buf, BUFLEN, "%s %s sick with %s%s.", you(lf), is(lf), pt->name, knownfatal ? ", potentially fatally" : ""); } if (pt->severity != PS_CURSE) { 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); } } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, buf); } if (f->known && (f->id == F_INCUBATING)) { poisontype_t *pt; pt = findpoisontype(f->val[0]); if (pt->id == P_LYCANTHROPY) { snprintf(buf, BUFLEN, "%s %s afflicted with early onset %s.", you(lf), is(lf), pt->name); } else { snprintf(buf, BUFLEN, "%s %s incubating %s.", you(lf), is(lf), pt->name); } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, buf); } } f = lfhasflag(lf, F_MUTABLE); if (f && (f->known)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s body is receptive to mutations.", your(lf), isplayer(lf) ? "is" : "are"); } f = lfhasflag(lf, F_NAUSEATED); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s nauseated.%s", you(lf), is(lf),source); } f = lfhasknownflag(lf, F_HOLYAURA); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s surrounded by a holy aura.%s", you(lf), is(lf),source); } f = lfhasknownflag(lf, F_HOLYTOUCH); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Any object %s weild%s will be temporarily blessed.%s", you(lf), isplayer(lf) ? "" : "s",source); } f = lfhasknownflag(lf, F_HOTFEET); if (f) { getflagsourcetext(f,source); msg("%s feet are on fire (%s %s damage per turn stationary).%s",your(lf), f->val[0], getdamnamenoun(f->val[1]),source); } f = lfhasknownflag(lf, F_ICESLIDE); if (f) { getflagsourcetext(f,source); msg("%s feet automatically generating sheets of ice.%s",your(lf),source); } f = lfhasknownflag(lf, F_FREEZINGTOUCH); if (f && (f->known)) { getflagsourcetext(f,source); 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); } effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s%s",buf,source); } f = lfhasflag(lf, F_GRAVBOOSTED); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Gravity is increased around %s.%s", you_l(lf),source); } f = lfhasflag(lf, F_GRAVLESSENED); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Gravity is lessened around %s, preventing fall damage, increasing flight speed and reducing load.%s", you_l(lf),source); } f = lfhasknownflag(lf, F_FULLSHIELD); if (f && (f->known)) { object_t *sh; char obname[BUFLEN]; sh = hasobid(lf->pack, atol(f->text)); getobname(sh, obname, 1); getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s fully shielded by %s %s.%s", you(lf), is(lf), your(lf), obname,source); } f = lfhasknownflag(lf, F_HEAVENARM); if (f && (f->known)) { char hpbuf[BUFLEN]; if (isplayer(lf)) { sprintf(hpbuf, " (%d hp left)", f->val[0]); } else { strcpy(hpbuf, ""); } getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s surrounded by a %s. %s%s", you(lf), is(lf), f->text, hpbuf,source); } f = lfhasknownflag(lf, F_INVULNERABLE); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s protected from all physical harm.%s", you(lf), is(lf),source); } f = lfhasflag(lf, F_MAGSHIELD); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s surrounded by a magnetic shield.%s", you(lf), is(lf),source); } f = lfhasflag(lf, F_PAIN); if (f && (f->known)) { getflagsourcetext(f,source); if (lfhasflag(lf, F_DRUNK)) { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s in extreme pain, somewhat mitigated by %s inebriation.%s", you(lf), is(lf), isplayer(lf) ? "Your" : "its",source); } else { effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s in extreme pain, and movement will cause %s damage.%s", you(lf), is(lf), isplayer(lf) ? "You" : "it",source); } } f = lfhasflag(lf, F_PARALYZED); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s paralyzed.%s", you(lf), is(lf),source); } f = hasflag_real(lf->flags, F_PHOTOMEM, NA, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s do not forget your surroundings.%s", you(lf),source); } f = hasflag_real(lf->flags, F_PLANTFRIEND, NA, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Plants are friendly towards %s.%s", you(lf),source); } f = hasflag_real(lf->flags, F_POLYIMMUNE, NA, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s cannot be polymorphed.%s", you(lf),source); } f = hasflag_real(lf->flags, F_PROTALIGN, NA, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s protected from attacks by %s-aligned creatures.%s", you(lf), is(lf), getalignmentname(f->val[1]),source); } f = lfhasflag(lf, F_RAGE); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s enraged, gaining accuracy, damage and hit point bonuses.%s", you(lf), is(lf),source); } f = lfhasflag(lf, F_REFLECTION); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s surrounded by a negative gravity field.%s", you(lf), is(lf),source); } f = lfhasknownflag(lf, F_TRUESTRIKE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s%s attacks will automatically hit.%s", you(lf), getpossessive(you(lf)),source); } f = lfhasknownflag(lf, F_WINDSHIELD); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), is(lf)); if (isplayer(lf)) { wprintw(mainwin, " (power %d).%s",roman(f->val[0]),source); } else { wprintw(mainwin, ".%s",source); } } f = lfhasflag(lf, F_RISEASGHOST); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s will rise as a ghost after death.%s", you(lf),source); } f = hasflag_real(lf->flags, F_STASIS, B_TRUE, NULL, FROMRACE); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "Time within your body has been frozen.%s", you(lf),source); } f = hasflag_real(lf->flags, F_STAMBOOST, B_TRUE, NULL, FROMRACE); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s stamina is currently being boosted.%s", your(lf),source); } f = hasflag_real(lf->flags, F_STENCH, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s emitting a foul stench, nauseating those nearby.%s", you(lf), is(lf),source); } f = hasflag_real(lf->flags, F_UNDEAD, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s have been rendered undead.%s", you(lf),source); } f = hasflag_real(lf->flags, F_SILENCED, B_TRUE, NULL, FROMRACE); if (f) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s been magically silenced.%s", you(lf), isplayer(lf) ? "have" : "has", source); } f = lfhasflag(lf, F_STRIKETOKO); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s attacking in a non-lethal manner.%s", you(lf), is(lf),source); } f = lfhasflag(lf, F_STUNNED); if (f && (f->known)) { getflagsourcetext(f,source); effectline(&stopnow, &count, offset, &nextoffset, headinglines, mainwin, &y, &x, 0, "%s %s stunned and cannot attack, cast spells or use abilities.%s", you(lf), is(lf),source); } } else if (mode == 'i') { object_t *o; cls(); wattron(mainwin, A_UNDERLINE); if (lf == player) { // mindscanning it centre(mainwin, C_WHITE, 0, "INVENTORY"); } else { // not mindscanning centre(mainwin, C_WHITE, 0, "INVENTORY (equipped items only)"); } wattroff(mainwin, A_UNDERLINE); y = headinglines; 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, headinglines, &nextoffset)) { nextoffset += offset; break; } } } } else { mvwprintw(mainwin, y, 0, "It is not carrying anything."); } } else if (mode == 'g') { int i; char line[BUFLEN]; cls(); wattron(mainwin, A_UNDERLINE); centre(mainwin, C_WHITE, 0, "GODS"); wattroff(mainwin, A_UNDERLINE); y = headinglines; snprintf(line, BUFLEN, "%-29s Worship? %-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; int blocked = B_FALSE; god = godlf[i]; if (!god) continue; blocked = godblocked(god->race->id); real_getlfname(god, godname, NULL, B_SHOWALL, B_REALRACE); f = lfhasflag(god, F_GODOF); strcat(godname, " ("); strcat(godname, f->text); strcat(godname, ")"); if (lfhasflag(god, F_PRAYEDTO)) { prayedto = B_TRUE; } piety = getpiety(god->race->id); if (blocked) { col = C_RED; strcpy(happiness, "Exiled"); } else { plev = getpietylev(god->race->id, &col, happiness); } // construct piety buf [---+--|--------------------] snprintf(pietybuf, BUFLEN, "%s[", blocked ? "" : "^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_DARKYELLOW: strcpy(colbuf, "^b"); break; case C_GREEN: strcpy(colbuf, "^g"); break; case C_LIGHTGREEN: strcpy(colbuf, "^G"); break; case C_LIGHTCYAN: 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 (blocked) { strcat(pietybuf, " "); } else if ((piety >= n) && (piety < n+25)){ strcat(pietybuf, "+"); } else { strcat(pietybuf, "-"); } } if (blocked) { strcat(pietybuf, "]"); } else { strcat(pietybuf, "^n]"); } snprintf(line, BUFLEN, "%s%s%-30s%-9s%s %s%s", blocked ? "^B" : "", // whole line is red if this god is blocked blocked ? "" : prayedto ? "^g" : "^n", godname, blocked ? " N/A " : prayedto ? " Yes " : " No ", pietybuf, colbuf, happiness); wmove(mainwin, y, 0); textwithcol(mainwin, line); y++; } } // display the prompt if (isplayer(lf) || showall) { snprintf(promptstr, BUFLEN, "^h[^W@^n=stats ^WS^nkills ^WA^nbils ^WM^nagic ^WE^nffects %s%s ^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, "^WM^nagic "); strcat(promptstr, buf); strcat(cmdchars, "m"); } snprintf(buf, BUFLEN, "^WESC^n=quit]"); strcat(promptstr, buf); } switch (mode) { case 'g': // help on gods case 's': // help on skills case '@': // help on current race strcat(cmdchars, "?"); default: break; } // are there other pages to go to (or go back to)? strcpy(navstr, ""); if (nextoffset) { strcat(cmdchars, "']}"); if (offset) { strcat(cmdchars, "[{"); } snprintf(buf, BUFLEN, "^W'^n=next page %s^W]^n=forward %s^W}^n=pgdn", (offset) ? "^W[^n=back " : "", (offset) ? "^W{^n=pgup " : ""); strncat(navstr, buf, BUFLEN); } else if (offset) { strcat(cmdchars, "'[{"); snprintf(buf, BUFLEN, "^W'^n=back to start ^W[^n=back ^W{^n=pgup"); strncat(navstr, buf, BUFLEN); } if (strlen(navstr)) { centre(mainwin, C_GREY, h-3, "(%s)", navstr); } if (strchr(cmdchars, '?')) { centre(mainwin, C_MAGENTA, 1, "[Press ? for a full description]"); } centre(mainwin, C_WHITE, h-1, promptstr); // wait for key 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; offset = 0; nextoffset = 0; break; case '\'': // go to next page, or back to start if (nextoffset) { offset = nextoffset; } else { offset = 0; } break; case ']': // go forward one line offset++; break; case '[': // go back one line offset--; break; case '}': // go forward one page offset += 18; limit (&offset, NA, nextoffset); break; case '{': // go back one page offset -= 18; limit (&offset, 0, NA); 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 showpath(lifeform_t *lf) { flag_t *f; char buf[BUFLEN]; cell_t *c; real_getlfname(lf, buf, NULL, B_SHOWALL, B_CURRACE); cls(); wmove(mainwin, 0, 0); f = lfhasflag(lf, F_AIPATH); wprintw(mainwin, "flagtext is: [%s]\n", f->text); wprintw(mainwin, "Path for %s (%d,%d -> %d,%d) is:\n", buf, lf->cell->x, lf->cell->y, f->val[0], f->val[1]); c = ai_getnextcellinpath(lf); while (c) { wprintw(mainwin, "%d,%d ->\n", c->x, c->y); ai_popnextcellinpath(lf); c = ai_getnextcellinpath(lf); } wprintw(mainwin, "END. (press key to exit)"); getch(); restoregamewindows(); } void startpathfind(void) { cell_t *c = NULL; c = askcoords("Go to where?", "Goto->", TT_NONE, player, UNLIMITED, LOF_DONTNEED, B_FALSE); if (!c) { msg("Cancelled."); return; } if (!c->known || (c->map != player->cell->map) || (haslos(player, c) && !cellwalkable(player, c, NULL))) { msg("You don't know how to get there."); return; } // try to find path. if (ai_createpathto(player, c)) { addflag(player->flags, F_PATHFINDING, c->x, c->y, player->cell->map->id, NULL); } else { msg("You don't know how to get there."); } } 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; flag_t *winflag; winflag = lfhasflag(player, F_WINNER); playerscore = calcscore(lf); getplayernamefull(pname); // clear screen cls(); y = 1; if (wintype) { centre(mainwin, C_GREY, y, "CONGRATULATIONS!"); y+= 2; } else { 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 (wintype) { y++; } else { getregionname(buf, player->cell->map, NULL, RF_LONG); centre(mainwin, C_GREY, y, "Died %s.", buf); y++; // ie. "Died on level 1 of the dungeon" } makekillertext(killer, lf->killverb, lf->lastdam, lf->cell->map, B_TRUE, B_FALSE); 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) { // -1 means 'cheating' mvwprintw(mainwin, y, 0, "Since you were cheating, your score will not be listed."); y++; minrank = 1; maxrank = 10; } else if ((rank == -2) || (rank > 100)) { // -2 means 'no points' mvwprintw(mainwin, y, 0, "Your score of %ld didn't make the top 100 list.", playerscore); y++; minrank = 1; maxrank = 10; } else { setcol(mainwin, C_LIGHTGREEN); mvwprintw(mainwin, y, 0, "You made rank #%d on the high score table!", rank); y++; unsetcol(mainwin, C_LIGHTGREEN); minrank = rank - 4; maxrank = rank + 4; limit(&minrank, 0, NA); limit(&maxrank, NA, 100); } centre(mainwin, C_GREY, y, "High Scores"); y++; wattron(mainwin, A_BOLD); mvwprintw(mainwin, y, 0, HISCOREFORMAT, "Pos", "Score", "Name", "Job"); wprintw(mainwin, "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(); } int warnabout(char *what) { return real_warnabout(what, DEF_WARNINGTIME, B_TRUE); } // // returns TRUE if you answered 'Yes' or you'd already accepted this warning // int real_warnabout(char *what, int lifetime, int doquestion) { char ch = 'n'; warning_t *w; // have we already warned about this? w = findwarning(what); if (w) { // if so, just update the existing warning's lifetime w->lifetime = lifetime; ch = 'y'; return B_TRUE; } else if (doquestion) { char ques[BUFLEN]; sprintf(ques, "%s", what); ch = askchar(what, "yn", "n", B_TRUE, B_FALSE); } else { more(); msg("%s", what); more(); ch = 'y'; } if (ch == 'y') { // accepted the warning. add it to the list. addwarning(what, lifetime); return B_TRUE; } return B_FALSE; } void wingame(void) { flag_t *winflag; winflag = lfhasflag(player, F_WINNER); if (winflag->val[0] == WT_DEMIGOD) { lifeform_t *god; // find the god who ascended us. god = findgod(winflag->val[1]); // god says something switch (god->race->id) { case R_GODPURITY: msg("Amberon flings the Godstone out into the cosmos!\""); more(); msg("\"Without the chaotic blight of this stone, the universe will be purified!\""); more(); msg("\"Deformities will be cured, chance eliminated, entropy denied.\""); more(); msg("\"From now on, all will be orderly and just.\""); more(); msg("\"I name you the Arbiter of Divine Justice!\""); more(); break; case R_GODTHIEVES: msg("Felix slips the Godstone into a pocket."); more(); msg("\"By bringing this stone to me, you have brought closure to thousands.\""); more(); msg("\"Every act of anger, every stolen penny, every wronged lover...\""); more(); msg("\"No more shall they be told to simply 'forgive and forget'!\""); more(); msg("\"All shall obtain their revenge!\""); more(); msg("\"I name you the Hand of Veangence!\""); more(); break; case R_GODDEATH: msg("A sinister smile spreads across Hecta's skull."); more(); msg("\"With this artifact, I will annihilate all living beings!\""); more(); msg("\"All souls throughout the universe shall become my servants!\""); more(); msg("\"And you, fleshling...\""); more(); msg("\"For your service, I name you my High Prince of the Dead!\""); more(); msg("\"HAHAHahahahahahaha...\""); more(); break; case R_GODFIRE: msg("Klikirak's flames explode outwards in a surge of triumphant fury!"); more(); msg("\"NO CREATION! NO PLANTS! NO MORE GROWING!\""); more(); msg("\"JUST FIRE! BURN! DESTROY! ANNIHILATE!\""); more(); msg("\"OBLITERATE!!!!!\""); more(); break; case R_GODLIFE: msg("Glorana's pulsating form melds into a female face, her eyes wide in shock."); more(); msg("\"The Godstone of Death! You have brought it to me!\""); more(); msg("\"Your efforts have earned eternal life for all humanity!\""); more(); msg("\"Such an action deserves the highest possibble reward.\""); more(); msg("\"Join me, as the Bringer of Life!\""); more(); break; case R_GODMERCY: msg("Yumi beams radiantly at you."); more(); msg("\"You do not know just how special this stone is.\""); more(); msg("\"Without petty acts of revenge and jealousy, there will be peace.\""); more(); msg("\"From the kindest soul, to the lowest criminal, all will know forgiveness.\""); more(); msg("\"Rise up, and spread mercy as Mankind's Redemption.\""); more(); break; case R_GODNATURE: msg("Ekrub gazes at the Godstone in awe."); more(); msg("\"An end to burning... an end to destruction...\""); more(); msg("\"All of nature's creations can finally grow in peace!\""); more(); msg("\"As my children shall thrive, so shall you.\""); more(); msg("\"I name you Nature's Soulmate!\""); more(); break; case R_GODBATTLE: msg("Bjorn cleaves the Godstone with a might stroke of his battleaxe!\""); more(); msg("\"You have won a great victory today, soldier.\""); more(); msg("\"With this power, I will rally all existence for the final battle.\""); more(); msg("\"No magic will interfere - might and battle tactics will win the day.\""); more(); msg("\"For your valour, I promote you to General of the Gods!\""); more(); break; case R_GODMAGIC: msg("Lumara's aging features begin to change, the years falling away in seconds.\""); more(); msg("Soon, an energised young woman stands before you.\""); more(); msg("\"You have done it!\""); more(); msg("\"The cosmic forces are already being renewed with infinite potential!\""); more(); msg("\"Henceforce all shall weild magic as easily as breathing.\""); more(); msg("\"All restraints will be lifted, actions limited only by imagination!\""); more(); msg("\"I name you the Font of Wizardry, the Arcane Grandmaster...\""); more(); msg("\"The Connoisseur of the Cosmos!\""); more(); break; default: break; } msg("^%cYou ascend to a higher plane of existence as a demi-god!^n", getlfcol(player, CC_VGOOD)); more(); msg("^%cCONGRATULATIONS!!!^n", getlfcol(player, CC_VGOOD)); more(); } else { // ie. WT_GOD, killed a god int i; char *buf; enum RACE opposeid; lifeform_t *god[MAXGODS],*g; int ngods = 0; flag_t *tempflag[2]; opposeid = getopposinggod(winflag->val[1]); msg("As you vanquish your foe, a sudden stillness descends."); more(); msg("For a brief moment, all is quiet."); more(); msg("Then, there is an almighty clap of thunder and a brilliant flash of light!"); more(); // make sure the player sees the gods appearing tempflag[0] = addflag(player->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); tempflag[1] = addflag(player->flags, F_CANSEETHROUGHLF, B_TRUE, NA, NA, NULL); setlosdirty(player); for (i = 0; i < ngodlfs; i++) { g = godlf[i]; if (!g) continue; godappears(g->race->id, NULL); god[ngods++] = g; } needredraw = B_TRUE; drawscreen(); g = god[rnd(0,ngods-1)]; say(g, "You have just done the unthinkable.", SV_TALK); more(); g = god[rnd(0,ngods-1)]; say(g, "You have killed a god!", SV_TALK); more(); g = findgod(R_GODTHIEVES); if (g) { say(g, "This act cannot go unpunished!", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "Felix would have insisted on punishment.", SV_TALK); more(); } g = findgod(R_GODMERCY); if (g) { say(g, "Although this seems unforgivable, we should always strive for mercy.", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "Yumi would have wanted mercy to be given.", SV_TALK); more(); } g = findgod(R_GODMAGIC); if (!g) g = god[rnd(0,ngods-1)]; say(g, "The cosmos works in mysterious ways.", SV_TALK); more(); g = findgod(R_GODBATTLE); if (g) { say(g, "The kill was through honourable battle!", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "We all knew this was a possibility.", SV_TALK); more(); } // nature g = findgod(R_GODNATURE); if (g) { say(g, "This is the cycle of life, nothing more. What lives must die.", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "Ekrub has withered, as all nature must do eventually.", SV_TALK); more(); } // fire g = findgod(R_GODFIRE); if (g) { say(g, "MIGHTY GOD DESTROYED!", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "The fires of destruction have been quenched.", SV_TALK); more(); } // life g = findgod(R_GODLIFE); if (g) { say(g, "To take any life is abhorrent... but that of a god?", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "The Goddess of Life destroyed? How can this be?", SV_TALK); more(); } g = findgod(R_GODDEATH); if (g) { say(g, "The fleshling has given me a monumental gift.", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "Had it been one of us, Hecta would exultant now.", SV_TALK); more(); } g = findgod(R_GODPURITY); if (g) { say(g, "Nevertheless, there is now an impurity within our ranks.", SV_TALK); more(); } else { g = god[rnd(0,ngods-1)]; say(g, "It would seem there is a new vacancy within our ranks.", SV_TALK); more(); } // don't want the opposing god of the killed one responding g = god[rnd(0,ngods-1)]; while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; say(g, "The one before us is obviously ambitious.", SV_TALK); more(); g = god[rnd(0,ngods-1)]; while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; say(g, "He has clearly proven his power.", SV_TALK); more(); g = god[rnd(0,ngods-1)]; while (g->race->id == opposeid) g = god[rnd(0,ngods-1)]; say(g, "Are we agreed, then?", SV_TALK); more(); // the opposing god will always disagree and storm off // in a huff. g = findgod(opposeid); switch (g->id) { case R_GODPURITY: say(g, "You fools would bring back Chaos?!", SV_SHOUT); more(); msg("\"I will not be part of this!\""); more(); break; case R_GODTHIEVES: say(g, "NO! Do not spoil my revenge by replacing her!", SV_SHOUT); more(); break; case R_GODDEATH: say(g, "Fools. Replace her if you wish, it will change nothing.", SV_SHOUT); more(); break; case R_GODFIRE: say(g, "NOOOO! WHY NATURE NEVER STOP REGROWING?!", SV_SHOUT); more(); break; case R_GODLIFE: say(g, "It would seem that somehow death will result in life...", SV_TALK); more(); msg("\"I must consider this.\""); more(); break; case R_GODMERCY: say(g, "\"How dare you!\"", SV_SHOUT); more(); msg("\"I show you mercy and you repay it by becoming my greatest rival?!\""); more(); break; case R_GODNATURE: say(g, "\"TRAITOR!\"", SV_SHOUT); more(); msg("\"I vowed to support you, but you know this is not what I meant!\""); more(); break; case R_GODBATTLE: say(g, "\"Not again! Magic was meant to be destroyed!\"", SV_SHOUT); more(); msg("\"Is there no end to the foul trickeries of magic?\""); more(); break; case R_GODMAGIC: say(g, "\"One has decided. Time will determine the wisdom of One's choice.\"", SV_TALK); more(); break; } // calling "unsommon" will technically kill // the god, but since the game is about to end it doesn't // really matter. unsummon(g, B_TRUE); msg("The remaining gods nod in unison."); more(); g = god[rnd(0,ngods-1)]; say(g, "Arise then, and join us!", SV_TALK); more(); msg("The combined voices the gods ring out:"); more(); buf = strdup(winflag->text); strrep(&buf, "&", "and", NULL); makeuppercase(buf); msg("^%c\"ALL HAIL THE NEW GOD OF %s!!\"", getlfcol(player, CC_VGOOD), buf); more(); free(buf); //killflag(tempflag[0]); //killflag(tempflag[1]); } } char wrapprint(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... ) { char buf[HUGEBUFLEN]; va_list args; va_start(args, format); vsnprintf( buf, HUGEBUFLEN, format, args ); va_end(args); return real_wrapprint(win, y, x, B_TRUE, newlineindent, "%s", buf); } char wrapprint_nomore(WINDOW *win, int *y, int *x, int newlineindent, char *format, ... ) { char buf[HUGEBUFLEN]; va_list args; va_start(args, format); vsnprintf( buf, HUGEBUFLEN, format, args ); va_end(args); return real_wrapprint(win, y, x, B_FALSE, newlineindent, "%s", buf); } // @ = tab char real_wrapprint(WINDOW *win, int *y, int *x, int pager, int newlineindent, char *format, ... ) { char word[HUGEBUFLEN],buf[HUGEBUFLEN]; char *p; va_list args; int w,nspaces = 0, h; int first = B_TRUE; va_start(args, format); vsnprintf( buf, HUGEBUFLEN, format, args ); va_end(args); if (!strlen(buf)) return '\0'; w = getmaxx(win); h = getmaxy(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); // count number of spaces at the start... /* p = buf; while (*p == ' ') { nstartspaces++; p++; } // print out pre-spaces. for (i = 0;i < nstartspaces; i++) { (*x)++; if (*x >= w) { (*y)++; *x = newlineindent; } } */ // 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; if (strlen(word) == 0) { repword = strdup(" "); } else { // handle newline chars while (word[0] == '\n') { (*y)++; *x = newlineindent; memmove(word, word + 1, strlen(word)); } repword = strdup(word); while (rv) { strrep(&repword, "@", " ", &rv); } } // if this word won't fit, put it on the next line. if (*x != 0) { if (*x + strlen_without_colours(repword) >= (w-1)) { (*y)++; *x = newlineindent; } } if (pager && (gamemode == GM_GAMESTARTED)) { if (*y >= h-2) { char ch; centre(win,C_WHITE, h-1, "--More--"); ch = getch(); if (ch == 27) { // esc return ch; } else { // clear window wclear(win); *y = 0; *x = 0; } } } wmove(win, *y, *x); if (first) { first = B_FALSE; } else if ((*x != newlineindent) && strlen(word)) { 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); return '\0'; }