From 94ed133ace345d08c94edc408f5bb1189cfb8da8 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Thu, 28 Jul 2011 22:45:34 +0000 Subject: [PATCH] * [+] hiscores - [+] limit name length * [+] The fire titan is burnt by a flaming greatsword! - [+] make ar slightly less effective. - [+] don't prompt "really walk into xxxdangerousthingxxx" when carefully walking. - [+] allow dodge check for web spell. - [+] speedups in attack.c - [+] "the centipede bites you" "the centipede hits you" - [+] how did it get "hit"? it should only have a teeth attack! - [+] after looking at skills, bottom line of status bar isn't redrawn. - [+] anything with a --more-- - [+] druids regenerate mana based on nearby plants - [+] bug: "your young wolf starts casting a spell" when sprinting. - [+] bug with AI follow code - now fixed. - [+] make ai pets be able to "smell" the player. - [+] unarmed adept: break wood (no "ow!" and extra dam to wood/doors) - [+] automatically give all player pets the ability to see footprints! * [+] monsters not following properly! fixed now i think. - [+] mark fountain potiontypes as "tried" after you drink - [+] replace barbarian with warrior. make it armour-based. - [+] bug: "A Jimbo comes into view" should be "Jimbo coes into view" - [+] more findlfags() calls needed in lf.c. - [+] give jimbo f_dontleaveroom! HELP SYSTEM - [+] ?? for commands - [+] ?s for skills --- Makefile | 2 +- ai.c | 22 +- attack.c | 107 ++++++--- attack.h | 1 + data/hiscores.db | Bin 0 -> 3072 bytes defs.h | 21 +- io.c | 302 ++++++++++++++++--------- io.h | 1 + lf.c | 559 ++++++++++++++++++++++++++++++----------------- lf.h | 1 + map.c | 22 +- move.c | 8 +- nexus.c | 4 +- objects.c | 91 +++++--- save.c | 121 ++++++++++ save.h | 2 + spell.c | 41 +++- text.c | 30 ++- text.h | 1 + 19 files changed, 942 insertions(+), 394 deletions(-) create mode 100644 data/hiscores.db diff --git a/Makefile b/Makefile index ad1ecda..c3beee8 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ nexus: Makefile defs.h nexus.c nexus.h ai.c ai.h attack.c attack.h flag.c flag.h io.c io.h lf.c lf.h map.c map.h move.c move.h objects.c objects.h text.c text.h save.c save.h spell.c spell.h vault.c vault.h - gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c vault.c vault.h -lncurses + gcc -Wall -g -pg -o nexus nexus.c ai.c attack.c flag.c io.c lf.c map.c move.c objects.c text.c save.c spell.c vault.c vault.h -lncurses -lsqlite3 diff --git a/ai.c b/ai.c index 07027dd..51eae6b 100644 --- a/ai.c +++ b/ai.c @@ -405,6 +405,7 @@ object_t *aigetwand(lifeform_t *lf, enum FLAG purpose) { return NULL; } +// returns targetcell flag on success flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int timelimit) { int db = B_FALSE; char whybuf[BUFLEN]; @@ -429,6 +430,9 @@ flag_t *aigoto(lifeform_t *lf, cell_t *c, enum MOVEREASON why, void *data, int t dblog(".oO { %s going to targecell: %d, %d }", lfname, c->x, c->y); } + + + // kill previous target flags. killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETCELL); @@ -737,7 +741,11 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { } else { // not already at their last known cell. try to go there. if (db) dblog(".oO { i cannot see my target. moving to last known loc %d/%d }",lastx,lasty); - if (!aigoto(lf, targcell, MR_LF, target, PERMENANT)) { + if (aigoto(lf, targcell, MR_LF, target, PERMENANT)) { + if (db) dblog(".oO { successfuly moved towards LKL. }"); + // success + return B_FALSE; + } else { if (db) dblog(".oO { aigoto target's last known loc failed! }"); } } @@ -783,7 +791,19 @@ void aimovetotargetcell(lifeform_t *lf, flag_t *f) { // are we there yet? if (lf->cell == c) { + // yes. remove target cell if (db) dblog(".oO { arrived at f_targetcell. removing. }"); + if (f->val[2] == MR_LF) { + lifeform_t *targlf; + // if we were chasing someone, keep looking + // for them. + targlf = findlf(lf->cell->map, atoi(f->text)); + if (targlf) { + if (db) dblog(".oO { resuming pursuit of %s }", targlf->race->name); + addflag(lf->flags, F_TARGETLF, targlf->id, NA, NA, NULL); + } + + } killflag(f); } } diff --git a/attack.c b/attack.c index 39bd730..e0b3582 100644 --- a/attack.c +++ b/attack.c @@ -16,6 +16,8 @@ extern lifeform_t *player; +extern flag_t *retflag[]; +extern int nretflags; int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { object_t *armour = NULL; @@ -250,7 +252,10 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } // then use all our innate attacks.. - for (f = lf->flags->first ; f; f = f->next) { + + getflags(lf->flags, F_HASATTACK, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_HASATTACK) { objecttype_t *ot; @@ -458,7 +463,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_NONCORPOREAL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; // ie. you have been made noncorporeal if ((f->id == F_NONCORPOREAL) && (f->lifetime != FROMRACE)) { if (isplayer(lf)) { @@ -760,6 +767,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } strcpy(attackverb, getattackverb(lf, wep, damtype[i],dam[i],victim->maxhp)); + if (strstr(attackverb, "hit")) { + dblog("xxx"); + } if ((dam[i] == 0) && (damtype[i] != DT_TOUCH)) { nodam = B_TRUE; strcpy(nodamstr, " but does no damage"); @@ -922,7 +932,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } // retaliation happens even if victim died - for (f = victim->flags->first ; f ; f = f->next) { + getflags(victim->flags, F_RETALIATE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_RETALIATE) { int rdam; char damstring[BUFLEN]; @@ -1119,15 +1131,30 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { } if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARDNESS)) { - char buf[BUFLEN]; - sprintf(buf, "punching %s", obname); - if ( losehp(lf, 1, DT_BASH, lf, buf)) { - if (isplayer(lf)) { - msg("^bOw!"); + object_t *gloves; + gloves = getequippedob(lf->pack, BP_HANDS); + if (gloves && hasflag(gloves->flags, F_HARDNESS)) { + // ok + } else if ((o->material->id == MT_WOOD) && (getskill(lf, SK_UNARMED) >= PR_ADEPT)) { + // ok + } else { + char buf[BUFLEN]; + sprintf(buf, "punching %s", obname); + if ( losehp(lf, 1, DT_BASH, lf, buf)) { + if (isplayer(lf)) { + msg("^bOw!"); + } } } } + // smash wood bonus + if ((wep->type->id == OT_FISTS) && + (o->material->id == MT_WOOD) && + (getskill(lf, SK_UNARMED) >= PR_ADEPT)) { + dam[i] += rnd(1,6); + } + // object loses hp takedamage(o, dam[i], damtype[i]); @@ -1175,7 +1202,7 @@ int damtypecausesbleed(enum DAMTYPE dt) { // returns the amount of damage the armour blocked... int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype) { int reduceamt = 0; - int ar,min; + int ar,min,max; //int pctrange; object_t *o; @@ -1186,9 +1213,9 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d //pctrange = rnd(25,75); //reduceamt = pctof(pctrange, ar); - // between ar/5 and AR - min = ar/5; - reduceamt = rnd(min, ar); + getarrange(ar, &min, &max); + + reduceamt = rnd(min, max); // special case @@ -1204,6 +1231,11 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d return reduceamt; } +// for a given ArmourRating (AR), return range of damage which it might reduce +void getarrange(int arating, int *min, int *max) { + *min = pctof(20,arating); + *max = pctof(60, arating); +} // returns a const char * char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp) { @@ -1217,24 +1249,25 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam pct = (int)(((float) dam / (float) maxhp) * 100.0); if (wep) { + int i; flag_t *f; - for (f = wep->flags->first ; f ; f = f->next) { - if (f->id == F_ATTACKVERB) { - if ((f->val[0] == NA) && (f->val[1] == NA)) { - return f->text; - } else if (f->val[0]) { - if (pct >= f->val[0]) { - if (f->val[1] == NA) { - return f->text; - } else if (pct <= f->val[1]) { - return f->text; - } - } - } else if (f->val[1]) { - if (pct <= f->val[1]) { + getflags(wep->flags, F_ATTACKVERB, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if ((f->val[0] == NA) && (f->val[1] == NA)) { + return f->text; + } else if (f->val[0]) { + if (pct >= f->val[0]) { + if (f->val[1] == NA) { + return f->text; + } else if (pct <= f->val[1]) { return f->text; } } + } else if (f->val[1]) { + if (pct <= f->val[1]) { + return f->text; + } } } } @@ -1259,7 +1292,7 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam if (lf && (ownersize <= SZ_SMALL)) { if (pct <= 5) { return "nip"; - } else if (pct <= 30) { + } else { return "bite"; } } else { @@ -1393,9 +1426,12 @@ enum DAMTYPE getdamtype(object_t *wep) { int getextradamlf(lifeform_t *lf, int *dam, enum DAMTYPE *damtype, int *ndam) { flag_t *f; + int i; // special case - EXTRADAM goes onto INITIAL dam[] if the same type, rather than // adding a new one. - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_EXTRADAM, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_EXTRADAM) { int *damwhere; int *damtypewhere; @@ -1436,7 +1472,10 @@ int getextradamlf(lifeform_t *lf, int *dam, enum DAMTYPE *damtype, int *ndam) { int getextradamwep(object_t *wep, int *dam, enum DAMTYPE *damtype, int *ndam) { flag_t *f; - for (f = wep->flags->first ; f ; f = f->next) { + int i; + getflags(wep->flags, F_FROZEN, F_ONFIRE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_ONFIRE) { if (strlen(f->text)) { *(dam + *ndam) = roll(f->text); @@ -1468,7 +1507,10 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d if (wep) { flag_t *f; - for (f = wep->flags->first ; f ; f = f->next) { + int i; + getflags(wep->flags, F_KILLVERB, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_KILLVERB) { if ((f->val[0] == NA) && (f->val[1] == NA)) { return f->text; @@ -1852,6 +1894,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { lifeform_t *victim; lifeform_t *owner = NULL; object_t *wep; + int i; if (!where) return; @@ -1867,7 +1910,9 @@ void wepeffects(flagpile_t *fp, cell_t *where, flag_t *damflag, int dam) { } victim = where->lf; - for (f = fp->first ; f ; f = f->next) { + getflags(fp, F_DISARMATTACK, F_FLAMESTRIKE, F_HEAVYBLOW, F_HITCONFER, F_REVENGE, F_TRIPATTACK, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_FLAMESTRIKE) { if (!hasob(where->obpile, OT_FIRESMALL)) { // ignite! diff --git a/attack.h b/attack.h index 6cb1bf4..7505fed 100644 --- a/attack.h +++ b/attack.h @@ -8,6 +8,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag); void confereffects(flagpile_t *fp, lifeform_t *victim); int damtypecausesbleed(enum DAMTYPE dt); int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damtype); +void getarrange(int arating, int *min, int *max); char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam, int maxhp); //object_t *getattackwep(lifeform_t *lf, obpile_t **unarmedpile, flag_t **unarmedflag); enum DAMTYPE getdamtype(object_t *wep); diff --git a/data/hiscores.db b/data/hiscores.db new file mode 100644 index 0000000000000000000000000000000000000000..15ea1de669e5829886be7a2424972e0d7917d328 GIT binary patch literal 3072 zcmeHIzi$&U6np1eLIB{Ze$!7*8&=AZ9;e)=hb#CeAiM{755GG-n|U$?F1rFp$SSN>D%R06Mcsf6 z__!w|8!x_S_i?M)X^~EIr`;k8?>hGg4;2|nKBO`tK8tE34kUpH`+BNILONt*N@Z_A zWsSTL?jOVFLBKpWT6i`#QGRu|VgV05HX9!X`doMEM2Xn$F0yvF79*@xw^z^vil_m2 zA74Y?(Fr<64HV%Mjg8B`D_Q*)t-y9E52(D+!e69t+tWLw=}lRvCX&gAaeETopOo}D z)qUR6GknB6=HQoLSC>p^WgA|_p<85Mgnl|`#3c;})VWnO#A+R0C&V2pT`KjGY4%ug z*=Np;f+1hO4aW)jQ7{?0e^)c3%306n!75ko9{eNu?~0{n-pm*H;^-6>vSb^^Ouk@mwy3HNaAe( literal 0 HcmV?d00001 diff --git a/defs.h b/defs.h index 5d4367e..235d876 100644 --- a/defs.h +++ b/defs.h @@ -16,6 +16,9 @@ #define SHOPIDENTPRICE 50 // cost to identify a just-purchased item +// rank, score, name, job, killer +#define HISCOREFORMAT "%-6s%-7s%-14s%-18s%s" + // ncurses colours #define C_NONE (-1) enum COLOUR { @@ -145,6 +148,7 @@ enum SKILLLEVEL { // save/load +#define DATADIR "data" #define MAPDIR "data/maps" #define SAVEDIR "data/save" #define VAULTDIR "vaults" @@ -236,7 +240,7 @@ enum SENSE { // AI defs // if target lf is out of view for this many turns, abandon chase -#define AI_FOLLOWTIME (30) +#define AI_FOLLOWTIME (50) #define DEFAULTRESTHEALTIME (3) @@ -293,8 +297,11 @@ enum FLAGCONDITION { #define BUFLENTINY 10 #define BUFLENSMALL 64 #define BUFLEN 128 +#define BIGBUFLEN 512 #define HUGEBUFLEN 1024 +#define MAXPNAMELEN 12 + #define MORESTRING "--More--" #define MSGMORESTRING "^n--More--" @@ -659,6 +666,7 @@ enum RACE { R_JAILER, // human monsters R_HUMAN, + R_BANDITLDR, R_BANDIT, R_BEGGAR, R_DRUNK, @@ -721,6 +729,7 @@ enum RACE { R_ANTLION, R_BAT, R_BEAR, + R_BEARCUB, R_BEARGRIZZLY, R_CHICKEN, R_DOG, @@ -770,7 +779,7 @@ enum JOB { J_GOD, J_ADVENTURER, J_ALLOMANCER, - J_BARBARIAN, + J_WARRIOR, J_COMMANDO, J_DRUID, J_MONK, @@ -1271,12 +1280,14 @@ enum OBTYPE { OT_BELTLEATHER, // armour - legs OT_CLOTHTROUSERS, - OT_RIDINGTROUSERS, OT_COMBATPANTS, + OT_GREAVES, + OT_RIDINGTROUSERS, // armour - feet OT_SANDALS, OT_SHOESLEATHER, OT_BOOTSLEATHER, + OT_BOOTSMETAL, OT_BOOTSRUBBER, OT_BOOTSSPIKED, // armour - hands @@ -1886,7 +1897,7 @@ enum FLAG { // text can be: // x (single number) // x-y (range) - F_DONTSTARTASLEEP, // this mosnter never starts off asleep + F_STARTASLEEPPCT, // v0=pct chance this mosnter starts off asleep F_STARTHIDDENPCT, // val0 = pct chance auto-generated monster will // start off hidden F_CORPSETYPE, // text field specifies what corpse obtype to leave @@ -1931,6 +1942,8 @@ enum FLAG { // 1 and its map dificulty/depth. // if v0 is set, this is the max level. F_MINION, // v0=lfid of minion + F_NOSCORE, // denotes that the player received 0 points. + // ie. cheating or they quit. F_XPVAL, // force xp val for killing this lf to v0 // ...OR if applied to an ability... // monsters with this abil/spell are worth diff --git a/io.c b/io.c index 404f371..bc02fca 100644 --- a/io.c +++ b/io.c @@ -2924,7 +2924,7 @@ void cls(void) { } void describeob(object_t *o) { - char buf[BUFLEN]; + char buf[BIGBUFLEN]; char buf2[BUFLEN]; int y; flag_t *f; @@ -3082,12 +3082,15 @@ void describeob(object_t *o) { ff2->val[0], (ff2->val[0] == 1) ? "" : "s"); y++; } else if (o->type->obclass->id == OC_WEAPON) { + flag_t *damflag; int delay; - mvwprintw(mainwin, y, 0, "It is a %s weapon.", hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); - y++; - if (hasflag(o->flags, F_DAM)) { + sprintf(buf, "It is a %s weapon", hasflag(o->flags, F_TWOHANDED) ? "two-handed" : "single handed"); + damflag = hasflag(o->flags, F_DAM); + if (damflag) { int bonus = 0; - + char buf2[BUFLEN]; + int mindam,maxdam; + enum DAMTYPE damtype; f = hasflag(o->flags, F_BONUS); if (f && f->known) { @@ -3095,33 +3098,28 @@ void describeob(object_t *o) { bonus = f->val[0]; } - f = hasflag(o->flags, F_DAM); - if (f) { - char buf[BUFLEN]; - int mindam,maxdam; - enum DAMTYPE damtype; - damtype = f->val[0]; - getdamrange(f, &mindam, &maxdam); - mindam += bonus; - maxdam += bonus; - if (mindam < 0) mindam = 0; - if (maxdam < 0) maxdam = 0; + damtype = damflag->val[0]; + getdamrange(damflag, &mindam, &maxdam); + mindam += bonus; + maxdam += bonus; + if (mindam < 0) mindam = 0; + if (maxdam < 0) maxdam = 0; - if (mindam == maxdam) { - sprintf(buf, " It inflicts %d %s damage",maxdam, getdamname(damtype)); - } else { - sprintf(buf, " It inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype)); - } - - //dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL); - - strcat(buf, " ("); - strcat(buf, f->text); - strcat(buf, ")."); - - mvwprintw(mainwin, y, 0, "%s",buf); - y++; + if (mindam == maxdam) { + sprintf(buf2, " which inflicts %d %s damage",maxdam, getdamname(damtype)); + } else { + sprintf(buf2, " which inflicts %d-%d %s damage",mindam,maxdam, getdamname(damtype)); } + strcat(buf, buf2); + + //dicetotext(f->val[0], f->val[1], f->val[2], NULL, NULL, dicebuf, NULL); + + strcat(buf, " ("); + strcat(buf, damflag->text); // ie. 2d6 + strcat(buf, ")."); + + mvwprintw(mainwin, y, 0, "%s",buf); + y++; // other extra damage or effects? f = hasflag(o->flags, F_ONFIRE); @@ -3133,6 +3131,9 @@ void describeob(object_t *o) { } y++; } + } else { + mvwprintw(mainwin, y, 0, "%s.", buf); + y++; } delay = 100; @@ -3206,8 +3207,8 @@ void describeob(object_t *o) { f = hasflag(o->flags, F_ACCURACYMOD); if (f) { - mvwprintw(mainwin, y, 0, " It will %s your evasion chance by %d%%.", buf, - (f->val[0] < 0) ? "lower" : "raise", abs(f->val[0])); y++; + mvwprintw(mainwin, y, 0, " It will %s your evasion chance by %d%%.", + (f->val[0] < 0) ? "lower" : "raise", abs(f->val[0])); y++; } @@ -3245,7 +3246,9 @@ void describeob(object_t *o) { sprintf(buf, "It is in perfect condition."); } if (showfullhp) { - sprintf(hpbuf, " [%d/%d hp]", f->val[0], f->val[1]); + int pct; + pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); + sprintf(hpbuf, " [%d%%, %d/%d hp]", pct, f->val[0], f->val[1]); } else if (isdamaged(o)) { int pct; pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); @@ -3789,9 +3792,10 @@ void describeskill(enum SKILL skid) { if (!sk) return; // title - sprintf(buf, "Skill - %s",sk->name); - capitalise(buf); + sprintf(buf, "Skill::%s",sk->name); + wattron(mainwin, A_BOLD); mvwprintw(mainwin, 0, 0, buf); + wattroff(mainwin, A_BOLD); mvwprintw(mainwin, 2, 0,"%s\n\n", sk->desc); @@ -5164,25 +5168,72 @@ void dohelp(void) { int y; command_t *c; char *ftext= "%c %s"; + enum { + HM_COMMANDS, + HM_MAIN, + HM_SKILLS, + } helpmode = HM_MAIN; + int done = B_FALSE; + int ch; h = getmaxy(mainwin); - cls(); - centre(mainwin,C_WHITE, 0, "COMMAND REFERENCE"); - y = 2; - + while (!done) { + cls(); + if (helpmode == HM_MAIN) { + initprompt(&prompt, "What would you like help with (ESC when done)?"); + addchoice(&prompt, '?', "Keyboard Commands", NULL, NULL); + addchoice(&prompt, 's', "Skill Descriptions", NULL, NULL); + addchoice(&prompt, '-', "(done)", NULL, NULL); + prompt.maycancel = B_TRUE; + ch = getchoice(&prompt); + switch (ch) { + case '?': + helpmode = HM_COMMANDS; + break; + case 's': + helpmode = HM_SKILLS; + break; + default: + done = B_TRUE; + break; + } + } else if (helpmode == HM_COMMANDS) { + 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)) { + 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(); - cls(); + helpmode = HM_MAIN; + } else if (helpmode == HM_SKILLS) { + 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); + } + addchoice(&prompt, '\0', "(done)", NULL, NULL); + prompt.maycancel = B_TRUE; + ch = getchoicestr(&prompt, B_FALSE, B_TRUE); + if (!ch) { + helpmode = HM_MAIN; + } else { + sk = (skill_t *)prompt.result; + describeskill(sk->id); + } } } - centre(mainwin,C_WHITE, h-1, "[Press any key]"); - getch(); restoregamewindows(); } @@ -5373,6 +5424,7 @@ void doquit(void) { char ch; ch = askchar("Really quit", "yn","n", B_TRUE); if (ch == 'y') { + addflag(player->flags, F_NOSCORE, B_TRUE, NA, NA, NULL); setlastdam(player, "quitting"); player->alive = B_FALSE; } @@ -6350,7 +6402,9 @@ char getchoicestr(prompt_t *prompt, int useshortcuts, int showallatstart) { wrefresh(mainwin); } curs_set(0); - restoregamewindows(); + if ((gamemode == GM_GAMESTARTED)) { + restoregamewindows(); + } // return NUL or result char if (ch == 27) { return '\0'; @@ -7353,9 +7407,12 @@ void redrawresume(void) { 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) { @@ -7431,6 +7488,29 @@ void setobcolour(WINDOW *win, object_t *o, int set) { } +// dump out a single hiscore line +int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname) { + int i; + char *rank, *score, *name, *job, *killer; + for (i = 0; i < ncols; i++) { + if (streq(colname[i], "rank")) rank = strdup(argv[i]); + else if (streq(colname[i], "score")) score = strdup(argv[i]); + else if (streq(colname[i], "name")) name = strdup(argv[i]); + else if (streq(colname[i], "job")) job = strdup(argv[i]); + else if (streq(colname[i], "killedby")) killer = strdup(argv[i]); + } + if (streq(score, (char *)hilitescore)) setcol(mainwin, C_BOLDGREEN); + wprintw(mainwin, HISCOREFORMAT, rank, score, name, job, killer); + if (streq(score, (char *)hilitescore)) unsetcol(mainwin, C_BOLDGREEN); + + wprintw(mainwin, "\n"); + free(score); + free(name); + free(job); + free(killer); + return B_FALSE; +} + void showlfarmour(lifeform_t *lf) { enum BODYPART bp; object_t *o; @@ -7457,23 +7537,29 @@ void showlfarmour(lifeform_t *lf) { o = getequippedob(lf->pack, bp); outerob = getouterequippedob(lf, bp); if (o) { + flag_t *f; char obname[BUFLEN]; getobname(o, obname, o->amt); strcpy(rhs, obname); - } - if (outerob && (outerob != o)) { - char outerobname[BUFLEN]; - getobname(outerob, outerobname, outerob->amt); - if (strlen(rhs)) strcat(rhs, " "); - strcat(rhs, "(covered) "); - } - if (strlen(rhs)) { - flag_t *f; + 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) { char numbuf[BUFLENSMALL]; - sprintf(numbuf, " [AR:%d]",f->val[0]); + sprintf(numbuf, " ^g[AR:%d]^n",f->val[0]); + 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); + sprintf(numbuf, " ^w[%d%%]^n",pct); strcat(rhs, numbuf); } } else { @@ -7481,36 +7567,16 @@ void showlfarmour(lifeform_t *lf) { } mvwprintw(mainwin, y, 0, "%s", buf); - setobcolour(mainwin, o, B_TRUE); - wprintw(mainwin, "%s", rhs); - setobcolour(mainwin, o, B_FALSE); + if (o) setobcolour(mainwin, o, B_TRUE); + //wprintw(mainwin, "%s", rhs); + textwithcol(mainwin, rhs); + if (o) setobcolour(mainwin, o, B_FALSE); y++; } } y = getmaxy(mainwin); centre(mainwin, C_WHITE, y-1, "[Press any key]"); - -/* - - - f = hasflag(mylist[i]->flags,F_EQUIPPED); - if (f) { - if (f->val[0] == BP_WEAPON) { - if (hasflag(mylist[i]->flags, F_TWOHANDED)) { - strcat(buf2, " (two-handed weapon)"); - } else { - strcat(buf2, " (weapon)"); - } - } else { - strcat(buf2, " ("); - strcat(buf2, getbodypartequipname(f->val[0])); - strcat(buf2, " "); - strcat(buf2, getbodypartname(f->val[0])); - strcat(buf2, ")"); - } - } -*/ getch(); restoregamewindows(); @@ -7942,7 +8008,9 @@ void showlfstats(lifeform_t *lf, int showall) { if (arating == 0) { wprintw(mainwin, "%d (no dmgreduce)", arating); y2++; } else { - wprintw(mainwin, "%d (dmgreduce %d-%d)", arating, arating/5, arating); y2++; + int min,max; + getarrange(arating, &min, &max); + wprintw(mainwin, "%d (dmgreduce %d-%d)", arating, min, max); y2++; } if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol); } @@ -8648,7 +8716,9 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } if (hasjob(lf, J_DRUID)) { - mvwprintw(mainwin, y, 0, "%s spells are boosted by nearby plants.", isplayer(lf) ? "Your" : "Its"); + mvwprintw(mainwin, y, 0, "%s spell power is boosted by nearby plants.", isplayer(lf) ? "Your" : "Its"); + y++; + mvwprintw(mainwin, y, 0, "%s regenerate mana when plants are nearby.", you(lf)); y++; } @@ -8951,7 +9021,7 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasflag(lf, F_RAGE); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s enraged, gaining temporary strength and hit points.", you(lf), is(lf)); + mvwprintw(mainwin, y, 0, "%s %s enraged, gaining accuracy, damage and hit point bonuses.", you(lf), is(lf)); y++; } f = lfhasknownflag(lf, F_REGENERATES); @@ -9163,8 +9233,13 @@ void textwithcol(WINDOW *win, char *buf) { void tombstone(lifeform_t *lf) { char pname[BUFLEN]; char buf[BUFLEN]; + char killer[BUFLEN]; int y; - char *p, *dummy; + int rank,minrank,maxrank; + char *p; + long playerscore; + + playerscore = calcscore(lf); getplayernamefull(pname); @@ -9174,7 +9249,7 @@ void tombstone(lifeform_t *lf) { y = 1; centre(mainwin, C_GREY, y, "R.I.P."); y++; //printf("%s\n",lf->name); - centre(mainwin, C_GREY, y, "%s (%ld points)",pname, calcscore(lf)); y++; + centre(mainwin, C_GREY, y, "%s (%ld points)",pname, playerscore); y++; if (player->cell->map->region->rtype->id == RG_WORLDMAP) { getregionname(buf, player->cell->map, B_TRUE); @@ -9184,27 +9259,52 @@ void tombstone(lifeform_t *lf) { centre(mainwin, C_GREY, y, "Died on level %d of %s.", player->cell->map->depth, buf); y++; } - p = strtok_r(lf->lastdam,"^", &dummy); - if (p) { - if (!strcmp(p, "you")) { - centre(mainwin, C_GREY, y, "Committed suicide.",p); y++; - } else { - centre(mainwin, C_GREY, y, "Killed by %s.",p); y++; - } - p = strtok_r(NULL, "^", &dummy); - while (p) { - centre(mainwin, C_GREY, y, "(%s)",p); y++; - p = strtok_r(NULL, "^", &dummy); - } - - } else { - centre(mainwin, C_GREY, y, "Killed by something unknown."); y++; + makekillertext(killer, lf->lastdam, B_TRUE); + + p = readuntil(buf, killer, '\n'); + while (strlen(buf)) { + centre(mainwin, C_GREY, y, buf); y++; + p = readuntil(buf, p, '\n'); } - wrefresh(mainwin); + + // write hiscores and calculate player's rank + writehiscore(player, &rank); + // wait for key... getch(); + + + cls(); + y = 0; + + if (rank == -1) { + mvwprintw(mainwin, y, 0, "Since you were cheating, your score will not be listed."); y++; + minrank = 1; + maxrank = 10; + } else if (rank > 100) { + mvwprintw(mainwin, y, 0, "You didn't make the top 100 list."); y++; + minrank = 1; + maxrank = 10; + } else { + setcol(mainwin, C_BOLDGREEN); + mvwprintw(mainwin, y, 0, "You made rank #%d on the high score table!", rank); y++; + unsetcol(mainwin, C_BOLDGREEN); + minrank = rank - 4; + maxrank = rank + 4; + limit(&minrank, 0, NA); + limit(&maxrank, NA, 100); + } + + centre(mainwin, C_GREY, y, "High Scores"); y += 2; + wattron(mainwin, A_BOLD); + mvwprintw(mainwin, y, 0, HISCOREFORMAT, "Rank", "Score", "Name", "Job", "Method of death"); y++; + wmove(mainwin, y, 0); + wattroff(mainwin, A_BOLD); + + showhiscores(player, minrank, maxrank); + getch(); // close down graphics ready to quit // clear windows diff --git a/io.h b/io.h index 4a731d2..c2ab09b 100644 --- a/io.h +++ b/io.h @@ -108,6 +108,7 @@ int screenglyphmatches(int x, int y, glyph_t *g); void setcol(WINDOW *win, enum COLOUR col); void unsetcol(WINDOW *win, enum COLOUR col); void setobcolour(WINDOW *win, object_t *o, int set); +int showhiscoreline(void *hilitescore, int ncols, char **argv, char **colname); void showlfarmour(lifeform_t *lf); void showlfstats(lifeform_t *lf, int showall); void textwithcol(WINDOW *win, char *buf); diff --git a/lf.c b/lf.c index 3d3c9c0..2e56214 100644 --- a/lf.c +++ b/lf.c @@ -224,6 +224,9 @@ void breakallgrabs(lifeform_t *lf) { long calcscore(lifeform_t *lf) { long points = 0; object_t *o; + if (lfhasflag(lf, F_NOSCORE)) { + return 0; + } // objects for (o = lf->pack->first ; o ; o = o->next) { points += getobvalue(o); @@ -245,7 +248,7 @@ int calcxp(lifeform_t *lf) { float avgdam = 0; int db = B_FALSE; int maxhdroll; - + int i; float xpconstant = 1; if (lfhasflag(lf, F_DEBUG)) { @@ -303,7 +306,9 @@ int calcxp(lifeform_t *lf) { // spells - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_CANCAST, F_CANWILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_CANCAST) { objecttype_t *ot; int power,level; @@ -920,6 +925,7 @@ int cansleep(lifeform_t *lf) { // where == BP_NONE means "can i wear it anywhere?' int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { + int i; object_t *oo; flag_t *f; @@ -946,7 +952,9 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { } // other flags to check - for (f = o->flags->first ; f ; f = f->next) { + getflags(o->flags, F_ATTREQ, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_ATTREQ) { // meetsattreq will set 'reason' for us. if (!meetsattreq(lf, f, o)) { @@ -961,7 +969,9 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { enum BODYPART possbp[MAXBODYPARTS]; int nparts = 0; int i; - for (f = o->flags->first ; f ; f = f->next) { + getflags(o->flags, F_GOESON, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_GOESON) { possbp[nparts] = f->val[0]; nparts++; @@ -1044,7 +1054,10 @@ int canweild(lifeform_t *lf, object_t *o) { } if (o) { - for (f = o->flags->first ; f; f = f->next) { + int i; + getflags(o->flags, F_ATTREQ, F_TWOHANDED, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_ATTREQ) { // meetsattreq will set 'reason' for us. if (!meetsattreq(lf, f, o)) { @@ -1214,16 +1227,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // boost power? if (hasjob(lf, J_DRUID)) { - int n; - int boost = 0; - for (n = 0; n < lf->nlos; n++) { - if (lf->los[n]->lf && getraceclass(lf->los[n]->lf) == RC_PLANT) { - boost++; - } else if (hasobofclass(lf->los[n]->obpile, OC_FLORA)) { - boost++; - } - } - power += boost; + power += countplantsinsight(lf); limit(&power, NA, 10); } @@ -1449,9 +1453,11 @@ float comparelfs(lifeform_t *lf1, lifeform_t *lf2) { } int countinnateattacks(lifeform_t *lf) { - int count = 0; + int count = 0,i; flag_t *f; - for (f = lf->flags->first ; f; f = f->next) { + getflags(lf->flags, F_HASATTACK, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_HASATTACK) count++; } return count; @@ -1495,6 +1501,18 @@ int countnearbyhurtallies(lifeform_t *lf) { return count; } +int countplantsinsight(lifeform_t *lf) { + int n, boost = 0; + for (n = 0; n < lf->nlos; n++) { + if (lf->los[n]->lf && getraceclass(lf->los[n]->lf) == RC_PLANT) { + boost++; + } else if (hasobofclass(lf->los[n]->obpile, OC_FLORA)) { + boost++; + } + } + return boost; +} + // toggle debugging void debug(lifeform_t *lf) { char lfname[BUFLEN]; @@ -1608,7 +1626,7 @@ void die(lifeform_t *lf) { flag_t *f; cell_t *where; //int dropobs = B_TRUE; - int vaporised = B_FALSE; + int vaporised = B_FALSE, i; int willbecomeghost = B_FALSE; object_t *corpse = NULL; @@ -1799,7 +1817,9 @@ void die(lifeform_t *lf) { } // add extra flags ? - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_CORPSEFLAG, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_CORPSEFLAG) { addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text); } @@ -3190,8 +3210,9 @@ enum SKILLLEVEL findskilllevbyname(char *name) { // anyone we are fleeing from. // returns TRUE if we ran away from something int flee(lifeform_t *lf) { - flag_t *f, *nextf; + flag_t *f; lifeform_t *fleefrom = NULL; + int i; // mindless? if (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) == IQ_MINDLESS) { @@ -3199,8 +3220,10 @@ int flee(lifeform_t *lf) { } // are we fleeing? - for (f = lf->flags->first ; f ; f = nextf) { - nextf = f->next; + + getflags(lf->flags, F_FLEEFROM, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_FLEEFROM) { lifeform_t *thisone; thisone = findlf(lf->cell->map, f->val[0]); @@ -3239,9 +3262,15 @@ int flee(lifeform_t *lf) { lifeform_t *targlf; cell_t *targcell; object_t *targob; - + objecttype_t *sp; + sp = findot(spell); aigetspelltarget(lf, findot(spell), fleefrom, &targlf, &targcell, &targob, F_AICASTTOFLEE); - return castspell(lf, spell, targlf, targob, targcell); + + if (getschool(spell) == SS_ABILITY) { + return useability(lf, spell, targlf, targcell); + } else { + return castspell(lf, spell, targlf, targob, targcell); + } } // if AI, use helpful fleeing items if (!useitemwithflag(lf, F_AIFLEEITEM)) { @@ -3510,6 +3539,7 @@ void gainxp(lifeform_t *lf, long amt) { int getactspeed(lifeform_t *lf) { int speed = 0; flag_t *f; + int i; f = lfhasflag(lf, F_ACTIONSPEED); if (f) { @@ -3519,7 +3549,9 @@ int getactspeed(lifeform_t *lf) { } // modifier? - for (f = lf->flags->first ; f ; f = f->next ){ + getflags(lf->flags, F_SLOWACT, F_SLOWACTMOVE, F_FASTACT, F_FASTACTMOVE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if ((f->id == F_SLOWACT) || (f->id == F_SLOWACTMOVE)) { speed += f->val[0]; } else if ((f->id == F_FASTACT) || (f->id == F_FASTACTMOVE)) { @@ -3661,13 +3693,15 @@ int getarmournoise(lifeform_t *lf) { int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms) { object_t *o; flag_t *f; - int ar = 0; + int ar = 0, i; if (narms) { (*narms) = 0; } - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_ARMOURRATING, F_MAGICARMOUR, F_PHALANX, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_ARMOURRATING) { ar += f->val[0]; if (hitob) { @@ -3798,7 +3832,7 @@ int getattr(lifeform_t *lf, enum ATTRIB attr) { } int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { - int val = 0; + int val = 0, i; flag_t *f; // override? @@ -3812,7 +3846,9 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { // base attribute val = lf->att[attr]; // modified? - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_ATTRMOD, F_DRUNK, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if ((f->id == F_ATTRMOD) && (f->val[0] == attr)) { val += f->val[1]; } @@ -3833,7 +3869,7 @@ int real_getattr(lifeform_t *lf, enum ATTRIB attr, int ignoreattrset) { // returns average damage per turn, modified by accuracy int getavgdam(lifeform_t *lf, int forxp) { obpile_t *op; - int avgdam = 0; + int avgdam = 0,i; int db = B_FALSE; flag_t *f; @@ -3842,7 +3878,9 @@ int getavgdam(lifeform_t *lf, int forxp) { } op = addobpile(NULL, NULL, NULL); - for (f = lf->race->flags->first ; f ; f = f->next) { + getflags(lf->race->flags, F_HASATTACK, F_STARTOB, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_HASATTACK) { int min,max; float thisavg; @@ -3889,43 +3927,45 @@ int getavgdam(lifeform_t *lf, int forxp) { getobname(o,obname,1); if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg); } - } else if (forxp && (f->id == F_STARTOB)) { - object_t *o; - int min,max; - float thisavg; - float acc; - flag_t *of; - obpile_t *op2; + } else if (forxp && (f->id == F_STARTOB)) { // starting weapons... + objecttype_t *ot; - op2 = addobpile(NULL,NULL, NULL); + ot = findotn(f->text); + if (ot && (ot->obclass->id == OC_WEAPON)) { + obpile_t *op2; + object_t *o; + op2 = addobpile(NULL,NULL, NULL); + o = addob(op2, f->text); + if (o) { + int min,max; + float thisavg; + float acc; + flag_t *of; - o = addob(op2, f->text); - - if (o) { - getdamrange(hasflag(o->flags, F_DAM), &min,&max); - thisavg = ((float)min + (float)max) / 2.0; + getdamrange(hasflag(o->flags, F_DAM), &min,&max); + thisavg = ((float)min + (float)max) / 2.0; - // confers anything? - for (of = o->flags->first ; of ; of = of->next) { - if (of->id == F_HITCONFER) { - thisavg += 10; + // confers anything? + for (of = o->flags->first ; of ; of = of->next) { + if (of->id == F_HITCONFER) { + thisavg += 10; + } + } + + // modify for accuracy + acc = getlfaccuracy(lf, o); + thisavg = pctof(acc, thisavg); + + + avgdam += thisavg; + if (db) { + char obname[BUFLEN]; + getobname(o,obname,1); + if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg); } } - - // modify for accuracy - acc = getlfaccuracy(lf, o); - thisavg = pctof(acc, thisavg); - - - avgdam += thisavg; - if (db) { - char obname[BUFLEN]; - getobname(o,obname,1); - if (db) dblog("getavgdam: %s: == %d-%d dam, avg is %0.1f",obname, min, max, thisavg); - } + killobpile(op2); } - - killobpile(op2); } } @@ -3994,7 +4034,7 @@ float getequippedweight(lifeform_t *lf) { int getevasion(lifeform_t *lf) { flag_t *f; - int ev = 0; + int ev = 0,i; // no evasion if you can't move! if (isimmobile(lf)) { @@ -4034,7 +4074,9 @@ int getevasion(lifeform_t *lf) { */ // adjust for bulky armour/shield - for (f = lf->flags->first ;f ; f = f->next) { + getflags(lf->flags, F_ARMOURPENALTY, F_SHIELDPENALTY, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_ARMOURPENALTY) { ev -= adjustarmourpenalty(lf, f->val[1]); } else if (f->id == F_SHIELDPENALTY) { @@ -4431,7 +4473,7 @@ int getlastdir(lifeform_t *lf) { int getlfaccuracy(lifeform_t *lf, object_t *wep) { flag_t *f; object_t *o; - int acc = 0; + int acc = 0,i; // get weapon if (wep) { @@ -4458,7 +4500,9 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { } // adjust for bulky armour/shield - for (f = lf->flags->first ;f ; f = f->next) { + getflags(lf->flags, F_ARMOURPENALTY, F_SHIELDPENALTY, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_SHIELDPENALTY) { acc -= adjustshieldpenalty(lf, f->val[0]); } else if (f->id == F_ARMOURPENALTY) { @@ -4595,7 +4639,11 @@ int getminions(lifeform_t *lf, lifeform_t **minion, int *nminions) { flag_t *f; lifeform_t *min; *nminions = 0; - for (f = lf->flags->first ; f ; f = f->next) { + int i; + + getflags(lf->flags, F_MINION, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_MINION) { min = findlf(lf->cell->map, f->val[0]); if (min) { @@ -4848,7 +4896,7 @@ float getmaxcarryweight(lifeform_t *lf) { int getmaxmp(lifeform_t *lf) { flag_t *f; int activemp = 0; - int maxmp; + int maxmp,i; int extrapct = 0; // base @@ -4860,7 +4908,9 @@ int getmaxmp(lifeform_t *lf) { // losses activemp = 0; - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_BOOSTSPELL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_BOOSTSPELL) { activemp += f->val[1]; } @@ -4887,7 +4937,7 @@ int getmr(lifeform_t *lf) { int getvisrange(lifeform_t *lf) { - int range; + int range,i; flag_t *f; if (isblind(lf)) { @@ -4921,7 +4971,9 @@ int getvisrange(lifeform_t *lf) { } // modifications? - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_VISRANGEMOD, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_VISRANGEMOD) { range += f->val[0]; } @@ -4932,7 +4984,7 @@ int getvisrange(lifeform_t *lf) { } int getmovespeed(lifeform_t *lf) { - int speed = 0; + int speed = 0,i; flag_t *f; object_t *o; @@ -4944,7 +4996,9 @@ int getmovespeed(lifeform_t *lf) { } // modifier? - for (f = lf->flags->first ; f ; f = f->next ){ + getflags(lf->flags, F_FASTMOVE, F_FASTACTMOVE, F_SLOWMOVE, F_SLOWACTMOVE, F_SPRINTING, F_TIRED, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if ((f->id == F_SLOWMOVE) || (f->id == F_SLOWACTMOVE)) { speed += f->val[0]; } else if ((f->id == F_FASTMOVE) || (f->id == F_FASTACTMOVE)) { @@ -6707,7 +6761,12 @@ void givestartobs(lifeform_t *lf, object_t *targob, flagpile_t *fp) { void givestartskills(lifeform_t *lf, flagpile_t *fp) { flag_t *f; - for (f = fp->first ; f ; f = f->next) { + int i; + + getflags(fp, F_STARTSKILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->id == F_STARTSKILL) { int wantval; wantval = f->val[1]; @@ -7396,6 +7455,7 @@ void initjobs(void) { //mayusespellschool(lastjob->flags, i, F_CANWILL); } } + addflag(lastjob->flags, F_NOSCORE, B_TRUE, NA, NA, NULL); addjob(J_ADVENTURER, "Adventurer"); // stats @@ -7462,57 +7522,6 @@ void initjobs(void) { addflag(lastjob->flags, F_DETECTMETAL, B_TRUE, NA, NA, NULL); mayusespellschool(lastjob->flags, SS_ALLOMANCY, F_CANCAST); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_BARBARIAN, "Barbarian"); - // stats - addflag(lastjob->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL); - // initial objects - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); - // initial skills - addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); - addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL); - // learnable skills - addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_LOCKPICKING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); - addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); - // abilities - addflag(lastjob->flags, F_HITDICE, 1, 6, NA, NULL); - addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); - addflag(lastjob->flags, F_LEVABIL, 3, OT_A_HEAVYBLOW, 3, NULL); - addflag(lastjob->flags, F_LEVABIL, 4, OT_A_WARCRY, 4, NULL); - addflag(lastjob->flags, F_LEVABIL, 5, OT_A_CHARGE, 5, NULL); - addflag(lastjob->flags, F_LEVABIL, 6, OT_A_RAGE, 50, NULL); - addflag(lastjob->flags, F_LEVABIL, 10, OT_A_HURRICANESTRIKE, 5, NULL); - addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); - addjob(J_COMMANDO, "Commando"); // stats addflag(lastjob->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); @@ -7808,6 +7817,60 @@ void initjobs(void) { // abilities addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addjob(J_WARRIOR, "Warrior"); + // stats + addflag(lastjob->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_DEX, AT_GTAVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CON, AT_GTAVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_WIS, AT_LTAVERAGE, NA, NULL); + // initial objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "helmet"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "suit of ring mail"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of gauntlets"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "set of greaves"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of metal boots"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "buckler"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10-20 gold coins"); + // initial skills + addflag(lastjob->flags, F_STARTSKILL, SK_AXES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CLUBS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SEWING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_METALWORK, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_THROWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); + // abilities + addflag(lastjob->flags, F_HITDICE, 1, 4, NA, NULL); + addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_LEVABIL, 3, OT_A_HEAVYBLOW, 3, NULL); + addflag(lastjob->flags, F_LEVABIL, 4, OT_A_WARCRY, 4, NULL); + addflag(lastjob->flags, F_LEVABIL, 5, OT_A_CHARGE, 5, NULL); + addflag(lastjob->flags, F_LEVABIL, 6, OT_A_RAGE, 50, NULL); + addflag(lastjob->flags, F_LEVABIL, 10, OT_A_HURRICANESTRIKE, 5, NULL); + addflag(lastjob->flags, F_HIRABLE, B_TRUE, NA, NA, NULL); + addjob(J_WIZARD, "Wizard"); // stats addflag(lastjob->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); @@ -7903,8 +7966,10 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d4"); addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, NA, NA, "11-13"); - addflag(lastrace->flags, F_STARTATT, A_IQ, AT_VLOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STAYINROOM, NA, NA, NA, NULL); // stay in our maze addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+2 halberd"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "gas mask"); @@ -7948,14 +8013,13 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, NULL); // human monsters... - addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); addflag(lastrace->flags, F_DEMANDSBRIBE, NA, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 2, 2, NA, NULL); - addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); @@ -7967,7 +8031,28 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_POTION, NA, NULL); addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_SCROLL, NA, NULL); - //addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); + addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MINIONS, 100, 1, 3, "bandit"); + addrace(R_BANDIT, "bandit", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID); + addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, NULL); + addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, NA, NA, "1d2"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "1-100 gold coins"); + addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_WEAPON, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 100, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 50, OC_ARMOUR, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 15, OC_POTION, NA, NULL); + addflag(lastrace->flags, F_STARTOBCLASS, 15, OC_SCROLL, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); @@ -8026,7 +8111,7 @@ void initrace(void) { addrace(R_TOWNGUARD, "town guard", 100, '@', C_GREY, MT_FLESH, RC_HUMANOID); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "12-18"); - addflag(lastrace->flags, F_DONTSTARTASLEEP, NA, NA, NA, NULL); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); addflag(lastrace->flags, F_STAYINHABITAT, NA, NA, NA, NULL); addflag(lastrace->flags, F_GUARD, NA, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_VILLAGE, 80, NA, NULL); @@ -8057,7 +8142,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, NA, NA, "10"); addflag(lastrace->flags, F_STARTATT, A_CON, NA, NA, "8"); addflag(lastrace->flags, F_STARTATT, A_CHA, NA, NA, "6"); - addflag(lastrace->flags, F_DONTSTARTASLEEP, NA, NA, NA, NULL); + addflag(lastrace->flags, F_STARTASLEEPPCT, 0, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 30, NA, NA, NULL); addflag(lastrace->flags, F_UNIQUE, B_TRUE, NA, NA, NULL); @@ -9311,6 +9396,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, ""); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_STARTASLEEPPCT, 80, NA, NA, NULL); // hibernating addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -9326,11 +9412,14 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;"); - addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_BROWN, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub"); + addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_YELLOW, MT_FLESH, RC_ANIMAL); + lastrace->baseid = R_BEAR; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 52, NA, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 62, NA, ""); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTASLEEPPCT, 80, NA, NA, NULL); // hibernating addflag(lastrace->flags, F_HITDICE, 5, 5, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -9348,6 +9437,27 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL); + addflag(lastrace->flags, F_MINIONS, 25, 1, 2, "bear cub"); + addrace(R_BEARCUB, "bear cub", 60, 'q', C_BROWN, MT_FLESH, RC_ANIMAL); + lastrace->baseid = R_BEAR; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 73, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); + addflag(lastrace->flags, F_MAXATTACKS, 2, 2, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "roars^a roars"); + addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); + addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); addrace(R_ANT, "giant ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9451,6 +9561,7 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_FLEEONHPPCT, 60, NA, NA, ""); addrace(R_DOGBLINK, "blink dog", 35, 'd', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, ""); @@ -9954,6 +10065,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 8, 8, NULL); addflag(lastrace->flags, F_LEVRACE, 5, R_WOLF, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_FLEEONHPPCT, 75, NA, NA, ""); addrace(R_WOLF, "wolf", 25, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -9977,6 +10089,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, 5, 5, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); // insects addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL); @@ -10652,13 +10765,15 @@ int isplayer(lifeform_t *lf) { // returns poison flag with longest remaining lifetime flag_t *ispoisoned(lifeform_t *lf) { flag_t *f,*max = NULL; - for (f = lf->flags->first ;f ; f = f->next) { - if (f->id == F_POISONED) { - if (f->lifetime == PERMENANT) { - return f; - } else if ((max == NULL) || (f->lifetime > max->lifetime)) { - max = f; - } + int i; + + getflags(lf->flags, F_POISONED, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if (f->lifetime == PERMENANT) { + return f; + } else if ((max == NULL) || (f->lifetime > max->lifetime)) { + max = f; } } @@ -11602,10 +11717,13 @@ void killrace(race_t *race) { flag_t *levelabilityready(lifeform_t *lf) { flag_t *f; + int i; if (!lfhasflag(lf, F_HASNEWLEVEL)) return NULL; - for (f = lf->flags->first ; f ; f = f->next) { + getflags(lf->flags, F_LEVABIL, F_LEVFLAG, F_LEVSPELL, F_LEVSPELLSCHOOL, F_LEVSKILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; // we'll set lifetime to -1 while actually assigning these. if (f->lifetime == FROMJOB) { switch (f->id) { @@ -11777,35 +11895,38 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // check for psychic armour etc if (amt > 0) { if (isphysicaldam(damtype)) { - for (f = lf->flags->first ; f ; f = f->next) { - if (f->id == F_MAGICARMOUR) { - int damtaken; - damtaken = amt; - if (damtaken > f->val[0]) { - damtaken = f->val[0]; - } - f->val[0] -= damtaken; - if (f->val[0] <= 0) { - // from a spell? - if (f->lifetime == FROMSPELL) { - flag_t *spellflag; - spellflag = hasactivespell(lf, f->obfrom); - if (spellflag) { - killflag(spellflag); - } - } - killflag(f); - } else { - if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s%s %s pulses!", lfname, getpossessive(lfname), f->text); - } - } + int i; - // reduce damage - amt -= damtaken; + getflags(lf->flags, F_MAGICARMOUR, F_NONE); + for (i = 0; i < nretflags; i++) { + int damtaken; + + f = retflag[i]; + damtaken = amt; + if (damtaken > f->val[0]) { + damtaken = f->val[0]; } + f->val[0] -= damtaken; + if (f->val[0] <= 0) { + // from a spell? + if (f->lifetime == FROMSPELL) { + flag_t *spellflag; + spellflag = hasactivespell(lf, f->obfrom); + if (spellflag) { + killflag(spellflag); + } + } + killflag(f); + } else { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s %s pulses!", lfname, getpossessive(lfname), f->text); + } + } + + // reduce damage + amt -= damtaken; } } } @@ -12709,7 +12830,7 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground, int want void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat) { flag_t *f; - int found = B_FALSE; + int found = B_FALSE,i; enum POISONSEVERITY psev; // are you immune to disease? @@ -12724,7 +12845,11 @@ void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char return; } - for (f = lf->flags->first ; f ; f = f->next) { + + getflags(lf->flags, F_POISONED, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; + if ( (f->id == F_POISONED) && (f->val[0] == ptype) && (f->lifetime > 0) ) { // extend duration @@ -13000,7 +13125,10 @@ int recruit(lifeform_t *lf) { void refreshlevelabilities(lifeform_t *lf) { flag_t *f; - for (f = lf->flags->first ; f ; f = f->next) { + int i; + getflags(lf->flags, F_LEVABIL, F_LEVFLAG, F_LEVSPELL, F_LEVSPELLSCHOOL, F_LEVSKILL, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; // we'll set timeleft to -1 while actually assigning these. switch (f->id) { case F_LEVFLAG: @@ -13563,8 +13691,10 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { killflagsofid(lf->flags, F_RARITY); // certain other flags are rnadom - for (f = lf->flags->first ; f ; f = nextf) { - nextf = f->next; + + getflags(lf->flags, F_RNDHOSTILE, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_RNDHOSTILE) { if (pctchance(f->val[0])) { addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -13742,10 +13872,10 @@ void initskills(void) { addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); addskill(SK_METALWORK, "Metalwork", "Lets you repair metal objects.", 100); addskilldesc(SK_METALWORK, PR_NOVICE, "^gYou can repair metal items up to 33% condition.", B_FALSE); - addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items up to 50% condition", B_FALSE); - addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items up to 60% condition", B_FALSE); - addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can repair metal items up to 70% condition", B_FALSE); - addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can repair metal items up to 85% condition", B_FALSE); + addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items up to 50% condition.", B_FALSE); + addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items up to 60% condition.", B_FALSE); + addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can repair metal items up to 70% condition.", B_FALSE); + addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can repair metal items up to 85% condition.", B_FALSE); addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can fully repair metal items.", B_FALSE); addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); addskilldesc(SK_RANGED, PR_NOVICE, "^gYou suffer a -20% accuracy penalty when using ranged weapons.", B_FALSE); @@ -13859,6 +13989,7 @@ void initskills(void) { addskill(SK_SHORTBLADES, "Short Blades", "Helps you use daggers, short swords, etc.", 50); addskill(SK_STAVES, "Staves", "Helps you use quarterstaffs, staffs, etc.", 50); addskill(SK_UNARMED, "Unarmed Combat", "Helps you fight using your bare hands.", 50); + addskilldesc(SK_UNARMED, PR_ADEPT, "^gYour unarmed attacks can now smash wooden objects.", B_TRUE); addskilldesc(SK_UNARMED, PR_SKILLED, "^gYou can now make melee attacks with your off-hand.", B_TRUE); // spell schools addskill(SK_SS_ALLOMANCY, "Allomancy", "Boosts casting of spells from this school.", 50); @@ -14636,7 +14767,7 @@ void stopsprinting(lifeform_t *lf) { } -// very much like addmonster(), but announce that it appears +// wrapper for addmonster(), but announce that it appears // and make it worth zero xp. // // for unique monsters, they move from their current position. @@ -15064,6 +15195,15 @@ void turneffectslf(lifeform_t *lf) { gainmp(lf, f->val[0]); } } + // druid gains mp from plants + if (hasjob(lf, J_DRUID)) { + int chance = 0; + // 5% per plant in sight of gaining mp + chance = countplantsinsight(lf) * 5; + if (pctchance(chance)) { + gainmp(lf, 1); + } + } if (hasactivespell(lf, OT_S_SUMMONWEAPON)) { @@ -16576,7 +16716,7 @@ int rest(lifeform_t *lf, int onpurpose) { } int wear(lifeform_t *lf, object_t *o) { - int rv = B_FALSE; + int rv = B_FALSE,i; char buf[BUFLEN],obname[BUFLEN]; flag_t *f; enum BODYPART possbp[MAXBODYPARTS]; @@ -16614,7 +16754,10 @@ int wear(lifeform_t *lf, object_t *o) { nparts = 0; - for (f = o->flags->first ; f ; f = f->next) { + + getflags(o->flags, F_GOESON, F_NONE); + for (i = 0; i < nretflags; i++) { + f = retflag[i]; if (f->id == F_GOESON) { possbp[nparts] = f->val[0]; nparts++; @@ -16666,20 +16809,24 @@ int wear(lifeform_t *lf, object_t *o) { if (isplayer(lf)) { int ch; char buf2[BUFLEN]; - // take offending item off first - this takes extra time. - sprintf(buf2, "Remove your %s",noprefix(buf)); - ch = askchar(buf2, "yn","y", B_TRUE); - if (ch == 'y') { - if (isarmour(inway)) { - if (!takeoff(player, inway)) { - // took it off! - errresolved = B_TRUE; - } - } else { // weapon - if (!unweild(player, inway)) { - // took it off! - errresolved = B_TRUE; - } + if (inway->blessknown && iscursed(inway)) { + msg("You cannot remove your %s.", noprefix(buf)); + } else { + // take offending item off first - this takes extra time. + sprintf(buf2, "Remove your %s",noprefix(buf)); + ch = askchar(buf2, "yn","y", B_TRUE); + if (ch == 'y') { + if (isarmour(inway)) { + if (!takeoff(player, inway)) { + // took it off! + errresolved = B_TRUE; + } + } else { // weapon + if (!unweild(player, inway)) { + // took it off! + errresolved = B_TRUE; + } + } } } } @@ -16919,10 +17066,15 @@ int weild(lifeform_t *lf, object_t *o) { char buf2[BUFLEN]; char ch; if (isplayer(lf)) { - getobname(oo, inwayname, oo->amt); - // prompt before taking it off. - sprintf(buf2, "Remove your %s",noprefix(inwayname)); - ch = askchar(buf2, "yn","y", B_TRUE); + if (oo->blessknown && iscursed(oo)) { + msg("You cannot remove your %s.", noprefix(inwayname)); + ch = 'n'; + } else { + getobname(oo, inwayname, oo->amt); + // prompt before taking it off. + sprintf(buf2, "Remove your %s",noprefix(inwayname)); + ch = askchar(buf2, "yn","y", B_TRUE); + } } else { ch = 'y'; } @@ -16978,10 +17130,15 @@ int weild(lifeform_t *lf, object_t *o) { char inwayname[BUFLEN]; char ch; if (isplayer(lf)) { - // prompt before taking it off. - getobname(oo, inwayname, oo->amt); - sprintf(buf2, "Remove your %s",noprefix(inwayname)); - ch = askchar(buf2, "yn","y", B_TRUE); + if (oo->blessknown && iscursed(oo)) { + msg("You cannot remove your %s.", noprefix(inwayname)); + ch = 'n'; + } else { + // prompt before taking it off. + getobname(oo, inwayname, oo->amt); + sprintf(buf2, "Remove your %s",noprefix(inwayname)); + ch = askchar(buf2, "yn","y", B_TRUE); + } } else { ch = 'y'; } diff --git a/lf.h b/lf.h index e63688f..018dd3a 100644 --- a/lf.h +++ b/lf.h @@ -49,6 +49,7 @@ int countinnateattacks(lifeform_t *lf); int countmoney(lifeform_t *lf); int countnearbyallies(lifeform_t *lf); int countnearbyhurtallies(lifeform_t *lf); +int countplantsinsight(lifeform_t *lf); void debug(lifeform_t *lf); int demandbribe(lifeform_t *lf); void die(lifeform_t *lf); diff --git a/map.c b/map.c index 6d8c4b5..a2e1f36 100644 --- a/map.c +++ b/map.c @@ -212,7 +212,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto } if (autogen) { - // sometimes start off asleep in new maps + // sometimes start off hiding/asleep in new maps f = lfhasflag(lf, F_STARTHIDDENPCT); if (f) { if (rnd(1,100) <= f->val[0]) { @@ -222,10 +222,14 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto addflag(lf->flags, F_HIDING, 0, NA, NA, NULL); } } - if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_DEAF) && cansleep(lf) && - !lfhasflag(lf, F_DONTSTARTASLEEP)) { + if (!lfhasflag(lf, F_HIDING) && !lfhasflag(lf, F_DEAF) && cansleep(lf) ) { + int asleepchance = 50; + f = lfhasflag(lf, F_STARTASLEEPPCT); + if (f) { + asleepchance = f->val[0]; + } // TODO: base this on the time, and whether monster is nocturnal - if (rnd(1,2) == 1) { + if (pctchance(asleepchance)) { addflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); } } @@ -3632,11 +3636,13 @@ object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tfl if ((oid == NA) || (o->type->id == oid)) { f = hasflag(o->flags, F_TRAIL); // raceid and lfid must match - if (f && (f->val[0] == lf->race->id) && (atoi(f->text) == lf->id)) { - if (tflag) { - *tflag = f; + if (f) { + if ((f->val[0] == lf->race->id) && (atoi(f->text) == lf->id)) { + if (tflag) { + *tflag = f; + } + return o; } - return o; } } } diff --git a/move.c b/move.c index 8cbc34d..a54bc5f 100644 --- a/move.c +++ b/move.c @@ -1183,10 +1183,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (cansee(l, lf) && areenemies(lf, l)) { if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_TRAINING)) { // TODO: also check for isresting(l), if we have allies standing watch - char lfname2[BUFLEN]; - getlfname(lf, lfname); - sprintf(lfname2, "%s",noprefix(lfname)); - msg("%s %s comes into view.",isvowel(lfname2[0]) ? "An" : "A", lfname2); + getlfnamea(lf, lfname); + msg("%s comes into view.", lfname); } dointerrupt = B_TRUE; } @@ -2052,7 +2050,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { cell = getcellindir(lf->cell, dir); - if (isplayer(lf)) { + if (isplayer(lf) && !lfhasflag(lf, F_SNEAK)) { if (cell && celldangerous(lf, cell, B_TRUE, &errcode)) { char ques[BUFLEN]; char ch; diff --git a/nexus.c b/nexus.c index 10a3f87..632f659 100644 --- a/nexus.c +++ b/nexus.c @@ -216,7 +216,9 @@ int main(int argc, char **argv) { user = getenv("USER"); if (user) { - addflag(player->flags, F_NAME, NA, NA, NA, getenv("USER")); + char pname[MAXPNAMELEN]; + snprintf(pname, MAXPNAMELEN, "%s", getenv("USER")); + addflag(player->flags, F_NAME, NA, NA, NA, pname); } else { addflag(player->flags, F_NAME, NA, NA, NA, "Anonymous"); } diff --git a/objects.c b/objects.c index 74e4c44..7ac0089 100644 --- a/objects.c +++ b/objects.c @@ -1876,8 +1876,8 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { // adjust damage if (o->blessed == B_BLESSED) { - // chance of no hp loss - if (onein(2)) { + // high chance of no hp loss + if (pctchance(90)) { lifeform_t *owner; owner = o->pile->owner; if (owner && isplayer(owner)) { @@ -1893,7 +1893,7 @@ void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype) { return; } } else if (o->blessed == B_CURSED) { - // chance of double damage! + // 50% chance of double damage! if (onein(2)) { lifeform_t *owner; (*dam) *= 2; @@ -2195,6 +2195,15 @@ int canseeob(lifeform_t *lf, object_t *o) { } } else { // ie. SCENT + + // special case: if lf is the player's pet, they can always "smell" the player + if (ispetof(lf, player) && strlen(f->text)) { + // scent belongs to the player? + if (atoi(f->text) == player->id) { + return B_TRUE; + } + } + // can't smell your own race... if ((f->val[0] != lf->race->id) && lfhasflag(lf, F_ENHANCESMELL)) { return B_TRUE; @@ -2489,7 +2498,7 @@ int doobtraps(object_t *o, lifeform_t *lf) { // announce... if (isplayer(lf)) { - msg("^wA trap goes off!"); + msg("^wA trap goes off!"); more(); } trapid = f->val[0]; @@ -6684,7 +6693,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 5, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); - addot(OT_S_JOLT, "jolt", "Jolts an adjacent enemy with a short pulse of electricity.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_JOLT, "jolt", "Jolts an adjacent enemy with a short pulse of electricity, dealing 1-^bpower^n damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL); @@ -6713,7 +6722,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); - addot(OT_S_WINDSHIELD, "cyclonic shield", "Surrounds the caster with a whirling cyclone to repel missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_WINDSHIELD, "cyclonic shield", "Surrounds the caster with a whirling cyclone to repel missiles. Spell power determines the speed of missile which can be repelled.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -6721,7 +6730,7 @@ void initobjects(void) { addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); // l4 - addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas. The cloud's size is 1-3 cells, depending on the spell power.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); @@ -8506,13 +8515,13 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); - addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour, designed to stop a bullet.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); + addot(OT_FLAKJACKET, "flak jacket", "Heavy metal body armour. Designed to stop a bullet, but only once.", MT_METAL, 30, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_GOESON, BP_BODY, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 10, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 10, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); - addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); + addflag(lastot->flags, F_OBHP, 3, 3, NA, NULL); addot(OT_OVERALLS, "pair of overalls", "Well-made, brightly coloured workman overalls.", MT_CLOTH, 1, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); @@ -8566,12 +8575,20 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); - addot(OT_COMBATPANTS, "pair of combat pants", "An armoured pair of camoflauged trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); + addot(OT_COMBATPANTS, "pair of combat pants", "An lightly-armoured pair of camoflauged trousers.", MT_CLOTH, 2, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 3, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); + addot(OT_GREAVES, "set of greaves", "A set of heavy metal greaves.", MT_METAL, 4, OC_ARMOUR, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_GOESON, BP_LEGS, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 25, 25, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_ARMOURPENALTY, 15, 15, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, 9, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 3, NA, NULL); // armour - feet addot(OT_SANDALS, "pair of sandals", "Comfortable pair of open leather sandals.", MT_LEATHER, 1, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); @@ -8608,6 +8625,13 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); + addot(OT_BOOTSMETAL, "pair of metal boots", "A strong pair of metal boots.", MT_METAL, 5, OC_ARMOUR, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_RARE, NULL); + addflag(lastot->flags, F_GOESON, BP_FEET, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 2, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, 7, NA, NULL); // armour - gloves addot(OT_GLOVESCLOTH, "pair of cloth gloves", "A pair of soft cloth gloves.", MT_CLOTH, 0.15, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); @@ -8682,7 +8706,7 @@ void initobjects(void) { addflag(lastot->flags, F_SCARY, 4, NA, NA, NULL); // armour - eyes - addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_PLASTIC, 0.01, OC_ARMOUR, SZ_SMALL); + addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_GLASS, 0.01, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); @@ -12047,7 +12071,7 @@ void quaff(lifeform_t *lf, object_t *o) { int seen; int killobwhendone = B_TRUE; flag_t *drinkflag; - enum OBTYPE fountainobid = OT_NONE; + enum OBTYPE realobid = OT_NONE; getobname(o, obname, 1); @@ -12059,7 +12083,16 @@ void quaff(lifeform_t *lf, object_t *o) { taketime(lf, getactspeed(lf)); - maketried(o->type->id); + if (o->type->id == OT_FOUNTAIN) { + flag_t *f; + // ie if not already identified... + f = hasflag(o->flags, F_LINKOB); + realobid = f->val[0]; + } else { + realobid = o->type->id; + } + + maketried(realobid); if (touch(lf, o)) { return; @@ -12086,21 +12119,15 @@ void quaff(lifeform_t *lf, object_t *o) { if (playercansee) { if (o->type->id == OT_FOUNTAIN) { flag_t *f; - // ie if not already identified... f = hasflag(o->flags, F_LINKOB); if (f->val[2] == B_TRUE) { - // already identified + // fountain which is already identified willid = B_FALSE; - fountainobid = OT_NONE; - } else { - // then identify based on potion effects... - fountainobid = f->val[0]; - } - } else { - fountainobid = o->type->id; - } + } + // otherwise identify based on potion effects... + } - switch (fountainobid) { + switch (realobid) { case OT_NONE: willid = B_FALSE; break; @@ -12119,9 +12146,9 @@ void quaff(lifeform_t *lf, object_t *o) { } if (willid) { + makeknown(realobid); + if (o->type->id == OT_FOUNTAIN) { - // id the linked potion - makeknown(fountainobid); // refresh fountain name getobname(o, obname, 1); if (isplayer(lf)) { @@ -12131,8 +12158,6 @@ void quaff(lifeform_t *lf, object_t *o) { drawmsg(); } } else if (!isknown(o)) { - // id the potion - makeknown(o->type->id); real_getobname(o, obname, 1, B_FALSE, B_TRUE, B_FALSE, B_FALSE, B_FALSE); // don't adjust for blindness if (isplayer(lf)) { // tell the player @@ -13615,9 +13640,13 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno int lfdam = 0; owner = o->pile->owner; f = hasflag(o->flags, F_EQUIPPED); - if (f && (f->val[0] != BP_WEAPON) && (f->val[0] != BP_SECWEAPON)) { - // ob equipped? 1.5x damage. - lfdam = pctof(150,howmuch); + if (f) { + // no damage from equipped _weapons_ + if ((f->val[0] != BP_WEAPON) || (f->val[0] != BP_SECWEAPON)) { + } else { + // equipped clothes/armour? 1.5x damage. + lfdam = pctof(150,howmuch); + } } else { // otherwise normal. lfdam = howmuch; diff --git a/save.c b/save.c index 3c8f5d5..e0bebd0 100644 --- a/save.c +++ b/save.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "defs.h" #include "flag.h" #include "io.h" @@ -1005,3 +1006,123 @@ int saveregions(void) { return B_FALSE; } + +int showhiscores(lifeform_t *lf, int min, int max) { + sqlite3 *db; + int rc; + char filename[BUFLEN],*cmd; + char *errmsg = NULL; + char hilitescoretext[BUFLEN]; + long hilitescore = -1; + + if (lf && !lfhasflag(lf, F_NOSCORE)) { + hilitescore = calcscore(lf); + } else { + hilitescore = -1; + } + // open database + sprintf(filename, "%s/hiscores.db", DATADIR); + rc = sqlite3_open(filename, &db); + if (rc) { + msg("error opening hiscore file '%s'.\n",filename); + dblog("error opening hiscore file '%s'.\n",filename); + return B_TRUE; + } + + // show top ten + //sprintf(cmd, "select * from hiscores order by score desc limit 10;"); + asprintf(&cmd, "select (select count(*) from hiscores b where b.score > a.score) + 1 as rank, score,name,job,killedby from hiscores a where (rank >= %d) and (rank <= %d) order by score desc limit 10;", min, max); + + sprintf(hilitescoretext, "%ld",hilitescore); + rc = sqlite3_exec(db, cmd, showhiscoreline, hilitescoretext, &errmsg); + free(cmd); + if (rc != SQLITE_OK) { + msg("error writing hiscores: '%s'", errmsg); + dblog("error writing hiscores: '%s'", errmsg); + sqlite3_free(errmsg); + } + sqlite3_close(db); + + return B_FALSE; +} + +// returns player's rank in 'rank' +int writehiscore(lifeform_t *lf, int *rank) { + sqlite3 *db; + int rc; + char filename[BUFLEN],*cmd; + char pname[BUFLEN]; + char jobname[BUFLEN]; + char killedby[BUFLEN]; + char *errmsg = NULL; + sqlite3_stmt *smt; + job_t *j; + long minscore; + long score; + + score = calcscore(lf); + + // open database + sprintf(filename, "%s/hiscores.db", DATADIR); + rc = sqlite3_open(filename, &db); + if (rc) { + msg("error opening hiscore file '%s'.\n",filename); + dblog("error opening hiscore file '%s'.\n",filename); + return B_TRUE; + } + + getplayername(pname); + j = getjob(player); + sprintf(jobname, "Lv%d %s", player->level, j->name); + + makekillertext(killedby, lf->lastdam, B_FALSE); + + if (!lfhasflag(lf, F_NOSCORE)) { + asprintf(&cmd, "insert into 'hiscores' (score,name,job,killedby) VALUES (%ld, '%s', '%s', '%s')", score, pname, jobname, killedby); + rc = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); + free(cmd); + if (rc != SQLITE_OK) { + msg("error writing hiscores: '%s'", errmsg); + dblog("error writing hiscores: '%s'", errmsg); + sqlite3_free(errmsg); + } + } + + if (rank) { + if (lfhasflag(lf, F_NOSCORE)) { + *rank = -1; + } else { + // find out the player's rank + asprintf(&cmd, "select (select count(*) from hiscores b where b.score > a.score) + 1 as rank from hiscores a where score = %ld;",score); + rc = sqlite3_prepare_v2(db, cmd, -1, &smt, 0); + free(cmd); + rc = sqlite3_step(smt); + while (rc == SQLITE_ROW) { + const char *p; + p = (const char *)sqlite3_column_text(smt, 0); + *rank = atoi(p); + rc = sqlite3_step(smt); + } + } + } + + // now delete all hiscore entries after 100 + // find score number 100... + asprintf(&cmd, "select score from hiscores order by score desc limit 100;"); + rc = sqlite3_prepare_v2(db, cmd, -1, &smt, 0); + free(cmd); + rc = sqlite3_step(smt); + while (rc == SQLITE_ROW) { + const char *p; + p = (const char *)sqlite3_column_text(smt, 0); + minscore = atol(p); + rc = sqlite3_step(smt); + } + // we now have a minimum score - delete everything lower than it. + asprintf(&cmd, "delete from hiscores where score < %ld;", minscore); + rc = sqlite3_exec(db, cmd, NULL, NULL, &errmsg); + free(cmd); + + sqlite3_close(db); + return 0; +} diff --git a/save.h b/save.h index f46b2c4..0cb8741 100644 --- a/save.h +++ b/save.h @@ -15,3 +15,5 @@ int savegame(void); int savemap(map_t *m); int saveob(FILE *f, object_t *o); int saveregions(void); +int showhiscores(lifeform_t *lf, int min, int max); +int writehiscore(lifeform_t *lf, int *rank); diff --git a/spell.c b/spell.c index a9ee24f..a596594 100644 --- a/spell.c +++ b/spell.c @@ -786,6 +786,8 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } howlong = 10; addtempflag(user->flags, F_RAGE, B_TRUE, NA, NA, NULL, howlong); + needredraw = B_TRUE; + statdirty = B_TRUE; } else if (abilid == OT_A_REPAIR) { enum SKILLLEVEL slev; object_t *o; @@ -1601,10 +1603,18 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef taketime(user, getactspeed(user)*2); // all in range must pass a morale check or flee - for (target = user->cell->map->lf ; target ; target = target->next) { if ((target != user) && cansee(target, user) && areenemies(target, user)) { - if (canhear(target, user->cell, 4)) { + int ok = B_FALSE; + switch (target->race->raceclass->id) { + case RC_ANIMAL: + case RC_HUMANOID: + ok = B_TRUE; + break; + default: + break; + } + if (ok && canhear(target, user->cell, 4)) { scare(target, user, rnd(5,10), 0); } } @@ -3794,6 +3804,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ amt = 1; } modbonus(o, amt); + if (iscursed(o)) { + setblessed(o, B_UNCURSED); + } } } else { // monsters can't id things! @@ -7184,14 +7197,24 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND); } if (c) { - addob(c->obpile, "web"); if (c->lf && (c->lf->race->baseid != R_SPIDER)) { - if (isplayer(c->lf)) { - msg("You are stuck in a web!"); - } else if (cansee(player, c->lf)) { - char lfname[BUFLEN]; - getlfname(c->lf, lfname); - msg("%s is stuck in a web!", lfname); + if (skillcheck(c->lf, SC_DODGE, 20+power, 0)) { + if (isplayer(c->lf)) { + msg("You dodge a web."); + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("%s dodges a web!", lfname); + } + } else { + addob(c->obpile, "web"); + if (isplayer(c->lf)) { + msg("You are stuck in a web!"); + } else if (cansee(player, c->lf)) { + char lfname[BUFLEN]; + getlfname(c->lf, lfname); + msg("%s is stuck in a web!", lfname); + } } } } diff --git a/text.c b/text.c index 92898a1..f7d2d19 100644 --- a/text.c +++ b/text.c @@ -62,6 +62,8 @@ enum COLOUR chartocol(char ch) { return C_GREEN; case 'G': // v.good return C_CYAN; + case 'h': // 'hilite' + return C_WHITE; case 'n': // normal default: break; @@ -389,6 +391,30 @@ int isvowel (char c) { return B_FALSE; } +char *makekillertext(char *retbuf, char *lastdam, int wantextra) { + char *p, *dummy; + p = strtok_r(lastdam,"^", &dummy); + if (p) { + if (!strcmp(p, "you")) { + strcpy(retbuf, "Committed suicide."); + } else { + sprintf(retbuf, "Killed by %s.",p); + } + if (wantextra) { + p = strtok_r(NULL, "^", &dummy); + while (p) { + strcat(retbuf, "\n("); + strcat(retbuf, p); + strcat(retbuf, ")"); + p = strtok_r(NULL, "^", &dummy); + } + } + } else { + strcpy(retbuf, "Killed by something unknown."); + } + return retbuf; +} + // allocates and returns new string char *makeplural(char *text) { char lastlet; @@ -552,8 +578,10 @@ char *readuntil(char *retbuf, char *src, char delim) { *bp = *p; bp++; } - p++; // go past delimiter *bp = '\0'; // nul-terminate buffer + if (*p == delim) { + p++; // go past delimiter + } return p; } diff --git a/text.h b/text.h index db71a2d..bbd6ec7 100644 --- a/text.h +++ b/text.h @@ -19,6 +19,7 @@ char *getwaterdepthname(enum DEPTH d); char *getweighttext(float weight, char *buf); char *is(lifeform_t *lf); int isvowel(char c); +char *makekillertext(char *retbuf, char *lastdam, int wantextra); char *makeplural(char *text); char *makeuppercase(char *text); int needses(char *text);