From 95c6ab8396dae402e8e553511a7ca0f175627039 Mon Sep 17 00:00:00 2001 From: Rob Pearce Date: Fri, 1 Jul 2011 03:34:41 +0000 Subject: [PATCH] - [+] tweak armour damage -make natural armour hittable. - [+] getdirtowards/away bug - [+] metalwork or armour skills let you see armour hp! * [+] allow players to select their weapon specialties at the start - [+] make statbar easier to read * [+] druids - [+] spark on rum will blow it up! * [+] evasion skill - [+] add charisma * [+] add speech skill - [+] bug: gate to level 1 took me to the outside! * [+] bug: not hearing shopkeepers final yell - out of range?? - [+] special corpses: i - a Jimbo corpse should be "Jimbo's corpse" - [+] when autogenerating monsters, make sure they have ammo for ranged weapons. * [+] map to town - [+] randomly place the town now. * [+] shopkeeper still doesn't talk to us if we can't see him when we pick up an object - [+] i am STILL not hearing when the shopkeeper yells you "stop thief"!! * [+] bug: LOTS of dungeon rooms with no exit - [+] town guards want money - [+] announce "a xxx falls through a pit" * [+] make running go around corners * [+] colourise known skills - [+] rename constitution to fitness * [+] scroll of mending - should this fix dulled weapons (by hitting doors etc)? - [+] colourise @@ (boldwhite for titles) * [+] colourise @s * [+] colourise @m and @e --- ai.c | 11 +- attack.c | 63 +++-- defs.h | 162 +++++++----- doc/add_attrib.txt | 5 +- doc/add_skill.txt | 8 +- io.c | 420 ++++++++++++++++++++++-------- io.h | 3 +- lf.c | 633 +++++++++++++++++++++++++++++++++++++++------ lf.h | 14 +- map.c | 108 ++++++-- map.h | 6 +- move.c | 50 ++-- objects.c | 377 ++++++++++++++++++++++++--- objects.h | 6 +- spell.c | 137 +++++++--- text.c | 30 ++- 16 files changed, 1605 insertions(+), 428 deletions(-) diff --git a/ai.c b/ai.c index cf6776a..67d075f 100644 --- a/ai.c +++ b/ai.c @@ -59,7 +59,6 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { killflagsofid(lf->flags, F_TARGETLF); killflagsofid(lf->flags, F_TARGETCELL); - if ((timelimit == PERMENANT) || (timelimit == UNLIMITED)) { addflag(lf->flags, F_TARGETLF, victim->id, victim->cell->x, victim->cell->y, NULL); } else { @@ -70,12 +69,14 @@ void aiattack(lifeform_t *lf, lifeform_t *victim, int timelimit) { makenoise(lf, N_GETANGRY); } + // become hostile? + if (!hasflag(lf->flags, F_HOSTILE)) { + addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } + // change allegience ? if (!areenemies(lf, victim)) { if (getallegiance(victim) == AL_FRIENDLY) { - if (!hasflag(lf->flags, F_HOSTILE)) { - addflag(lf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - } killflagsofid(lf->flags, F_FRIENDLY); } } @@ -1685,7 +1686,7 @@ int lookforobs(lifeform_t *lf) { // if we are in battle only go for it if we covet it if (target && !wantflagcovet[n]) continue; - if (o && !isdangerousob(o, lf, B_TRUE) && (canpickup(lf, o, 1) || caneat(lf,o)) ) { + if (o && !isdangerousob(o, lf, B_TRUE) && aipickupok(lf, o) && (canpickup(lf, o, 1) || caneat(lf,o)) ) { if (db) dblog(".oO { current cell has ob with flag i want (%s) }",o->type->name); // try to pick it up if (!aipickup(lf, o)) return B_TRUE; diff --git a/attack.c b/attack.c index 2758938..267f4c9 100644 --- a/attack.c +++ b/attack.c @@ -59,9 +59,14 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty // ALL of damage reduction goes towards armour } else { // SOME of the damage reduction goes towards the armour + // damage taken by armour is reduced by half its armour rating if (ar) { - actualdam -= rnd(0,ar); - limit(&actualdam, 0, NA); + int max; + max = ar/2; + if (max >= 1) { + actualdam -= rnd(0,max); + limit(&actualdam, 0, NA); + } } } @@ -124,6 +129,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { int attacktime; int gotweapon = B_FALSE; int maxattacks = ALL; + int attacksdone = 0; int lastweaponidx = -1; flag_t *sf; @@ -180,7 +186,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { }; } else { // TODO: attack wall? - if (isplayer(lf)) { + if (isplayer(lf) && !lfhasflag(lf, F_HURRICANESTRIKE)) { msg("There is nothing there to attack!"); } return B_TRUE; @@ -272,7 +278,7 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { //maxattacks = nweps; // ie. all - maxattacks = getmaxattacks(lf); + maxattacks = getattacks(lf, NULL, NULL); /* // if we have a weapon, this takes the place of one of our @@ -317,22 +323,28 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } // remember initial cells - for (i = 0; i < nweps; i++) { - if (validwep[i]) { - if (attacktype == AT_LF) { - if (!isdead((lifeform_t *)attacktarget)) { - if (attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i])) break; + + attacksdone = 0; + while (attacksdone < maxattacks) { + for (i = 0; (i < nweps) && (attacksdone < maxattacks); i++) { + if (validwep[i]) { + if (attacktype == AT_LF) { + if (!isdead((lifeform_t *)attacktarget)) { + if (attacklf(lf, (lifeform_t *)attacktarget, wep[i], damflag[i])) break; + } + } else if (attacktype == AT_OB) { + if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; } - } else if (attacktype == AT_OB) { - if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; } - } + attacksdone++; - // stop attacking if they somehow got out of range - // (eg. dodging) - if (attacktype == AT_LF) { - if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { - break; + // stop attacking if they somehow got out of range + // (eg. dodging) + if (attacktype == AT_LF) { + if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { + attacksdone = maxattacks; + break; + } } } } @@ -662,8 +674,8 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) !ismeleedam(damtype[i])) { verb = getattackverb(lf, wep, damtype[i], dam[i], victim->maxhp); } else { - verb = strdup("hit"); - needfree = B_TRUE; + // always use verb for 10% + verb = getattackverb(lf, wep, damtype[i], pctof(10, victim->maxhp), victim->maxhp); } } warn("You %s %s%s%s%s", @@ -708,7 +720,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) needses(attackverb) ? "es" : "s", victimname,withwep, nodamstr); } - noise(lf->cell, lf, 3, "sounds of fighting.", NULL); + noise(lf->cell, lf, NC_OTHER, 3, "sounds of fighting.", NULL); } @@ -897,6 +909,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) msg("%s misses %s.", buf, victimname); } } + + // train evasion + practice(victim, SK_EVASION, 1); if (lfhasflag(victim, F_DODGES)) { cell_t *adj; @@ -1043,7 +1058,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { msg("%s %ss %s%s.", attackername, getattackverb(lf, wep, damtype[i],dam[i],maxhp), obname,withwep); } else { - noise(lf->cell, NULL, 3, "sounds of fighting.", NULL); + noise(lf->cell, NULL, NC_OTHER, 3, "sounds of fighting.", NULL); } if ((i == 0) && (wep->type->id == OT_FISTS) && hasflag(o->flags, F_HARDNESS)) { @@ -1107,7 +1122,7 @@ int getarmourdamreduction(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE d int pctrange; object_t *o; - ar = getarmourrating(lf); + ar = getarmourrating(lf, NULL, NULL, NULL); //reducepct = getdamreducepct(ar); //reduceamt = (int) ceil((reducepct / 100.0) * (float)dam); @@ -1760,7 +1775,7 @@ void modifyforsize(int *val, lifeform_t *lf, lifeform_t *victim, int howmuch, en // returns true if we hit int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) { int acc,ev; - int gothit; + int gothit = B_FALSE; enum SKILLLEVEL slev; int myroll; flag_t *f; @@ -1791,7 +1806,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) killflag(f); } gothit = B_TRUE; - } else if (critical) { + } else if (critical && *critical) { gothit = B_TRUE; } else { // actually roll... diff --git a/defs.h b/defs.h index b5e33eb..27feb42 100644 --- a/defs.h +++ b/defs.h @@ -17,6 +17,7 @@ */ // ncurses colours +#define C_NONE -1 enum COLOUR { C_BLACK = 0, C_RED = 1, @@ -35,6 +36,14 @@ enum COLOUR { C_ORANGE = 13, C_BOLDGREEN = 14, }; +#define BLUEBG 50 + + +enum NOISECLASS { + NC_NONE = 0, + NC_SPEECH = 1, + NC_OTHER = 2, +}; enum SPEECHVOL { SV_SILENT = 0, @@ -54,6 +63,7 @@ enum SKILL { SK_CHANNELING, SK_CLIMBING, SK_COOKING, + SK_EVASION, SK_FIRSTAID, SK_LISTEN, SK_LOCKPICKING, @@ -61,6 +71,7 @@ enum SKILL { SK_RANGED, SK_SEWING, SK_SHIELDS, + SK_SPEECH, SK_SPELLCASTING, SK_SPOTHIDDEN, SK_STEALTH, @@ -100,7 +111,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 50 +#define MAXSKILLS 52 // proficiency levels enum SKILLLEVEL { @@ -146,14 +157,16 @@ enum ATTRIB { A_DEX = 1, A_IQ = 2, A_CON = 3, + A_CHA = 4, }; -#define MAXATTS 4 +#define MAXATTS 5 enum CHECKTYPE { SC_STR, SC_DEX, SC_IQ, SC_CON, + SC_CHA, ////////// SC_CLIMB, SC_DISARM, @@ -473,6 +486,18 @@ enum SPELLSCHOOL { SS_LAST, }; +enum CHABRACKET { + CH_RANDOM = -1, + CH_HIDEOUS = 0, + CH_REPULSIVE, + CH_UGLY, + CH_UNATTRACTIVE, + CH_AVERAGE, + CH_ATTRACTIVE, + CH_ALLURING, + CH_BEAUTIFUL, +}; + enum STRBRACKET { ST_RANDOM = -1, ST_HELPLESS = 0, @@ -741,6 +766,7 @@ enum JOB { J_BARBARIAN, J_COMMANDO, J_DRUID, + J_MONK, J_PIRATE, J_PLUMBER, J_PRINCE, @@ -833,6 +859,7 @@ enum OBTYPE { // flora OT_FLOWER, OT_LEAF, + OT_MISTLETOE, OT_SHRUB, OT_STUMP, OT_TREE, @@ -883,6 +910,7 @@ enum OBTYPE { OT_POT_JUICE, // scrolls OT_MAP, + OT_GRAPHPAPER, OT_SCR_NOTHING, OT_SCR_CREATEMONSTER, OT_SCR_DETECTAURA, @@ -1451,6 +1479,9 @@ enum FLAG { F_NO_A, // this obname doesn't need to start with 'a' for singular (eg. gold) F_CONTAINSOB, // for vending machiens. v0 is ob letter // text is an object it contains. + F_MAPTO, // this object is a map to the world map at xy=v0/v1. + // optional v2 = obtypeid of target + // text = what this is a map to ie. "the nearest village" F_SIGNTEXT, // for 'sign' objects. f->text is what is says. F_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc F_STARTBLESSED, // v0 = b_blessed or b_cursed @@ -1535,6 +1566,8 @@ enum FLAG { // val1 = BIG means hit surrounding cells // val2 = ifactivated, only explodes if activated. F_EXPLODEONDAM, // explodes when it is damaged, deals TEXT damage. + // v0 = damage type which makes it explode. + // NA means 'any damage type' // val1 = BIG means hit surrounding cells // val2 = ifactivated, only explodes if activated. F_FLASHONDEATH, // produce a bright flash when it dies,v0=range @@ -1976,6 +2009,7 @@ enum FLAG { F_GRABBEDBY,// you've been grabbed by lf id v0 F_GRABBING, // you are grabbing lf id v0 F_HEAVYBLOW, // next attack is a heavy blow + F_HURRICANESTRIKE, // lf is performing a hurricane strike F_HIDING, // lifeform is hiding. v0 is modifier to stealth checks. F_INVISIBLE, // lifeform is invisible F_INVULNERABLE,// immune to most damage @@ -2032,7 +2066,8 @@ enum FLAG { F_HASSKILL, // lf has skill v0 at level v1 F_PRACTICINGSKILL, // lf is pract skill v0 // COMBAT - F_MAXATTACKS, // v0 = max # attacks this lf can make per round + F_MAXATTACKS, // v0 = min # attacks this lf can make per round + // v1 = max # attacks this lf can make per round F_HASATTACK, // v0 = obid to use when attacking unarmed // if text is set, it overrides the damage F_EVASION, // % chance of evading an attack @@ -2050,11 +2085,14 @@ enum FLAG { F_RESTUNTILMP, // resting until we have full mp F_RESTUNTILALLIES, // resting until allies have full hp // - F_RUNNING, // are we running? + F_RUNNING, // are we running? (shift+dir) + // v0 is last dir moved. + // v1 is whether we have turned yet. // nutrition F_HUNGER, // val0 = hunger, higher = hungrier // for jobs (job flags) + F_SELECTWEAPON, // this job gets to pick their starting weapon F_NOPLAYER, // players can't pick this job F_HASPET, // this job starts with a pet of race f->text F_IFPCT, // only add the NEXT job flag if rnd(1,100) <= v0. @@ -2211,65 +2249,66 @@ enum SPELLTARGET { enum ERROR { E_OK = 0, E_WALLINWAY = 1, - E_LFINWAY = 2, - E_NOSPACE = 3, - E_SELNOTHING = 4, - E_ALREADYUSING = 5, - E_WEARINGSOMETHINGELSE = 6, - E_NOUNARMEDATTACK = 7, - E_NOTEQUIPPED = 8, - E_NOPICKUP = 9, - E_MONSTERNEARBY = 10, - E_NOEFFECT = 11, - E_FAILED = 12, - E_WRONGCELLTYPE = 13, - E_OBINWAY = 14, - E_TOOHEAVY = 15, - E_NOHANDS = 16, - E_NOPACK = 17, - E_INSUBSTANTIAL = 18, - E_WRONGOBTYPE = 19, - E_CURSED = 20, - E_NOLOS = 21, - E_NOLOF = 22, - E_IMPOSSIBLE = 23, - E_NOTARGET = 24, - E_NOAMMO = 25, - E_GRAVBOOSTED = 26, - E_NOMP = 27, - E_AVOIDOB = 28, - E_FROZEN = 29, - E_TOOBIG = 30, - E_NOTREADY = 31, - E_BLIND = 32, - E_GRABBEDBY = 33, - E_CANTMOVE = 34, - E_NOTKNOWN = 35, - E_TOOPOWERFUL = 36, - E_NEEDGRAB = 37, - E_DOORINWAY = 38, - E_NOCANNIBUL = 39, - E_LOWCON = 40, - E_LOWDEX = 41, - E_LOWIQ = 42, - E_LOWSTR = 43, - E_WONT = 44, - E_OFFMAP = 45, + E_LFINWAY, + E_NOSPACE, + E_SELNOTHING, + E_ALREADYUSING, + E_WEARINGSOMETHINGELSE, + E_NOUNARMEDATTACK, + E_NOTEQUIPPED, + E_NOPICKUP, + E_MONSTERNEARBY, + E_NOEFFECT, + E_FAILED, + E_WRONGCELLTYPE, + E_OBINWAY, + E_TOOHEAVY, + E_NOHANDS, + E_NOPACK, + E_INSUBSTANTIAL, + E_WRONGOBTYPE, + E_CURSED, + E_NOLOS, + E_NOLOF, + E_IMPOSSIBLE, + E_NOTARGET, + E_NOAMMO, + E_GRAVBOOSTED, + E_NOMP, + E_AVOIDOB, + E_FROZEN, + E_TOOBIG, + E_NOTREADY, + E_BLIND, + E_GRABBEDBY, + E_CANTMOVE, + E_NOTKNOWN, + E_TOOPOWERFUL, + E_NEEDGRAB, + E_DOORINWAY, + E_NOCANNIBUL, + E_LOWCON, + E_LOWDEX, + E_LOWIQ, + E_LOWSTR, + E_LOWCHA, + E_WONT, + E_OFFMAP, // charm failure reasons - // LOWIQ = 42 - E_UNDEAD = 46, - E_DRUNK = 47, + // LOWIQ + E_UNDEAD, + E_DRUNK, // - E_NOBP = 48, - E_VEGETARIAN = 49, - E_PARTVEGETARIAN = 50, - E_CARNIVORE = 51, - E_NOOB = 52, - E_LEVITATING = 53, - E_PRONE = 54, - E_PENTAGRAM = 55, - E_SWIMMING = 56, - E_DANGEROUS = 57, + E_NOBP, + E_VEGETARIAN, + E_PARTVEGETARIAN, + E_CARNIVORE, + E_NOOB, + E_LEVITATING, + E_PRONE, + E_PENTAGRAM, + E_SWIMMING, + E_DANGEROUS, }; @@ -2575,6 +2614,7 @@ typedef struct lifeform_s { int born; // for ai movement - don't need to save. + struct cell_s *prevcell[2]; struct cell_s *cell; struct lifeform_s *next, *prev; diff --git a/doc/add_attrib.txt b/doc/add_attrib.txt index 5c9d344..8d6a6a2 100644 --- a/doc/add_attrib.txt +++ b/doc/add_attrib.txt @@ -11,9 +11,10 @@ lf.c: update rollstat() add rollxxx() update skillcheck() - update gainlevel() question - update givejob() + update enhanceskills() question if you can up this at levelup update modattr() + + update jobs io.c: update announceflaggain() and loss() for this stat text.c: diff --git a/doc/add_skill.txt b/doc/add_skill.txt index 54824c5..68727c4 100644 --- a/doc/add_skill.txt +++ b/doc/add_skill.txt @@ -1,13 +1,11 @@ defs.h: add SK_xxx inc MAXSKILLS - add OT_MAN_xxx for this skill - -objects.c: - add a manual for this skill lf.c: add addskill() + if it is a lore skill, update isloreskill() + if it is a weapon skill, update isweaponskill() - if it is a lroe skill, update isloreskill() + assign to jobs diff --git a/io.c b/io.c index ec5060d..e79fb16 100644 --- a/io.c +++ b/io.c @@ -1040,6 +1040,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { case A_STR: msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "weaker" : "stronger"); break; + case A_CHA: + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less attractive" : "more attractive"); + break; case A_IQ: msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "foolish" : "smarter"); break; @@ -1060,6 +1063,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { case A_STR: msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "weak" : "strong"); break; + case A_CHA: + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "ugly" : "attractive"); + break; case A_IQ: msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "foolish" : "smart"); break; @@ -1557,6 +1563,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { 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 foolish"); break; @@ -1577,6 +1586,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { 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 foolish"); break; @@ -2269,7 +2281,7 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, int forpickup, int mvwprintw(mainwin, 2, 0, "There is nothing here."); } // wait for key - centre(mainwin, getmaxy(mainwin)-1, "[Press any key]"); + centre(mainwin, C_WHITE, getmaxy(mainwin)-1, "[Press any key]"); getch(); restoregamewindows(); @@ -2465,7 +2477,7 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { cls(); mvwprintw(mainwin, 2, 0, "You have no possessions."); // wait for key - centre(mainwin, getmaxy(mainwin)-1, "[Press any key]"); + centre(mainwin,C_WHITE, getmaxy(mainwin)-1, "[Press any key]"); getch(); restoregamewindows(); @@ -2683,7 +2695,7 @@ vault_t *askvault(char *prompttext) { return v; } -void centre(WINDOW *win, int y, char *format, ... ) { +void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ) { int w; char buf[BUFLEN]; va_list args; @@ -2696,16 +2708,18 @@ void centre(WINDOW *win, int y, char *format, ... ) { w = getmaxx(win); startx = (w/2) - (strlen(buf)/2); if (startx < 0) startx = 0; + if (col != C_NONE) setcol(win, col); mvwprintw(win, y, (w/2) - (strlen(buf)/2), buf); + if (col != C_NONE) unsetcol(win, col); } int chartodir(char c) { switch (tolower(c)) { - case 'h': return D_W; - case 'j': return D_S; - case 'k': return D_N; - case 'l': return D_E; + case 'h': return DC_W; + case 'j': return DC_S; + case 'k': return DC_N; + case 'l': return DC_E; case 'y': return DC_NW; case 'u': return DC_NE; case 'b': return DC_SW; @@ -2939,7 +2953,7 @@ void describeob(object_t *o) { // weapons? if (o->type->obclass->id == OC_WEAPON) { int delay; - mvwprintw(mainwin, y, 0, "It is a weapon."); + 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)) { int bonus = 0; @@ -3055,6 +3069,8 @@ void describeob(object_t *o) { evmod = adjustarmourpenalty(player, f->val[0]); if (evmod != 0) { sprintf(buf, " When worn, it %s your evasion chance by %d%%.", (evmod < 0) ? "reduces" : "increases", abs(evmod)); + mvwprintw(mainwin, y, 0, "%s",buf); + y++; } } @@ -3070,9 +3086,43 @@ void describeob(object_t *o) { f = hasflag(o->flags, F_GOESON); if (f) { sprintf(buf, "It is worn %s your %s. ",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); + mvwprintw(mainwin, y, 0, "%s",buf); + y++; } } + if (hasflag(o->flags, F_DAMAGABLE) && isarmour(o) ) { + int showfullhp = B_FALSE; + char hpbuf[BUFLEN]; + f = hasflag(o->flags, F_OBHP); + if (isarmour(o) && getskill(player, SK_ARMOUR)) { + showfullhp = B_TRUE; + } else if ((o->type->material->id == MT_METAL) && getskill(player, SK_METALWORK)) { + showfullhp = B_TRUE; + } else if ( ((o->type->material->id == MT_LEATHER) || (o->type->material->id == MT_CLOTH)) && + getskill(player, SK_SEWING)) { + showfullhp = B_TRUE; + } + + if (isdamaged(o)) { + sprintf(buf, "It has been damaged."); + } else { + sprintf(buf, "It is in perfect condition."); + } + if (showfullhp) { + sprintf(hpbuf, " [%d/%d hp]", f->val[0], f->val[1]); + } else if (isdamaged(o)) { + int pct; + pct = (int)(((float)f->val[0] / (float)f->val[1]) * 100.0); + sprintf(hpbuf, " [%d%% hp]", pct); + } else { + strcpy(hpbuf, ""); + } + strcat(buf, hpbuf); + mvwprintw(mainwin, y, 0, "%s", buf); + y++; + } + if (o->type->obclass->id == OC_WAND) { if (isidentified(o)) { int charges; @@ -3862,7 +3912,7 @@ void docomms(lifeform_t *lf) { break; case 'y': msg("You shout at %s!", lfname); - noise(where, player, 3, "someone shouting!", NULL); + noise(where, player, NC_OTHER, 3, "someone shouting!", NULL); break; } taketime(player, getactspeed(player)); @@ -4059,7 +4109,7 @@ void dovendingmachine(lifeform_t *lf, object_t *vm) { cls(); mvwprintw(mainwin, 0, 0, toptext); y = 2; - centre(mainwin, y, "VENDING MACINE"); + centre(mainwin,C_WHITE, y, "VENDING MACINE"); y += 2; // list objects for sale @@ -4223,7 +4273,11 @@ void doknowledgelist(void) { first = B_FALSE; } - mvwprintw(mainwin, y, 0, " %-25s (%s)",ot->name, k->hiddenname); + if (k->known == B_KNOWN) { + mvwprintw(mainwin, y, 0, " %-25s (%s)",ot->name, k->hiddenname); + } else { // ie. tried + mvwprintw(mainwin, y, 0, " %-25s (%s)","???", k->hiddenname); + } y++; numfound++; @@ -4621,11 +4675,7 @@ void dooperate(obpile_t *op) { // ask which object to read o = askobject(op, "Operate what", NULL, AO_OPERABLE); if (o) { - if (isoperable(o)) { - operate(player, o, NULL); - } else { - msg("You can't operate that!"); - } + operate(player, o, NULL); } } @@ -4779,20 +4829,20 @@ void dohelp(void) { h = getmaxy(mainwin); cls(); - centre(mainwin, 0, "COMMAND REFERENCE"); + centre(mainwin,C_WHITE, 0, "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, h-1, "[Press any key]"); + centre(mainwin,C_WHITE, h-1, "[Press any key]"); getch(); cls(); y = 2; } } - centre(mainwin, h-1, "[Press any key]"); + centre(mainwin,C_WHITE, h-1, "[Press any key]"); getch(); restoregamewindows(); @@ -5242,9 +5292,9 @@ int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, snprintf(headbuf, w-1, "%s (continued)", heading); (*y)++; if (*y >= (h-3)) { - centre(mainwin, h-2, MORESTRING); + centre(mainwin,C_WHITE, h-2, MORESTRING); if (bottomstring) { - centre(mainwin, h-1, bottomstring); + centre(mainwin, C_WHITE, h-1, bottomstring); } ch = getch(); if (cmdchars && strchr(cmdchars, ch)) { @@ -5256,7 +5306,7 @@ int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, } cls(); *y = 0; - centre(mainwin, *y, headbuf); + centre(mainwin, C_WHITE, *y, headbuf); *y += 2; wmove(mainwin, *y, 0); @@ -5399,11 +5449,19 @@ void doheading(WINDOW *win, int *y, int x, char *what) { buf = malloc(len * sizeof(char)); memset(buf, '-', (size_t)(len-1)); buf[len] = '\0'; + setcol(win, C_WHITE); mvwprintw(win, *y, x, what); (*y)++; mvwprintw(win, *y, x, buf); (*y)++; + unsetcol(win, C_WHITE); free(buf); } +void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading) { + setcol(win, C_WHITE); + mvwprintw(mainwin, y, x, format, heading); + unsetcol(win, C_WHITE); +} + void initgfx(void) { int msgwinh = 2; int statwinh = 2; @@ -5438,6 +5496,25 @@ void initgfx(void) { init_pair(C_BOLDGREEN, COLOR_GREEN, COLOR_BLACK); init_pair(C_ORANGE, COLOR_RED, COLOR_BLACK); + + init_pair(BLUEBG+C_BLACK, COLOR_BLACK, COLOR_BLUE); + init_pair(BLUEBG+C_RED, COLOR_RED, COLOR_BLUE); + init_pair(BLUEBG+C_GREEN, COLOR_GREEN, COLOR_BLUE); + init_pair(BLUEBG+C_BROWN, COLOR_YELLOW, COLOR_BLUE); + init_pair(BLUEBG+C_YELLOW, COLOR_YELLOW, COLOR_BLUE); + init_pair(BLUEBG+C_BLUE, COLOR_BLUE, COLOR_BLUE); + init_pair(BLUEBG+C_MAGENTA, COLOR_MAGENTA, COLOR_BLUE); + init_pair(BLUEBG+C_CYAN, COLOR_CYAN, COLOR_BLUE); + init_pair(BLUEBG+C_GREY, COLOR_WHITE, COLOR_BLUE); + init_pair(BLUEBG+C_YELLOW, COLOR_YELLOW, COLOR_BLUE); + init_pair(BLUEBG+C_WHITE, COLOR_WHITE, COLOR_BLUE); + init_pair(BLUEBG+C_BOLDCYAN, COLOR_CYAN, COLOR_BLUE); + init_pair(BLUEBG+C_BOLDBLUE, COLOR_BLUE, COLOR_BLUE); + init_pair(BLUEBG+C_BOLDMAGENTA, COLOR_MAGENTA, COLOR_BLUE); + init_pair(BLUEBG+C_BOLDGREEN, COLOR_GREEN, COLOR_BLUE); + init_pair(BLUEBG+C_ORANGE, COLOR_RED, COLOR_BLUE); + + noecho(); cbreak(); nodelay(mainwin, FALSE); @@ -5481,22 +5558,29 @@ int drop(object_t *o, int count) { getobname(o, obname, count); origid = o->type->id; + + // have to announce this before aclling drop, because + // drop might trigger 'the xx falls down a hole' etc + if (isplayer(op->owner)) { + msg("You drop %s.",obname); + } else if (cansee(player, op->owner)) { + char ownername[BUFLEN]; + getlfname(op->owner, ownername); + msg("%s drops %s.",ownername, obname); + } + newob = moveob(o, op->owner->cell->obpile, count); + if (newob) { // if drop was successful... //taketime(op->owner, (SPEED_DROP * count)); taketime(op->owner, SPEED_DROP); // if object wasn't changed... + /* if (newob->type->id == origid) { if (op->owner) { - 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); - } } } + */ } else { // tell the player why! if (isplayer(op->owner)) { @@ -5927,16 +6011,18 @@ enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev) { switch (slev) { case PR_INEPT: return C_RED; - case PR_BEGINNER: case PR_NOVICE: return C_BROWN; + case PR_BEGINNER: + return C_GREY; case PR_ADEPT: return C_GREEN; case PR_SKILLED: - case PR_EXPERT: return C_BOLDGREEN; - case PR_MASTER: + case PR_EXPERT: return C_BOLDCYAN; + case PR_MASTER: + return C_BOLDMAGENTA; } return C_GREY; } @@ -5952,32 +6038,78 @@ void handleinput(void) { // if running, automatically do move f = hasflag(player->flags, F_RUNNING); if (f) { - int dir; - int hasgettableobs = B_FALSE; - dir = f->val[0]; + int rundir = D_NONE; + int lastdir; + int ihaveturned; + int stopnow = B_FALSE; + lastdir = f->val[0]; + ihaveturned = f->val[1]; object_t *o; - // certain objects will stop us from running. for (o = player->cell->obpile->first ; o ; o = o->next) { if (!hasflag(o->flags, F_NOPICKUP) || hasflag(o->flags, F_CLIMBABLE) ) { - hasgettableobs = B_TRUE; + stopnow = B_TRUE; break; } } - + if (countadjcellswithflag(player->cell, F_DOOR, DT_COMPASS)) { + stopnow = B_TRUE; + } + // stop if enter/exit a room + if (player->prevcell[0] && (player->cell->roomid != player->prevcell[0]->roomid)) { + stopnow = B_TRUE; + } // something here? - if (hasgettableobs) { - stoprunning(player); - } else if (!moveclear(player, dir, NULL)) { // can't move anymore? + if (stopnow) { + } else if (!ihaveturned && moveclear(player, lastdir, NULL)) { + // go the same dir if we can. + rundir = lastdir; + } else { + int dir; + int poss[MAXDIR_COMPASS],nposs; + // we have now turned + f->val[1] = B_TRUE; + // check how many possible moves we have. + nposs = 0; + for (dir = DC_N; dir <= DC_W; dir+= 2) { // ie. only go orthogonally from now on + // don't count the way we just came from + if (dir == diropposite(lastdir)) continue; + if (moveclear(player,dir, NULL)) { + cell_t *adjcell; + // if not in last two spots moved... + adjcell = getcellindir(player->cell, dir); + if ((adjcell != player->prevcell[0]) && (adjcell != player->prevcell[1])) { + poss[nposs++] = dir; + } + } + } + // only one possible direction? + if (nposs == 1) { + rundir = poss[0]; + } else { + // stop running + stoprunning(player); + stopnow = B_TRUE; + } + } + + if (rundir == D_NONE) { + stopnow = B_TRUE; + } + + if (stopnow) { stoprunning(player); } else { - if (trymove(player, dir, B_TRUE)) { + if (trymove(player, rundir, B_TRUE)) { + // failed. stoprunning(player); } else { - // moved ok - dont wait for input + // moved ok. remember this dir. + f->val[0] = rundir; + // our turn ends return; } } @@ -6478,18 +6610,25 @@ void drawstatus(void) { curs_set(0); wclear(statwin); + xpleft = getxpforlev(player->level + 1) - player->xp; - sprintf(buf, "[%-26s] Lv:%d", pname, - player->level); - mvwprintw(statwin, 0, 0, buf); + wmove(statwin, 0, 0); + wattron(statwin, A_BOLD); wprintw(statwin, "["); wattroff(statwin, A_BOLD); + wprintw(statwin, "%-26s ", pname); + wattron(statwin, A_BOLD); wprintw(statwin, "] "); wattroff(statwin, A_BOLD); + + wattron(statwin, A_BOLD); wprintw(statwin, "Lv:"); wattroff(statwin, A_BOLD); + sprintf(buf, "%d", player->level); + wprintw(statwin, buf); if (lfhasflag(player, F_HASNEWLEVEL)) { setcol(statwin, C_BOLDGREEN); wprintw(statwin, " LevUp",xpleft); unsetcol(statwin, C_BOLDGREEN); } else { - wprintw(statwin, " Next:%ld",xpleft); + wattron(statwin, A_BOLD); wprintw(statwin, " Next:"); wattroff(statwin, A_BOLD); + wprintw(statwin, "%ld",xpleft); } // blinded? if (isblind(player) && !lfhasflag(player, F_ASLEEP)) { @@ -6532,9 +6671,9 @@ void drawstatus(void) { wprintw(statwin, " Resting"); unsetcol(statwin, C_CYAN); } else if (lfhasflag(player, F_ASLEEP)) { - setcol(statwin, C_BLUE); + setcol(statwin, C_MAGENTA); wprintw(statwin, " Asleep"); - unsetcol(statwin, C_BLUE); + unsetcol(statwin, C_MAGENTA); } else if (isprone(player)) { setcol(statwin, C_YELLOW); wprintw(statwin, " Prone"); @@ -6679,13 +6818,13 @@ void drawstatus(void) { // good effects f = lfhasflag(player, F_HIDING); if (f) { - setcol(statwin, C_BLUE); + setcol(statwin, C_MAGENTA); if (f->val[0] < 0) { wprintw(statwin, " Hiding--"); } else { wprintw(statwin, " Hiding"); } - unsetcol(statwin, C_BLUE); + unsetcol(statwin, C_MAGENTA); } // construct waiting string @@ -6726,7 +6865,8 @@ void drawstatus(void) { // HP - mvwprintw(statwin, 1, 0, "HP:"); + wmove(statwin, 1, 0); + 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)); @@ -6734,21 +6874,28 @@ void drawstatus(void) { // MP if (getmaxmp(player) > 0) { - wprintw(statwin, "MP:"); + 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 { - wprintw(statwin, "MP:- "); + wattron(statwin, A_BOLD); wprintw(statwin, "MP:"); wattroff(statwin, A_BOLD); + wprintw(statwin, "- "); } - sprintf(buf, "$:%d AR:%d ", countmoney(player), getarmourrating(player)); + wattron(statwin, A_BOLD); wprintw(statwin, "$:"); wattroff(statwin, A_BOLD); + sprintf(buf, "%d ", countmoney(player)); + wprintw(statwin, buf); + wattron(statwin, A_BOLD); wprintw(statwin, "AR:"); wattroff(statwin, A_BOLD); + sprintf(buf, "%d ", getarmourrating(player, NULL, NULL, NULL)); wprintw(statwin, buf); + wattron(statwin, A_BOLD); wprintw(statwin, "EV:"); wattroff(statwin, A_BOLD); + wprintw(statwin, "%d ", getevasion(player)); for (a = 0; a < MAXATTS; a++) { - wprintw(statwin, "%s:", getattrabbrev(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 { @@ -6864,7 +7011,7 @@ void setobcolour(WINDOW *win, object_t *o, int set) { if (!o) return; // unpaid? - if (hasflag(o->flags, F_SHOPITEM)) { + if (hasflag(o->flags, F_SHOPITEM) && o->pile->owner) { funcptr(win, C_ORANGE); return; } @@ -6898,9 +7045,9 @@ void showlfarmour(lifeform_t *lf) { cls(); if (isplayer(lf)) { - centre(mainwin, 0, "CHARACTER EQUIPMENT"); + centre(mainwin, C_WHITE, 0, "CHARACTER EQUIPMENT"); } else{ - centre(mainwin, 0, "MONSTER EQUIPMENT"); + centre(mainwin, C_WHITE, 0, "MONSTER EQUIPMENT"); } y = 2; @@ -6939,7 +7086,7 @@ void showlfarmour(lifeform_t *lf) { } } y = getmaxy(mainwin); - centre(mainwin, y-1, "[Press any key]"); + centre(mainwin, C_WHITE, y-1, "[Press any key]"); /* @@ -6998,6 +7145,7 @@ void showlfstats(lifeform_t *lf, int showall) { int done = B_FALSE; enum SKILLLEVEL lorelev; enum COLOUR lorecol; + int min,max; h = getmaxy(mainwin); @@ -7038,9 +7186,9 @@ void showlfstats(lifeform_t *lf, int showall) { ch = '\0'; if (mode == '@') { if (isplayer(lf)) { - centre(mainwin, 0, "CHARACTER DETAILS"); + centre(mainwin, C_WHITE, 0, "CHARACTER DETAILS"); } else{ - centre(mainwin, 0, "MONSTER DETAILS"); + centre(mainwin, C_WHITE, 0, "MONSTER DETAILS"); } y = 2; y2 = 2; @@ -7053,34 +7201,34 @@ void showlfstats(lifeform_t *lf, int showall) { } else { getlfnamea(lf, buf); } - mvwprintw(mainwin, y, 0, ftext, "Name"); + doheadingsmall(mainwin, y, 0, ftext, "Name"); wprintw(mainwin, "%-20s", buf); y++; if (isplayer(lf)) { - mvwprintw(mainwin, y, 0, ftext, "Race"); + doheadingsmall(mainwin, y, 0, ftext, "Race"); wprintw(mainwin, "%-20s", lf->race->name); y++; } else { - mvwprintw(mainwin, y, 0, ftext, "Type"); + doheadingsmall(mainwin, y, 0, ftext, "Type"); wprintw(mainwin, "%-20s", lf->race->raceclass->name); y++; } j = getjob(lf); if (j) { - mvwprintw(mainwin, y, 0, ftext, "Job"); + doheadingsmall(mainwin, y, 0, ftext, "Job"); sprintf(buf, "Level %d %s", lf->level, j->name); wprintw(mainwin, "%-20s", buf); y++; } // size - mvwprintw(mainwin, y, 0, ftext, "Size"); + doheadingsmall(mainwin, y, 0, ftext, "Size"); wprintw(mainwin, "%-20s", getsizetext(getlfsize(lf))); y++; if (showall) { float w; w = getlfweight(lf, B_NOOBS); - mvwprintw(mainwin, y, 0, ftext, "Weight"); + doheadingsmall(mainwin, y, 0, ftext, "Weight"); getweighttext(w, buf); wprintw(mainwin, buf, w); y++; } @@ -7090,15 +7238,15 @@ void showlfstats(lifeform_t *lf, int showall) { if (showall || (getseenlfconditioncutoff(player) == C_HEALTHY) || (lorelev >= PR_ADEPT)) { + doheadingsmall(mainwin, y, 0, ftext, "Hit Points"); if (lorelev >= PR_ADEPT) setcol(mainwin, lorecol); - mvwprintw(mainwin, y, 0, ftext, "Hit Points"); wprintw(mainwin, "%d / %d", lf->hp , lf->maxhp); y++; if (lorelev >= PR_ADEPT) unsetcol(mainwin, lorecol); } else { char hpinfo[BUFLEN]; sprintf(hpinfo, "%s",getseenlfconditionname(lf, player)); if (strlen(hpinfo) > 0) { - mvwprintw(mainwin, y, 0, ftext, "Hit Points"); + doheadingsmall(mainwin, y, 0, ftext, "Hit Points"); wprintw(mainwin, "%s", hpinfo); y++; } } @@ -7111,11 +7259,11 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(maxmpstr, "(%d)",lf->maxmp); } - mvwprintw(mainwin, y, 0, ftext, "Mana"); + doheadingsmall(mainwin, y, 0, ftext, "Mana"); wprintw(mainwin, "%d / %d%s", lf->mp , lf->maxmp,maxmpstr); y++; } if (showall) { - mvwprintw(mainwin, y, 0, ftext, "Exp Level"); + doheadingsmall(mainwin, y, 0, ftext, "Exp Level"); if (isplayer(lf)) { xpneeded = getxpforlev(lf->level + 1) - lf->xp; wprintw(mainwin, "%d (%ld XP, %ld for next)", lf->level, lf->xp, xpneeded); y++; @@ -7125,7 +7273,7 @@ void showlfstats(lifeform_t *lf, int showall) { if (isplayer(lf)) { int attpoints; attpoints = getattpoints(lf); - mvwprintw(mainwin, y, 0, ftext, "Training"); + doheadingsmall(mainwin, y, 0, ftext, "Training"); if ((lf->skillpoints == 0) && (attpoints == 0)) { wprintw(mainwin, "n/a"); } else { @@ -7152,16 +7300,16 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(buf, "%d (%s, -%d%% dmg)",str, buf2, (int)(100 - (dammod * 100)) ); } if (str != lf->baseatt[A_STR]) strcat(buf, "*"); - mvwprintw(mainwin, y, 0, ftext, "STR"); + doheadingsmall(mainwin, y, 0, ftext, "Strength"); wprintw(mainwin, "%s", buf); y++; } else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) { int str; // just show name str = getattr(lf, A_STR); getstrname(str, buf); + doheadingsmall(mainwin, y, 0, ftext, "Strength"); if (str != lf->baseatt[A_STR]) strcat(buf, "*"); setcol(mainwin, lorecol); - mvwprintw(mainwin, y, 0, ftext, "STR"); wprintw(mainwin, "%s", buf); y++; unsetcol(mainwin, lorecol); } @@ -7181,7 +7329,7 @@ void showlfstats(lifeform_t *lf, int showall) { } if (dex != lf->baseatt[A_DEX]) strcat(buf, "*"); - mvwprintw(mainwin, y, 0, ftext, "DEX"); + doheadingsmall(mainwin, y, 0, ftext, "Dexterity"); wprintw(mainwin, "%s", buf); y++; } else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) { int dex; @@ -7189,8 +7337,8 @@ void showlfstats(lifeform_t *lf, int showall) { dex = getattr(lf, A_DEX); getdexname(dex, buf); if (dex != lf->baseatt[A_DEX]) strcat(buf, "*"); + doheadingsmall(mainwin, y, 0, ftext, "Dexterity"); setcol(mainwin, lorecol); - mvwprintw(mainwin, y, 0, ftext, "DEX"); wprintw(mainwin, "%s", buf); y++; unsetcol(mainwin, lorecol); } @@ -7202,7 +7350,7 @@ void showlfstats(lifeform_t *lf, int showall) { getiqname(iq, buf2); sprintf(buf, "%d (%s)",iq, buf2); if (iq != lf->baseatt[A_IQ]) strcat(buf, "*"); - mvwprintw(mainwin, y, 0, ftext, "IQ"); + doheadingsmall(mainwin, y, 0, ftext, "Intelligence"); wprintw(mainwin, "%s", buf); y++; } else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) { int iq; @@ -7210,8 +7358,8 @@ void showlfstats(lifeform_t *lf, int showall) { iq = getattr(lf, A_IQ); getiqname(iq, buf); if (iq != lf->baseatt[A_IQ]) strcat(buf, "*"); + doheadingsmall(mainwin, y, 0, ftext, "Intelligence"); setcol(mainwin, lorecol); - mvwprintw(mainwin, y, 0, ftext, "IQ"); wprintw(mainwin, "%s", buf); y++; unsetcol(mainwin, lorecol); } @@ -7223,7 +7371,7 @@ void showlfstats(lifeform_t *lf, int showall) { getconname(con, buf2); sprintf(buf, "%d (%s)",con, buf2); if (con != lf->baseatt[A_CON]) strcat(buf, "*"); - mvwprintw(mainwin, y, 0, ftext, "CON"); + doheadingsmall(mainwin, y, 0, ftext, "Fitness"); wprintw(mainwin, "%s", buf); y++; } else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) { int con; @@ -7231,8 +7379,29 @@ void showlfstats(lifeform_t *lf, int showall) { con = getattr(lf, A_CON); getconname(con, buf); if (con != lf->baseatt[A_CON]) strcat(buf, "*"); + doheadingsmall(mainwin, y, 0, ftext, "Fitness"); + setcol(mainwin, lorecol); + wprintw(mainwin, "%s", buf); y++; + unsetcol(mainwin, lorecol); + } + + if (showall) { + char buf2[BUFLEN]; + int cha; + cha = getattr(lf, A_CHA); + getchaname(cha, buf2); + sprintf(buf, "%d (%s)",cha, buf2); + if (cha != lf->baseatt[A_CHA]) strcat(buf, "*"); + doheadingsmall(mainwin, y, 0, ftext, "Charisma"); + wprintw(mainwin, "%s", buf); y++; + } else if (!isplayer(lf) && (lorelev >= PR_NOVICE)) { + int cha; + // just show name + cha = getattr(lf, A_CHA); + getconname(cha, buf); + if (cha != lf->baseatt[A_CHA]) strcat(buf, "*"); + doheadingsmall(mainwin, y, 0, ftext, "Charisma"); setcol(mainwin, lorecol); - mvwprintw(mainwin, y, 0, ftext, "CON"); wprintw(mainwin, "%s", buf); y++; unsetcol(mainwin, lorecol); } @@ -7246,8 +7415,13 @@ void showlfstats(lifeform_t *lf, int showall) { // now go to second column - mvwprintw(mainwin, y2, x2, ftext, "# Attacks"); - wprintw(mainwin, "%d", getmaxattacks(lf)); y2++; + doheadingsmall(mainwin, y2, x2, ftext, "# Attacks"); + getattacks(lf, &min, &max); + if (min == max) { + wprintw(mainwin, "%d", max); y2++; + } else { + wprintw(mainwin, "%d-%d", min,max); y2++; + } y2++; // current weapon + dam @@ -7305,7 +7479,7 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(buf, "%s (%d-%d dmg)", w[i]->type->name,(int)mindam,(int)maxdam); - mvwprintw(mainwin, y2, x2, ftext, "Weapon"); + doheadingsmall(mainwin, y2, x2, ftext, "Weapon"); wprintw(mainwin, "%-20s", buf); y2++; // attack speed @@ -7320,13 +7494,13 @@ void showlfstats(lifeform_t *lf, int showall) { } else { // just show weapon name sprintf(buf, "%s", w[i]->type->name); - mvwprintw(mainwin, y2, x2, ftext, "Weapon"); + doheadingsmall(mainwin, y2, x2, ftext, "Weapon"); wprintw(mainwin, "%-20s", buf); y2++; } } else { // no weapon sprintf(buf, "N/A"); - mvwprintw(mainwin, y2, x2, ftext, "Current Weapon"); + doheadingsmall(mainwin, y2, x2, ftext, "Current Weapon"); wprintw(mainwin, "%-20s", buf); y2++; } } // end for each weapon @@ -7372,7 +7546,7 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(dambuf, " (%d-%d dmg)",(int)mindam,(int)maxdam); } - mvwprintw(mainwin, y2, x2, ftext, "Innate Attack"); + doheadingsmall(mainwin, y2, x2, ftext, "Innate Attack"); wprintw(mainwin, "%s", buf); if (strlen(dambuf)) { if (lorelev >= PR_BEGINNER) setcol(mainwin, lorecol); @@ -7389,7 +7563,7 @@ void showlfstats(lifeform_t *lf, int showall) { // no attacks at all? if ((nweps == 0) && !op->first) { sprintf(buf, "N/A"); - mvwprintw(mainwin, y2, x2, ftext, "Attack"); + doheadingsmall(mainwin, y2, x2, ftext, "Attack"); wprintw(mainwin, "%-20s", buf); y2++; } @@ -7400,11 +7574,10 @@ void showlfstats(lifeform_t *lf, int showall) { // ARMOUR STUFF if (showall || (lorelev >= PR_NOVICE)) { - arating = getarmourrating(lf); + arating = getarmourrating(lf, NULL, NULL, NULL); - if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol); - mvwprintw(mainwin, y2, x2, ftext, "Armour Rating"); + doheadingsmall(mainwin, y2, x2, ftext, "Armour Rating"); /* if (arating > 0) { wprintw(mainwin, "%d (-%0.0f%% dmg)", arating, getdamreducepct(arating)); y2++; @@ -7412,16 +7585,19 @@ void showlfstats(lifeform_t *lf, int showall) { wprintw(mainwin, "%d", arating); y2++; } */ + if (lorelev >= PR_NOVICE) setcol(mainwin, lorecol); wprintw(mainwin, "%d", arating); y2++; if (lorelev >= PR_NOVICE) unsetcol(mainwin, lorecol); } - if (showall) { + if (showall || (lorelev >= PR_NOVICE)) { evasion = getevasion(lf); - mvwprintw(mainwin, y2, x2, ftext, "Evasion"); + 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(player), actbuf); @@ -7433,7 +7609,7 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(buf, "Mv:%s Act:%s", movebuf,actbuf); } - mvwprintw(mainwin, y2, x2, ftext, "Speed"); + doheadingsmall(mainwin, y2, x2, ftext, "Speed"); wprintw(mainwin, "%-20s", buf); y2++; y2++; // skip line @@ -7442,10 +7618,10 @@ void showlfstats(lifeform_t *lf, int showall) { if (showall) { f = hasflag(lf->flags, F_HUNGER); if (f) { + doheadingsmall(mainwin, y2, x2, ftext, "Hunger"); + gethungername(gethungerlevel(f->val[0]), buf); capitalise(buf); - mvwprintw(mainwin, y2, x2, ftext, "Hunger"); - wprintw(mainwin, "%-14s", buf); y2++; /* if (showall) { @@ -7845,7 +8021,7 @@ void showlfstats(lifeform_t *lf, int showall) { int exitnow = B_FALSE; // now show intrinsics on next page - centre(mainwin, 0, "ABILITIES"); + centre(mainwin, C_WHITE, 0, "ABILITIES"); y = 2; for (ot = objecttype ; ot ; ot = ot->next) { @@ -7880,8 +8056,14 @@ void showlfstats(lifeform_t *lf, int showall) { } else { strcpy(eb2, ""); } - sprintf(buf, "%-12s%s%s", ot->name, ot->desc, eb2); + setcol(mainwin, C_GREEN); + sprintf(buf, "%-12s", ot->name); mvwprintw(mainwin, y, 0, buf); + unsetcol(mainwin, C_GREEN); + + sprintf(buf, "%s%s", ot->desc, eb2); + wprintw(mainwin, buf); + if (downline(&y, h, "ABILITIES", NULL, prompt, cmdchars, &ch)) { exitnow = B_TRUE; break; @@ -7913,16 +8095,20 @@ void showlfstats(lifeform_t *lf, int showall) { doheading(mainwin, &y, 0, skilltitle); for (n = 0; n < MAXOF(numknown,numavailable); n++) { if (n < numavailable) { + setcol(mainwin, C_RED); mvwprintw(mainwin, y, 0, "- %s", getskillname(available[n]->val[0]) ); + unsetcol(mainwin, C_RED); } if (n < numknown) { + setcol(mainwin, getskilllevelcolour(known[n]->val[1])); mvwprintw(mainwin, y, 40, "%c %s (%s)%s", ismaxedskill(lf, known[n]->val[0]) ? '*' : '-', getskillname(known[n]->val[0]), getskilllevelname(known[n]->val[1]), //ismaxedskill(lf, known[n]->val[0]) ? "/MAX" : "", (known[n]->lifetime == FROMSPELL) ? "[spell]" : ""); + unsetcol(mainwin, getskilllevelcolour(known[n]->val[1])); } if (downline(&y, h, "SKILLS", skilltitle, prompt, cmdchars, &ch)) { exitnow = B_TRUE; @@ -7938,7 +8124,7 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(subheading, " %-4s%-26s%-15s%-13s%s","Lv","Spell", "School", "Power", "Cost"); - centre(mainwin, y, "MAGIC"); y += 2; + centre(mainwin, C_WHITE, y, "MAGIC"); y += 2; doheading(mainwin, &y, 0, subheading); //if (!isplayer(lf)) { // show spells monster can cast using mp @@ -7959,6 +8145,7 @@ void showlfstats(lifeform_t *lf, int showall) { int power; int mpcost; int castable = B_TRUE; + int atwill = B_FALSE; // power power = getspellpower(lf, ot->id); @@ -7982,6 +8169,7 @@ void showlfstats(lifeform_t *lf, int showall) { sprintf(mpbuf, "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) { @@ -7991,15 +8179,19 @@ void showlfstats(lifeform_t *lf, int showall) { } } - if ((mpcost > getmaxmp(lf)) || (power <= 0)) { - castable = B_FALSE; + if (!atwill) { + if ((mpcost > getmaxmp(lf)) || (power <= 0)) { + castable = B_FALSE; + } } getspellname(ot->id, lf, spellname); - if (!castable) setcol(mainwin, C_RED); + if (castable) setcol(mainwin, C_GREEN); + else setcol(mainwin, C_RED); sprintf(buf, " %-4d%-26s%-15s%-13s%s",thislev, spellname, getschoolnameshort(getspellschoolknown(lf, ot->id)), powerbuf, mpbuf); mvwprintw(mainwin, y, 0, "%s\n", buf); - if (!castable) unsetcol(mainwin, C_RED); + if (castable) unsetcol(mainwin, C_GREEN); + else unsetcol(mainwin, C_RED); anyfound = B_TRUE; if (downline(&y, h, "MAGIC", subheading, prompt, cmdchars, &ch)) { exitnow = B_TRUE; @@ -8017,7 +8209,7 @@ void showlfstats(lifeform_t *lf, int showall) { int nfound = 0; x = 0; // override // down a line. - centre(mainwin, y, "EFFECTS"); + centre(mainwin, C_WHITE, y, "EFFECTS"); y += 2; @@ -8477,7 +8669,7 @@ void showlfstats(lifeform_t *lf, int showall) { } else if (mode == 'i') { object_t *o; cls(); - centre(mainwin, 0, "INVENTORY"); + centre(mainwin, C_WHITE, 0, "INVENTORY"); y = 2; if (lfhasflag(lf, F_NOPACK)) { mvwprintw(mainwin, y, 0, "It cannot carry anything."); @@ -8506,7 +8698,7 @@ void showlfstats(lifeform_t *lf, int showall) { } // wait for key - centre(mainwin, h-1, prompt); + centre(mainwin, C_WHITE, h-1, prompt); if (ch == '\0') { ch = getch(); } @@ -8558,33 +8750,33 @@ void tombstone(lifeform_t *lf) { cls(); y = 1; - centre(mainwin, y, "R.I.P."); y++; + centre(mainwin, C_GREY, y, "R.I.P."); y++; //printf("%s\n",lf->name); - centre(mainwin, y, "%s (%ld points)",pname, calcscore(lf)); y++; + centre(mainwin, C_GREY, y, "%s (%ld points)",pname, calcscore(lf)); y++; if (player->cell->map->region->rtype->id == RG_WORLDMAP) { getregionname(buf, player->cell->map, B_TRUE); - centre(mainwin, y, "Died on %s.", buf); y++; + centre(mainwin, C_GREY, y, "Died on %s.", buf); y++; } else { getregionname(buf, player->cell->map, B_FALSE); - centre(mainwin, y, "Died on level %d of %s.", player->cell->map->depth, buf); y++; + 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, y, "Committed suicide.",p); y++; + centre(mainwin, C_GREY, y, "Committed suicide.",p); y++; } else { - centre(mainwin, y, "Killed by %s.",p); y++; + centre(mainwin, C_GREY, y, "Killed by %s.",p); y++; } p = strtok_r(NULL, "^", &dummy); while (p) { - centre(mainwin, y, "(%s)",p); y++; + centre(mainwin, C_GREY, y, "(%s)",p); y++; p = strtok_r(NULL, "^", &dummy); } } else { - centre(mainwin, y, "Killed by something unknown."); y++; + centre(mainwin, C_GREY, y, "Killed by something unknown."); y++; } diff --git a/io.h b/io.h index 3334991..4a95bcb 100644 --- a/io.h +++ b/io.h @@ -24,7 +24,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars); cell_t *askcoords(char *prompt, char *subprompt, int targettype, lifeform_t *srclf, int maxrange, enum LOFTYPE loftype, int wanttrail); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); vault_t *askvault(char *prompttext); -void centre(WINDOW *win, int y, char *format, ... ); +void centre(WINDOW *win, enum COLOUR col, int y, char *format, ... ); int chartodir(char ch); char checkforkey(void); int cleanupgfx(void); @@ -84,6 +84,7 @@ int getkey(void); enum COLOUR getskilllevelcolour(enum SKILLLEVEL slev); void handleinput(void); void doheading(WINDOW *win, int *y, int x, char *what); +void doheadingsmall(WINDOW *win, int y, int x, char *format, char *heading); void initgfx(void); void initprompt(prompt_t *p, char *q1); int keycodetokey(int keycode); diff --git a/lf.c b/lf.c index 2cd5e5e..da98c77 100644 --- a/lf.c +++ b/lf.c @@ -59,10 +59,14 @@ int notime = B_FALSE; // prevent taketime from doing anything void autoweild(lifeform_t *lf) { object_t *bestwep,*bestfirearm; - object_t *o; + object_t *o,*firearm; int pretimespent; pretimespent = lf->timespent; + + if (isplayer(lf)) { + dblog("xxx"); + } // weild weapons if required bestwep = getbestweapon(lf); if (bestwep) { @@ -88,7 +92,8 @@ void autoweild(lifeform_t *lf) { // start using ammo if required //if (isplayer(lf)) { - if (getfirearm(lf)) { + firearm = getfirearm(lf); + if (firearm) { for (o = lf->pack->first ; o ; o = o->next) { testammo(lf, o); if (getammo(lf)) break; @@ -96,6 +101,21 @@ void autoweild(lifeform_t *lf) { } //} + // make sure monsters have ammo for their weapons + if (!isplayer(lf) && firearm && !getammo(lf)) { + objecttype_t *ot; + // make some ammo + ot = getrandomammofor(firearm); + if (ot) { + char buf[BUFLEN]; + sprintf(buf, "1-5 %s",ot->name); + o = addob(lf->pack, buf); + testammo(lf, o); + } + } + + + // make sure it doesn't take any time lf->timespent = pretimespent; } @@ -580,14 +600,15 @@ int caneat(lifeform_t *lf, object_t *o) { return B_TRUE; } -int canhear(lifeform_t *lf, cell_t *dest) { +int canhear(lifeform_t *lf, cell_t *dest, int volume) { int numpixels; int i; int x1,y1; - int hleft; + int sounddist; int x2,y2; map_t *map; cell_t *retcell[MAXRETCELLS]; + int celldist; if (!lf) return B_FALSE; if (!dest) return B_FALSE; @@ -609,9 +630,9 @@ int canhear(lifeform_t *lf, cell_t *dest) { // can't hear if you have a hostile mosnter next to you // and you're not blind. // (you're too engrossed in the battle) + celldist = getcelldist(lf->cell, dest); if (isplayer(lf) && isinbattle(lf)) { - if (getcelldist(lf->cell, dest) != 1) - return B_FALSE; + if (celldist != 1) return B_FALSE; } map = dest->map; @@ -623,9 +644,10 @@ int canhear(lifeform_t *lf, cell_t *dest) { calcbresnham(map, x1, y1, x2, y2, retcell, &numpixels ); - // get max hearing range - hleft = gethearingrange(lf); - if (hleft <= 0) { + // get sound celldistance + //sounddist = gethearingrange(lf); + sounddist = getsounddist(volume); + if (sounddist < celldist) { // sound won't travel far enough return B_FALSE; } @@ -642,14 +664,14 @@ int canhear(lifeform_t *lf, cell_t *dest) { if (i != 0) { // solid cells decrease hearing range if (cell->type->solid) { - hleft--; + sounddist--; } // hearing range decreases by one - hleft--; + sounddist--; } - if (hleft <= 0) { + if (sounddist <= 0) { return B_FALSE; } } @@ -2445,6 +2467,11 @@ void enhanceskills(lifeform_t *lf) { lf->level = lf->newlevel; + // special cases which happen before doing hp/mp + if (hasjob(lf, J_MONK) && (lf->level == 2)) { + addflag(lf->flags, F_MPDICE, 1, 0, NA, NULL); + } + // update hp hpratio = ((float)lf->hp / (float)lf->maxhp); lf->maxhp += rollhitdice(lf); @@ -2452,7 +2479,11 @@ void enhanceskills(lifeform_t *lf) { // update mp if (lfhasflag(lf, F_MPDICE)) { - mpratio = ((float)lf->mp / (float)lf->maxmp); + if (lf->maxmp == 0) { + mpratio = 1; + } else { + mpratio = ((float)lf->mp / (float)lf->maxmp); + } lf->maxmp += rollmpdice(lf); lf->mp = mpratio * (float)lf->maxmp; } @@ -2472,11 +2503,11 @@ void enhanceskills(lifeform_t *lf) { enum ATTRIB att; if (isplayer(lf)) { char ch; - ch = askchar("Increase your Strength, Dexterity, Constitution or Intelligence?", "sdci",NULL, B_TRUE); + ch = askchar("Increase your Strength, Dexterity, Fitness or Intelligence?", "sdfi",NULL, B_TRUE); switch (ch) { case 's': att = A_STR; break; case 'd': att = A_DEX; break; - case 'c': att = A_CON; break; + case 'f': att = A_CON; break; case 'i': att = A_IQ; break; } } else { @@ -2671,6 +2702,98 @@ void enhanceskills(lifeform_t *lf) { // now refresh them all for next level. refreshlevelabilities(lf); + // special case level-based job effects + if (hasjob(lf, J_MONK)) { + // enhance fist strength + f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); + if (f) { + char newtext[BUFLEN]; + strcpy(newtext, f->text); + switch(lf->level) { + case 2: + strcpy(newtext,"1d6"); + break; + case 3: + case 4: + strcpy(newtext,"1d6+1"); + break; + case 5: + strcpy(newtext,"2d4"); + break; + case 6: + case 7: + strcpy(newtext,"3d3"); + break; + case 8: + strcpy(newtext,"2d6"); + break; + case 9: + case 10: + strcpy(newtext,"3d4"); + break; + case 11: + strcpy(newtext,"3d4+1"); + break; + case 12: + case 13: + strcpy(newtext,"4d4"); + break; + case 14: + strcpy(newtext,"4d4+1"); + break; + case 15: + strcpy(newtext,"5d4"); + break; + case 16: + case 17: + strcpy(newtext,"4d6"); + break; + case 18: + strcpy(newtext,"6d4"); + break; + case 19: + strcpy(newtext,"5d6"); + break; + case 20: + strcpy(newtext,"8d4"); + break; + default: + strcpy(newtext,"6d6"); + break; + } + if (!streq(newtext, f->text)) { + free(f->text); + f->text = strdup(newtext); + if (isplayer(lf)) msg("Your unarmed attack damage has increased!"); + } + } + // enhance # attacks + f = lfhasflag(lf, F_MAXATTACKS); + if (f) { + int min,max; + min = f->val[0]; + max = f->val[1]; + if ((lf->level >= 2) && (lf->level <= 3)) { + min = 1; max = 1; + } else if ((lf->level >= 4) && (lf->level <= 6)) { + min = 1; max = 2; + } else if ((lf->level >= 7) && (lf->level <= 9)) { + min = 2; max = 2; + } else if ((lf->level >= 10) && (lf->level <= 12)) { + min = 2; max = 3; + } else if ((lf->level >= 13) && (lf->level <= 16)) { + min = 3; max = 3; + } else if (lf->level >= 17) { + min = 3; max = 4; + } + if ((min != f->val[0]) || (max != f->val[1])) { + f->val[0] = min; + f->val[1] = max; + if (isplayer(lf)) msg("Your number of unarmed attacks has increased!"); + } + } + } + killflagsofid(lf->flags, F_HASNEWLEVEL); // ready for another level? @@ -3362,17 +3485,33 @@ int getarmournoise(lifeform_t *lf) { return volmod; } -int getarmourrating(lifeform_t *lf) { + +// hitob, hitchnace and narms are optional +int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms) { object_t *o; flag_t *f; int ar = 0; + if (narms) { + (*narms) = 0; + } + for (f = lf->flags->first ; f ; f = f->next) { if (f->id == F_ARMOURRATING) { ar += f->val[0]; + if (hitob) { + hitob[*narms] = NULL; + hitchance[*narms] = getbodyparthitchance(BP_BODY); + (*narms)++; + } } if (f->id == F_MAGICARMOUR) { ar += f->val[0]; + if (hitob) { + hitob[*narms] = NULL; + hitchance[*narms] = getbodyparthitchance(BP_BODY); + (*narms)++; + } } if (f->id == F_PHALANX) { int dir; @@ -3389,20 +3528,31 @@ int getarmourrating(lifeform_t *lf) { } if (nmatched >= f->val[2]) { ar += f->val[0]; + if (hitob) { + hitob[*narms] = NULL; + hitchance[*narms] = getbodyparthitchance(BP_BODY); + (*narms)++; + } } } } for (o = lf->pack->first ; o ; o = o->next) { - if (hasflag(o->flags, F_EQUIPPED)) { + flag_t *eqflag; + eqflag = hasflag(o->flags, F_EQUIPPED); + if (eqflag) { f = hasflag(o->flags, F_ARMOURRATING); if (f) { float thisar; + int isshield = B_FALSE; thisar = f->val[0]; + if (hasflag(o->flags, F_SHIELD)) { + isshield = B_TRUE; + } // adjust for skill - if (hasflag(o->flags, F_SHIELD)) { + if (isshield) { switch (getskill(lf, SK_SHIELDS)) { case PR_INEPT: thisar *= 0.5; @@ -3433,6 +3583,11 @@ int getarmourrating(lifeform_t *lf) { ar += thisar; ar += getobbonus(o); + if (hitob) { + hitob[*narms] = o; + hitchance[*narms] = getbodyparthitchance(isshield ? BP_BODY : eqflag->val[0]); + (*narms)++; + } } } } @@ -3674,9 +3829,14 @@ int getevasion(lifeform_t *lf) { if (f) { // evasion 10 means -10% penalty to hit you ev += (f->val[0]); - if (ev < 0) ev = 0; } + // level based evasion + ev += gethitdice(lf); + + // skill based + ev += (getskill(lf, SK_EVASION)*10); + // now get object penalties/bonuses for (o = lf->pack->first ; o ; o = o->next) { // armour/weapons must be worn to do anything @@ -3689,26 +3849,22 @@ int getevasion(lifeform_t *lf) { } else { ev += (f->val[0]); } - if (ev < 0) ev = 0; } } } // dexterity mod ev += (getstatmod(lf, A_DEX) / 2); - if (ev < 0) ev = 0; // you are easier to hit if you're glowing if (hasflag(lf->flags, F_PRODUCESLIGHT)) { ev -= 5; - if (ev < 0) ev = 0; } // modify for stickiness if (hasobwithflag(lf->cell->obpile, F_RESTRICTMOVEMENT)) { ev -= 50; } - if (ev < 0) ev = 0; // modify for blindness // PLUS if you're blind, your evasion is 0 anyway for anyone @@ -3716,8 +3872,8 @@ int getevasion(lifeform_t *lf) { if (isblind(lf)) { ev -= 15; } - if (ev < 0) ev = 0; + limit(&ev, 0, NA); return ev; @@ -4363,13 +4519,16 @@ enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid) { return slev; } -int getmaxattacks(lifeform_t *lf) { +int getattacks(lifeform_t *lf, int *min, int *max) { flag_t *f; - int maxattacks; + int minattacks,maxattacks; + int nattacks; f = lfhasflag(lf, F_MAXATTACKS); if (f) { - maxattacks = f->val[0]; + minattacks = f->val[0]; + maxattacks = f->val[1]; } else { + minattacks = countinnateattacks(lf); maxattacks = countinnateattacks(lf); } @@ -4386,7 +4545,12 @@ int getmaxattacks(lifeform_t *lf) { if (getskill(lf, SK_TWOWEAPON) && isdualweilding(lf)) { maxattacks++; } - return maxattacks; + + if (min) *min = minattacks; + if (max) *max = maxattacks; + nattacks = rnd(minattacks,maxattacks); + + return nattacks; } float getmaxcarryweight(lifeform_t *lf) { @@ -4961,13 +5125,11 @@ int getracerarity(map_t *map, enum RACE rid) { } - return rarity; } object_t *getrandomarmour(lifeform_t *lf) { object_t *o; - flag_t *f; object_t *poss[MAXBODYPARTS]; object_t **hitposition; int hitchance[MAXBODYPARTS]; @@ -4975,9 +5137,11 @@ object_t *getrandomarmour(lifeform_t *lf) { int maxroll = 0; int i,n,idx; int sel; - int anyfound = B_FALSE; // make a list of all valid armour + getarmourrating(lf, poss, hitchance, &nposs); + if (!nposs) return NULL; + /* for (o = lf->pack->first ; o ; o = o->next) { if (hasflag(o->flags, F_ARMOURRATING)) { f = hasflag(o->flags, F_EQUIPPED); @@ -4994,16 +5158,19 @@ object_t *getrandomarmour(lifeform_t *lf) { } } } + */ - if (anyfound == B_FALSE) return NULL; - + maxroll = 0; + for (i = 0; i < nposs; i++) { + maxroll += hitchance[i]; + } // now figure out chances of each one getting hit hitposition = malloc(maxroll * sizeof(object_t *)); idx = 0; for (i = 0; i < nposs; i++) { for (n = 0; n < hitchance[i]; n++) { - hitposition[idx] = poss[i]; + hitposition[idx] = poss[i]; idx++; } } @@ -5202,6 +5369,10 @@ enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id) { return PR_INEPT; } +int getsounddist(int volume) { + return (3 * volume); +} + char *getspeedname(int speed, char *buf) { sprintf(buf, "unknownspeed"); if (speed <= SP_GODLIKE) { @@ -5332,6 +5503,37 @@ float getstatmod(lifeform_t *lf, enum ATTRIB att) { return mod; } +enum CHABRACKET getchaname(int cha, char *buf) { + if (cha <= 2) { + if (buf) strcpy(buf, "hideous"); + return CH_HIDEOUS; + } else if (cha <= 6) { + if (buf) strcpy(buf, "repulsive"); + return CH_REPULSIVE; + } else if (cha <= 8) { + if (buf) strcpy(buf, "ugly"); + return CH_UGLY; + } else if (cha <= 10) { + if (buf) strcpy(buf, "unattractive"); + return CH_UNATTRACTIVE; + } else if (cha <= 12) { + if (buf) strcpy(buf, "average"); + return CH_AVERAGE; + } else if (cha <= 14) { + if (buf) strcpy(buf, "attractive"); + return CH_ATTRACTIVE; + } else if (cha <= 16) { + if (buf) strcpy(buf, "alluring"); + return CH_ALLURING; + } else if (cha <= 18) { + if (buf) strcpy(buf, "beautiful"); + return CH_BEAUTIFUL; + } + + if (buf) strcpy(buf, "average"); + return CH_AVERAGE; +} + enum CONBRACKET getconname(int str, char *buf) { if (str <= 2) { if (buf) strcpy(buf, "frail"); @@ -5672,12 +5874,21 @@ void givejob(lifeform_t *lf, enum JOB jobid) { } // special cases - if (j->id == J_PIRATE) { + if (j->id == J_MONK) { + flag_t *f; + f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); + if (f) { + // monk fists do more damage + free(f->text); + f->text = strdup("1d4"); + } + } else if (j->id == J_PIRATE) { flag_t *f; f = lfhasflagval(lf, F_HASATTACK, OT_FISTS, NA, NA, NULL); if (f) { f->val[0] = OT_HOOKHAND; - sprintf(f->text, "1d4"); + free(f->text); + f->text = strdup("1d4"); } } else if (j->id == J_SHOPKEEPER) { // shopkeepers are not hostile. @@ -6025,9 +6236,11 @@ int giveskill(lifeform_t *lf, enum SKILL id) { mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST); } else if (id == SK_SS_MENTAL) { // give a spell + /* if (!lfhasflagval(lf, F_CANCAST, OT_S_MINDSCAN, NA, NA, NULL)) { addflag(lf->flags, F_CANCAST, OT_S_MINDSCAN, NA, NA, NULL); } + */ } else if (isloreskill(id) && (gamemode == GM_GAMESTARTED) && isplayer(lf)) { raceclass_t *rc; // find raceclass for this one @@ -6092,6 +6305,60 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) { sprintf(buf2, "calling givestartobs for %s",lf->race->name); } + // handle autoweapon + if (hasflag(fp, F_SELECTWEAPON)) { + skill_t *sk; + objecttype_t *poss[MAXSKILLS]; + int nposs = 0, i; + // find all the weapon skills this lf can learn + // and get basic objects of this type + for (sk = firstskill ; sk ; sk = sk->next) { + if (isweaponskill(sk->id)) { + if (canlearn(lf, sk->id) || getskill(lf, sk->id)) { + objecttype_t *ot; + ot = getbasicweaponforskill(sk->id); + if (ot) { + poss[nposs++] = ot; + } + } + } + } + if (nposs) { + char ch = 'a'; + objecttype_t *ot = NULL; + + // note: we use getplayername here even if this isn't a player, + // since in that case the prompt will never be displayed. + getplayernamefull(buf2); + sprintf(buf, "%s, select your starting weapon:", buf2); + initprompt(&prompt, buf); + + for (i = 0; i < nposs; i++) { + addchoice(&prompt, ch++, poss[i]->name, NULL, poss[i]); + } + + if (prompt.nchoices == 1) { + ot = (objecttype_t *)prompt.choice[0].data; + } else if (prompt.nchoices) { + if (isplayer(lf)) { + getchoice(&prompt); + ot = (objecttype_t *)prompt.result; + } else { + ot = (objecttype_t *)prompt.choice[rnd(0,prompt.nchoices-1)].data; + } + } + + if (ot) { + // give that weapon + addob(lf->pack, ot->name); + // skill in this weapon will be added later during autoskill() + } + + } + + } + + // give start objects and id them ignorenext = B_FALSE; for (f = fp->first ; f ; f = f->next) { @@ -6179,15 +6446,40 @@ void givestartobs(lifeform_t *lf, flagpile_t *fp) { ignoredprev = B_FALSE; } + // now remove startob flags so we don't get them again! killflagsofid(fp, F_STARTOB); killflagsofid(fp, F_STARTOBDT); killflagsofid(fp, F_STARTOBCLASS); + // SPECIAL CASES + if (lf->race->id == R_JAILER) { + regionoutline_t *ro; + region_t *r; + regionthing_t *rt = NULL; + int i; + o = addob(lf->pack, "map"); + assert(o); + // find first worldmap village + r = findregion(RG_WORLDMAP); + ro = r->outline; + for (i = 0; i < ro->nthings; i++) { + regionthing_t *thisthing; + thisthing = &ro->thing[i]; + if ((thisthing->whatkind == RT_HABITAT) && (thisthing->value == H_VILLAGE)) { + rt = thisthing; + break; + } + } + addflag(o->flags, F_MAPTO, rt->x, rt->y, OT_GATEWOOD, "a village"); + + } + // make sure lf doesn't start off burdened! while (isburdened(lf)) { modattr(lf, A_STR, 1); // get stronger } + } void givestartskills(lifeform_t *lf, flagpile_t *fp) { @@ -6872,11 +7164,11 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "short sword"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 bananas"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "3 potions of healing"); + addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_MPDICE, 1, NA, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_SKILLED, NA, NULL); @@ -6909,6 +7201,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLIMBING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); @@ -6922,7 +7215,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_DOPEY, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_FIT, NA, NULL); addflag(lastjob->flags, F_HITDICE, 1, 6, NA, NULL); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "axe"); + addflag(lastjob->flags, F_SELECTWEAPON, B_TRUE, NA, NA, NULL); 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"); @@ -6991,19 +7284,26 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + /////////////////////////////////////// addjob(J_DRUID, "Druid"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "quarterstaff"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); + // stats addflag(lastjob->flags, F_MPDICE, 1, 1, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_STR, ST_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_ATTRACTIVE, NA, NULL); + // objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "quarterstaff"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "sickle"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 sprigs of mistletoe"); // skills addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_SKILLED, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STAVES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_ADEPT, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TRACKING, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_ADEPT, NA, NULL); // learnable skills addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -7020,7 +7320,70 @@ void initjobs(void) { addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); addflag(lastjob->flags, F_PARTVEGETARIAN, B_TRUE, NA, NA, NULL); + /////////////////////////////////////// + addjob(J_MONK, "Monk"); + // stats + addflag(lastjob->flags, F_STARTATT, A_STR, ST_STRONG, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_DEX, DX_NIMBLE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CON, CN_AVERAGE, NA, NULL); + // TODO: high wisdom + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_AVERAGE, NA, NULL); + // objects + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "pair of sandals"); + // skills + addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_EVASION, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPOTHIDDEN, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_UNARMED, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SS_MENTAL, PR_NOVICE, NA, NULL); + // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, 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_FIRSTAID, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SEWING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TRAPS, NA, NA, NULL); + // starting abilities + // 1: feign death (mp) + addflag(lastjob->flags, F_MAXATTACKS, 1, 1, NA, NULL); // this will go up later + // gained abilities + // somewhere: slow falling when next to walls + // somehwere: heavy blow + // somehwere: flurry + // somehwere: alertness when sleeping + // somehwere: tremorsense + // 2: resist ESP (innate) + addflag(lastjob->flags, F_LEVSPELL, 3, OT_S_CALMANIMALS, NA, NULL); + // 4: self-healing (mp), immune to disease (innate), immune to haste/slow (innate) + // 5: waterawlk via 'body equilibrium' (innate) + // 6: empathy (ie. sense hostility.... useful???) + addflag(lastjob->flags, F_LEVSPELL, 7, OT_S_INVISIBILITY, NA, NULL); + // 8: molecular manipulation (ie. lower hardness of physical obs by level-7, not lfs) (innate) + // 9: resistance to charm, hypnosis, sleep (innate) + addflag(lastjob->flags, F_LEVFLAG, 10, F_DTIMMUNE, DT_POISON, NULL); + // 11: body control (ie. have one turn as another lf) (mp) + // 12: quivering palm (v.high mp cost OR once every 200 turns or so) + addflag(lastjob->flags, F_LEVFLAG, F_CANWILL, OT_S_BLINK, 10, "pw:6;"); // l6 = controlled + // 14: speak with plants (mp?innate?) + // 15: mind bar??? what is this + // 16: identify (not very often) (mp) + addflag(lastjob->flags, F_LEVFLAG, F_CANWILL, OT_S_IDENTIFY, 100, NULL); + // 17: dimension walk (controlled teleport??) (mp) + // 18: astral projection.. .??useful? + // 19: premonition of death 1-4 turns before + // 20: tower of iron will + // 21: planeshift + + addjob(J_PLUMBER, "Plumber"); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_UGLY, NA, NULL); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spanner"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "overalls"); @@ -7040,6 +7403,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, NA, NA, NULL); addjob(J_PRINCE, "Prince"); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_ALLURING, NA, NULL); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "blessed ornamental sword"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "100 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "golden crown"); @@ -7055,6 +7419,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_NATURE, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SPEECH, PR_SKILLED, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CARTOGRAPHY, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); @@ -7070,13 +7435,14 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_STR, NA, NA, "8-15"); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_UNATTRACTIVE, NA, NULL); // abilities addflag(lastjob->flags, F_STABILITY, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_NOBODYPART, BP_LEFTHAND, NA, NA, NULL); addflag(lastjob->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastjob->flags, F_EXTRALUCK, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young hawk"); - addflag(lastjob->flags, F_MAXATTACKS, 2, NA, NA, NULL);// this is so that our hookhand works + addflag(lastjob->flags, F_MAXATTACKS, 2, 2, NA, NULL);// this is so that our hookhand works addflag(lastjob->flags, F_VISRANGEMOD, -4, NA, NA, NULL); // also: has a hook instead of fists. // startobjects @@ -7110,6 +7476,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_DEX, DX_NIMBLE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_UNFIT, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_RANDOM, NA, NULL); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); @@ -7128,6 +7495,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SWIMMING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); @@ -7162,6 +7530,8 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_STR, ST_WEAK, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_IQ, IQ_ENLIGHTENED, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CON, CN_UNFIT, NA, NULL); + addflag(lastjob->flags, F_STARTATT, A_CHA, CH_RANDOM, NA, NULL); // wizard heals slowly, but regenerates mp addflag(lastjob->flags, F_RESTHEALTIME, 6, NA, NA, NULL); //addflag(lastjob->flags, F_MPREGEN, 1, SK_SPELLCASTING, 35, NULL); @@ -7177,6 +7547,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SPEECH, NA, NA, NULL); // wizards can learn all spell schools except psionics and allomancy addflag(lastjob->flags, F_CANLEARN, SK_SS_AIR, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_DEATH, NA, NA, NULL); @@ -7338,6 +7709,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-10 arrows"); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERARM, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); // monsters @@ -7720,6 +8092,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "1-25 gold coins"); addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "short sword"); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "sling"); addflag(lastrace->flags, F_STARTOBCLASS, 40, OC_POTION, NA, NULL); addflag(lastrace->flags, F_WANTSBETTERWEP, B_TRUE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); @@ -8196,7 +8569,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8"); addflag(lastrace->flags, F_HASATTACK, OT_HOOF, NA, NA, "1d8"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); - addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); @@ -8529,7 +8902,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_EYES, NA, NA, NULL); @@ -8558,7 +8931,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 0, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -8580,7 +8953,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6"); - addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); @@ -8600,7 +8973,7 @@ void initrace(void) { addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d6"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d8"); - addflag(lastrace->flags, F_MAXATTACKS, 3, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 3, 3, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); @@ -8688,7 +9061,7 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 2, 3, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d6"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); @@ -8711,7 +9084,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10"); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d10"); - addflag(lastrace->flags, F_MAXATTACKS, 2, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 2, 2, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 5, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); @@ -8736,7 +9109,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 83, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "2d4"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -8909,7 +9282,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 80, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); @@ -8928,7 +9301,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 0, 1, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d2"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -9167,7 +9540,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, 97, NA, ""); addflag(lastrace->flags, F_HITDICE, 2, 2, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d3"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); @@ -9190,7 +9563,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, 3, 3, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "1d5"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d5"); - addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_WEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); @@ -10023,6 +10396,9 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->sorted = B_FALSE; a->forgettimer = 0; + a->prevcell[0] = NULL; + a->prevcell[1] = NULL; + a->polyrevert = B_FALSE; // for precalcing line of sight @@ -10690,6 +11066,22 @@ flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt) { return NULL; } +int isweaponskill(enum SKILL skid) { + switch (skid) { + case SK_AXES: + case SK_CLUBS: + case SK_LONGBLADES: + case SK_POLEARMS: + case SK_SHORTBLADES: + case SK_STAVES: + //case SK_UNARMED: + return B_TRUE; + default: + break; + } + return B_FALSE; +} + void killjob(job_t *job) { job_t *nextone, *lastone; @@ -10952,7 +11344,8 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml more(); } } else if (prebleed != postbleed) { - if (ispetof(lf, player) && !canhear(player, lf->cell)) { + // TODO: replace 4 + if (ispetof(lf, player) && !canhear(player, lf->cell, 4)) { char realname[BUFLEN]; real_getlfname(lf, realname, B_FALSE); warn("You feel worried about your %s.", noprefix(realname)); @@ -11067,7 +11460,7 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { if (nid == N_WALK) { volume += getarmournoise(lf); } - noise(lf->cell, lf, volume, noisetext, verb); + noise(lf->cell, lf, NC_OTHER, volume, noisetext, verb); } else { // some defaults if (nid == N_WALK) { @@ -11110,10 +11503,10 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid) { } volume += getarmournoise(lf); if (strlen(movetext)) { - noise(lf->cell, lf, volume, movetext, NULL); + noise(lf->cell, lf, NC_OTHER, volume, movetext, NULL); } } else if (nid == N_WARCRY) { - noise(lf->cell, lf, 4, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!"); + noise(lf->cell, lf, NC_OTHER, 4, "a blood-curdling war cry!", "shouts a blood-curdling war-cry!"); } } @@ -11166,6 +11559,9 @@ int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o) { case A_DEX: reason = E_LOWDEX; break; + case A_CHA: + reason = E_LOWCHA; + break; case A_CON: reason = E_LOWCON; break; @@ -11217,6 +11613,9 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { case A_STR: strcpy(adverb, "stronger"); break; + case A_CHA: + strcpy(adverb, "more attractive"); + break; case A_CON: strcpy(adverb, "healthier"); break; @@ -11234,6 +11633,9 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { case A_STR: strcpy(adverb, "weaker"); break; + case A_CHA: + strcpy(adverb, "less attractive"); + break; case A_CON: strcpy(adverb, "frail"); break; @@ -11353,7 +11755,7 @@ int needstorest(lifeform_t *lf, char *validchars) { } // returns TRUE if the player heard it. -int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seetext) { +int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext) { lifeform_t *l; int sounddist; int rv = B_FALSE; @@ -11361,8 +11763,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete return B_FALSE; } - // sound will travel 2*volume cells - sounddist = 2 * volume; + // sound will travel 3*volume cells + sounddist = getsounddist(volume); // if anything nearby hears it, it might respond for (l = c->map->lf; l ; l = l->next) { @@ -11380,8 +11782,17 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete int lbonus; //if (canhear(l, c) && haslos(l, c)) { + // listen check difficulty is based on sound distance vs max hearing distance - difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); + if (nt == NC_SPEECH) { + if (isplayer(l)) { + dblog("xxx"); + } + // you always hear it, as long as you're in range + difficulty = 0; + } else { + difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); + } // listen bonus is the sound volume if (lfhasflag(l, F_ASLEEP)) { @@ -11391,9 +11802,8 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete } // skillcheck to hear this - if (canhear(l, c) && - (haslos(l, c) || - ((dist <= sounddist) && skillcheck(l, SC_LISTEN, difficulty, lbonus)))) { + if ( (haslos(l, c) || + (canhear(l, c, volume) && skillcheck(l, SC_LISTEN, difficulty, lbonus)))) { flag_t *f; // announce? if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { @@ -11405,7 +11815,7 @@ int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seete msg("%s %s.", lfname, seetext); rv = B_TRUE; } - } else if (text && !lfhasflag(l, F_DONELISTEN)) { + } else if (text && ((nt == NC_SPEECH) || !lfhasflag(l, F_DONELISTEN))) { char textnopunc[BUFLEN]; char punc; int dist; @@ -12019,6 +12429,39 @@ int rolliq(enum IQBRACKET bracket) { return roll; } +int rollcha(enum CHABRACKET bracket) { + int roll = 0; + switch (bracket) { + case CH_HIDEOUS: + roll = rnd(0,2); + break; + case CH_REPULSIVE: + roll = rnd(3, 6); + break; + case CH_UGLY: + roll = rnd(7, 8); + break; + case CH_UNATTRACTIVE: + roll = rnd(9, 10); + break; + case CH_AVERAGE: + roll = rnd(11, 12); + break; + case CH_ATTRACTIVE: + roll = rnd(13, 14); + break; + case CH_ALLURING: + roll = rnd(15, 16); + break; + case CH_BEAUTIFUL: + roll = rnd(17, 18); + break; + default: + roll = rolldie(3,6); + break; + } + return roll; +} int rollcon(enum CONBRACKET bracket) { int roll = 0; switch (bracket) { @@ -12161,6 +12604,8 @@ int rollstat(lifeform_t *lf, enum ATTRIB attr) { switch (attr) { case A_STR: bracket = ST_RANDOM; break; + case A_CHA: + bracket = CH_RANDOM; break; case A_CON: bracket = CN_RANDOM; break; case A_DEX: @@ -12173,8 +12618,11 @@ int rollstat(lifeform_t *lf, enum ATTRIB attr) { } switch (attr) { - case A_STR: - lf->att[attr] = rollstr(bracket); + case A_CHA: + lf->att[attr] = rollcha(bracket); + break; + case A_CON: + lf->att[attr] = rollcon(bracket); break; case A_DEX: lf->att[attr] = rolldex(bracket); @@ -12182,8 +12630,8 @@ int rollstat(lifeform_t *lf, enum ATTRIB attr) { case A_IQ: lf->att[attr] = rolliq(bracket); break; - case A_CON: - lf->att[attr] = rollcon(bracket); + case A_STR: + lf->att[attr] = rollstr(bracket); break; default: return B_TRUE; @@ -12209,29 +12657,31 @@ int safetorest(lifeform_t *lf) { } int say(lifeform_t *lf, char *text, int volume) { - char buf[BUFLEN]; + char seebuf[BUFLEN]; + char hearbuf[BUFLEN]; char verb[BUFLEN]; char noun[BUFLEN]; if (volume < 2) { strcpy(verb, "whispers"); - strcpy(noun, "whispering."); + strcpy(noun, "a whisper:"); } else if (volume == 2) { strcpy(verb, "says"); - strcpy(noun, "voices."); + strcpy(noun, "a voice:"); } else if (volume == 3) { strcpy(verb, "shouts"); - strcpy(noun, "raised voices."); + strcpy(noun, "a shout:"); } else if (volume == 4) { strcpy(verb, "roars"); - strcpy(noun, "roaring voices!"); + strcpy(noun, "a roar:"); } else { // ie > 4 strcpy(verb, "bellows"); - strcpy(noun, "bellowing voices!"); + strcpy(noun, "a bellow:"); } - sprintf(buf, "%s \"%s\"", verb, text); + sprintf(seebuf, "%s \"%s\"", verb, text); + sprintf(hearbuf, "%s \"%s\"", noun, text); - return noise(lf->cell, lf, volume, noun, buf); + return noise(lf->cell, lf, NC_SPEECH, volume, hearbuf, seebuf); } // returns TRUE if something happened @@ -12321,7 +12771,7 @@ int setammo(lifeform_t *lf, object_t *ammo) { getobname(gun, gunname, gun->amt); - if (ammo && !isammofor(ammo, gun)) { + if (ammo && !isammofor(ammo->type, gun)) { if (isplayer(lf)) { msg("You can't load %s with %s!", gunname, ammoname); } @@ -12586,6 +13036,7 @@ void initskills(void) { addskill(SK_CHANNELING, "Channeling", "Lets you make better use of magical items.", 0); // untrainable addskill(SK_CLIMBING, "Climbing", "Helps you to climb walls, mountains or other terrain.", 50); addskill(SK_COOKING, "Cooking", "Your ability to combine foods into nutritious meals.", 50); + addskill(SK_EVASION, "Evasion", "Your ability to dodge blows or traps.", 50); addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison.", 0); // untrainable addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds.", 100); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); @@ -12593,6 +13044,7 @@ void initskills(void) { addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 100); addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block projectiles.", 50); + addskill(SK_SPEECH, "Speech", "Your skill at haggling prices, or swaying others through speech.", 50); addskill(SK_SPELLCASTING, "Sorcery", "Determines your ability to cast spells from all schools.", 50); addskill(SK_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures.", 50); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently.", 0); // untrainable? @@ -12751,6 +13203,9 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r case SC_DEX: attrib = getattr(lf, A_DEX); break; + case SC_CHA: + attrib = getattr(lf, A_CHA); + break; case SC_OPENLOCKS: attrib = getattr(lf, A_DEX); break; @@ -12907,13 +13362,13 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r // natural 20 will pass some checks if (roll == 20) { - if (db) { - msg("%s skillcheck passed with natural 20.", lf->race->name); - } switch (ct) { case SC_DODGE: case SC_SEARCH: case SC_STEALTH: + if (db) { + msg("%s skillcheck passed with natural 20.", lf->race->name); + } modroll = diff; break; default: @@ -12926,6 +13381,15 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r } if (modroll >= diff) { + // passed! + // some checks will train skills when passed. + switch (ct) { + case SC_DODGE: + practice(lf, SK_EVASION, 1); + break; + default: + break; + } return B_TRUE; } return B_FALSE; @@ -13308,7 +13772,7 @@ int testammo(lifeform_t *lf, object_t *o) { object_t *gun; gun = getfirearm(lf); if (gun) { - if (isammofor(o, gun)) { + if (isammofor(o->type, gun)) { object_t *curammo; curammo = getammo(lf); if (!curammo) { @@ -15361,6 +15825,9 @@ int weild(lifeform_t *lf, object_t *o) { case E_NOHANDS: msg("You do not have enough free hands to weild this weapon."); break; + case E_LOWCHA: + msg("You are not attractive enough to use this weapon."); + break; case E_LOWCON: msg("You are not healthy enough to use this weapon."); break; diff --git a/lf.h b/lf.h index db80de9..a4ab7df 100644 --- a/lf.h +++ b/lf.h @@ -27,7 +27,7 @@ void callguards(lifeform_t *caller, lifeform_t *victim); int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost); int candrink(lifeform_t *lf, object_t *o); int caneat(lifeform_t *lf, object_t *o); -int canhear(lifeform_t *lf, cell_t *c); +int canhear(lifeform_t *lf, cell_t *c, int volume); int canlearn(lifeform_t *lf, enum SKILL skid); int canopendoors(lifeform_t *lf); int canpickup(lifeform_t *lf, object_t *o, int amt); @@ -87,7 +87,7 @@ enum ALLEGIENCE getallegiance(lifeform_t *lf); int getallouterarmour(lifeform_t *lf, object_t **ob, int *nobs); object_t *getarmour(lifeform_t *lf, enum BODYPART bp); int getarmournoise(lifeform_t *lf); -int getarmourrating(lifeform_t *lf); +int getarmourrating(lifeform_t *lf, object_t **hitob, int *hitchance, int *narms); int getattackspeed(lifeform_t *lf); int getattpoints(lifeform_t *lf); int getattr(lifeform_t *lf, enum ATTRIB attr); @@ -128,7 +128,7 @@ char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer); glyph_t *getlfglyph(lifeform_t *lf); enum MATERIAL getlfmaterial(lifeform_t *lf); enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid); -int getmaxattacks(lifeform_t *lf); +int getattacks(lifeform_t *lf, int *min, int *max); float getmaxcarryweight(lifeform_t *lf); float getmaxliftweight(lifeform_t *lf); int getmaxmp(lifeform_t *lf); @@ -164,10 +164,12 @@ race_t *getreallyrandomrace(enum RACECLASS wantrc); enum SKILL getrandomskill(void); object_t *getrestob(lifeform_t *lf); enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id); +int getsounddist(int volume); char *getspeedname(int speed, char *buf); char *getspeednameshort(int speed, char *buf); float getstatmod(lifeform_t *lf, enum ATTRIB att); -enum CONBRACKET getconname(int str, char *buf); +enum CHABRACKET getchaname(int cha, char *buf); +enum CONBRACKET getconname(int con, char *buf); enum STRBRACKET getstrname(int str, char *buf); enum DEXBRACKET getdexname(int dex, char *buf); enum IQBRACKET getiqname(int iq, char *buf); @@ -237,6 +239,7 @@ object_t *isstuck(lifeform_t *lf); int isswimming(lifeform_t *lf); int isundead(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); +int isweaponskill(enum SKILL skid); void killjob(job_t *job); void killlf(lifeform_t *lf); void killrace(race_t *race); @@ -256,7 +259,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); void modhunger(lifeform_t *lf, int amt); float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); int needstorest(lifeform_t *lf, char *validchars); -int noise(cell_t *c, lifeform_t *noisemaker, int volume, char *text, char *seetext); +int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nt, int volume, char *text, char *seetext); void outfitlf(lifeform_t *lf); int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground); void poison(lifeform_t *lf, int howlong, enum POISONTYPE ptype, int power, char *fromwhat); @@ -270,6 +273,7 @@ void refreshlevelabilities(lifeform_t *lf); void relinklf(lifeform_t *src, map_t *dst); int rest(lifeform_t *lf, int onpurpose); void startresting(lifeform_t *lf, int willtrain); +int rollcha(enum CHABRACKET bracket); int rollcon(enum CONBRACKET bracket); int rolldex(enum DEXBRACKET bracket); int rolliq(enum IQBRACKET bracket); diff --git a/map.c b/map.c index 56fdcff..4b857ad 100644 --- a/map.c +++ b/map.c @@ -622,7 +622,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in if (newcell && !newcell->type->solid) { int doorcount; // if so, make sure there are no other adjacent doors - doorcount = countadjcellswithflag(cell[i], F_DOOR); + doorcount = countadjcellswithflag(cell[i], F_DOOR, DT_ORTH); if (doorcount == 0) { // if there is only one way out of the adjacent empty cell, and // walls to either side of the potential door location, then @@ -632,6 +632,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in makedoor(cell[i], dooropenchance); } else { setcelltype(cell[i], cell[i]->habitat->emptycelltype); + addflag(map->flags, F_ROOMEXIT, roomid, cell[i]->x, cell[i]->y, NULL); } } else { // otherwise mark this as a _potential_ door location. @@ -651,6 +652,7 @@ int autodoors(map_t *map, int roomid, int minx, int miny, int maxx, int maxy, in makedoor(poss[sel], dooropenchance); } else { setcelltype(poss[sel], poss[sel]->habitat->emptycelltype); + addflag(map->flags, F_ROOMEXIT, roomid, poss[sel]->x, poss[sel]->y, NULL); } doorsadded++; @@ -843,9 +845,11 @@ void clearcell(cell_t *c) { while (c->obpile->first) { killob(c->obpile->first); } - c->known = B_FALSE; - c->knownglyph.ch = ' '; - c->knownglyph.colour = C_GREY; + if (gamemode == GM_GAMESTARTED) { + c->known = B_FALSE; + c->knownglyph.ch = ' '; + c->knownglyph.colour = C_GREY; + } } // returns true if something happened @@ -1322,13 +1326,21 @@ int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int return B_FALSE; } -int countadjcellswithflag(cell_t *cell, enum FLAG fid) { +int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype) { int d; int count = 0; + int start, end; cell_t *newcell; - for (d = D_N; d < MAXDIR_ORTH; d++) { + if (dirtype == DT_ORTH) { + start = D_N; + end = D_W; + } else { + start = DC_N; + end = DC_NW; + } + for (d = start; d <= end; d++) { newcell = getcellindir(cell, d); - if (newcell && hasobwithflag(cell->obpile, fid)) { + if (newcell && hasobwithflag(newcell->obpile, fid)) { count++; } } @@ -1389,6 +1401,18 @@ int countcellexits(cell_t *cell) { return exits; } +int countcellexitsfor(lifeform_t *lf) { + int d; + int exits = 0; + assert(lf); + for (d = DC_N; d <= DC_NW; d++) { + if (moveclear(lf, d, NULL)) { + exits++; + } + } + return exits; +} + // void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) { int wantrooms = B_TRUE; @@ -1418,7 +1442,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ int moved = 0; - enum CELLTYPE emptycell; + enum CELLTYPE emptycell,solidcell; // fill entire maze with walls for (y = 0; y < map->h; y++) { @@ -1430,6 +1454,7 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ // what kind of cells will 'empty' ones be? emptycell = map->habitat->emptycelltype; + solidcell = map->habitat->solidcelltype; // pick initial random spot cell = getrandomcell(map); @@ -1531,8 +1556,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } } - - // introduce loops for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { @@ -1593,8 +1616,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } } } - - // create rooms if (wantrooms) { numrooms = rnd(minrooms, maxrooms); @@ -1615,9 +1636,11 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } } if (!roomvault[i]) { + int rx,ry; // just do a normal room - createroom(map, i, NA, NA, 0, 0, NULL, NULL, &roomw[i],&roomh[i], 50, B_FALSE); + createroom(map, i, NA, NA, 0, 0, &rx, &ry, &roomw[i],&roomh[i], 50, B_FALSE); roomvault[i] = B_FALSE; + linkexits(map, i, rx, ry, rx+roomw[i]-1, ry+roomh[i]-1); } } } @@ -1746,6 +1769,29 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } // end if wantrooms & nrooms>0 if (db) dblog("Finished adding objects."); + + // now do a border + y = 0; + for (x = 0; x < map->w; x++) { + // n + c = getcellat(map, x, 0); + clearcell(c); + setcelltype(c,solidcell); + // s + c = getcellat(map, x, map->h-1); + clearcell(c); + setcelltype(c,solidcell); + } + for (y = 1; y < map->h-1; y++) { + // w + c = getcellat(map, 0, y); + clearcell(c); + setcelltype(c,solidcell); + // e + c = getcellat(map, map->w-1, y); + clearcell(c); + setcelltype(c,solidcell); + } } void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings) { @@ -2340,7 +2386,7 @@ int linkexits(map_t *m, int roomid, int minx, int miny, int maxx, int maxy) { if (db) dblog("linkexits for roomid %d", roomid); - // find all doors // TODO: ...or "exits" + // find all doors or f_roomexits for (y = miny; y <= maxy; y++) { for (x = minx; x <= maxx; x++) { c = getcellat(m, x, y); @@ -2631,7 +2677,7 @@ void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int msg("You see %s explosion!", (range > 0) ? "a huge" : "an"); } } else { - noise(c, NULL, (range > 0) ? 6 : 5, "an explosion!", NULL); + noise(c, NULL, NC_OTHER, (range > 0) ? 6 : 5, "an explosion!", NULL); } for (y = c->y - range ; y <= c->y + range ; y++) { @@ -2827,7 +2873,7 @@ object_t *findobidinmap(map_t *m, long id) { // find the cell in 'map' which contains object oid -cell_t *findobinmap(map_t *m, enum OBCLASS oid) { +cell_t *findobinmap(map_t *m, enum OBTYPE oid) { cell_t *c; int x,y; for (y = 0; y < m->h; y++) { @@ -3422,6 +3468,7 @@ object_t *hastrailof(obpile_t *op, lifeform_t *lf, enum OBTYPE oid, flag_t **tfl void initmap(void) { + int vx,vy; // habitats // thingchance, obchance, vaultchance addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 10); @@ -3453,10 +3500,18 @@ void initmap(void) { // link to first dungeon addregionthing(lastregionoutline, NA, 0, 0, RT_REGIONLINK, RG_FIRSTDUNGEON, "staircase going down"); // the village - addregionthing(lastregionoutline, NA, 0, -1, RT_HABITAT, H_VILLAGE, NULL); - addregionthing(lastregionoutline, NA, 0, -1, RT_VAULT, NA, "potion_shop"); - addregionthing(lastregionoutline, NA, 0, -1, RT_VAULT, NA, "weapon_shop"); - addregionthing(lastregionoutline, NA, 0, -1, RT_VAULT, NA, "armour_shop"); + /* + vx = 0; vy = 0; + while ((vx == 0) && (vy == 0)) { + vx = rnd(-2,2); + vy = rnd(-2,2); + } + */ + vx = 0; vy = -1; + addregionthing(lastregionoutline, NA, vx, vy, RT_HABITAT, H_VILLAGE, NULL); + addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "potion_shop"); + addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "weapon_shop"); + addregionthing(lastregionoutline, NA, vx, vy, RT_VAULT, NA, "armour_shop"); addregionoutline(RG_FIRSTDUNGEON); addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair"); } @@ -3981,6 +4036,17 @@ void setcellknown(cell_t *cell, int forcelev) { //getcellglyph(&(cell->knownglyph), cell, player); } +void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype) { + cell_t *cell[MAXCANDIDATES]; + int ncells,i; + getradiuscells(centre, radius, dirtype, LOF_DONTNEED, B_TRUE, cell, &ncells); + for (i = 0; i < ncells; i++) { + cell_t *c; + c = cell[i]; + setcellknown(c, forcelev); + } +} + void setcelltype(cell_t *cell, enum CELLTYPE id) { assert(cell); cell->type = findcelltype(id); @@ -4012,7 +4078,7 @@ int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring) { seen = B_TRUE; } else { // very loud - noise(c, NULL, 7, "shattering glass.", NULL); + noise(c, NULL, NC_OTHER, 7, "shattering glass.", NULL); } if (target) { diff --git a/map.h b/map.h index de1d352..dbd3ff4 100644 --- a/map.h +++ b/map.h @@ -32,9 +32,10 @@ void calclight(map_t *map); int calcroompos(map_t *map, int w, int h, int xmargin, int ymargin, int *bx, int *by, int force); int countadjcellsoftype(cell_t *cell, int id); int countadjrooms(cell_t *cell); -int countadjcellswithflag(cell_t *cell, enum FLAG fid); +int countadjcellswithflag(cell_t *cell, enum FLAG fid, int dirtype); int countadjwalls(cell_t *cell); int countcellexits(cell_t *cell); +int countcellexitsfor(lifeform_t *lf); void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings); void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); @@ -56,7 +57,7 @@ map_t *findmap(int mid); map_t *findmapofdepth(int depth); cell_t *findmapentrypoint(map_t *m, int side, lifeform_t *lf); object_t *findobidinmap(map_t *m, long id); -cell_t *findobinmap(map_t *m, enum OBCLASS oid); +cell_t *findobinmap(map_t *m, enum OBTYPE oid); region_t *findregion(int regionid); region_t *findregionbytype(enum REGIONTYPE rtid); map_t *findregionmap(int regionid, int depth); @@ -104,6 +105,7 @@ void makedoor(cell_t *cell, int openchance); void makelit(cell_t *c, enum LIGHTLEV how, int howlong); void makelitradius(cell_t *c, int radius, enum LIGHTLEV how, int howlong); void setcellknown(cell_t *cell, int forcelev); +void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype); void setcelltype(cell_t *cell, enum CELLTYPE id); int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring); void updateknowncells(void); diff --git a/move.c b/move.c index 95aeb0a..d89301d 100644 --- a/move.c +++ b/move.c @@ -482,7 +482,7 @@ int getdiraway(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, int d } dist[d - DC_N] = thisdist; - if (thisdist > maxdist) { + if (thisdist >= maxdist) { maxdist = thisdist; bestdir = d; } @@ -569,10 +569,11 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in thisdist = getcelldist(c, dst); } - if (thisdist < mindist) { + if (thisdist <= mindist) { dist[d - DC_N] = thisdist; mindist = thisdist; } else { + // don't move AWAY from them. dist[d - DC_N] = -1; } } else { @@ -823,7 +824,7 @@ int moveclear(lifeform_t *lf, int dir, enum ERROR *error) { } } - if ((lf->race->id == RC_DEMON) && hasob(cell->obpile, OT_PENTAGRAM)) { + if ((lf->race->raceclass->id == RC_DEMON) && hasob(cell->obpile, OT_PENTAGRAM)) { *error = E_PENTAGRAM; return B_FALSE; } @@ -934,6 +935,10 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } + // remember previous cells + lf->prevcell[1] = lf->prevcell[0]; + lf->prevcell[0] = lf->cell; + // update lifeform lf->cell = newcell; @@ -1172,7 +1177,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // in range of alarm? range is 3 * spell power cells. if (getcelldist(lf->cell, l->cell) <= (alarm->val[2]*3)) { // alarm goes off - noise(l->cell, NULL, 50, "a blaring siren!", NULL); + noise(l->cell, NULL, NC_OTHER, 50, "a blaring siren!", NULL); killflag(alarm); } } @@ -1184,25 +1189,23 @@ int movelf(lifeform_t *lf, cell_t *newcell) { // are you about to go outside a shop with stolen goods? if ((lf->cell->roomid == preshop) && (lf->cell->type->id != CT_FLOORSHOP)) { lifeform_t *shk; + int nitems = 0; shk = findshopkeeper(lf->cell->map, preshop); - if (shk) { - int nitems = 0; - // do you have any unpaid items from that shop? - if (getowing(lf, preshop, &nitems)) { - char saybuf[BUFLEN]; - // warning... - switch (rnd(1,3)) { - case 1: sprintf(saybuf, "Hey! Where do you think you're going?"); - break; - case 2: sprintf(saybuf, "AHEM!"); - break; - case 3: sprintf(saybuf, "I hope you are going to pay for %s!", - (nitems == 1) ? "that" : "those" ); - break; - } - say(shk, saybuf, SV_SHOUT); - didmsg = B_TRUE; + // do you have any unpaid items from that shop? + if (shk && getowing(lf, preshop, &nitems)) { + char saybuf[BUFLEN]; + // warning... + switch (rnd(1,3)) { + case 1: sprintf(saybuf, "Hey! Where do you think you're going?"); + break; + case 2: sprintf(saybuf, "AHEM!"); + break; + case 3: sprintf(saybuf, "I hope you are going to pay for %s!", + (nitems == 1) ? "that" : "those" ); + break; } + say(shk, saybuf, SV_SHOUT); + didmsg = B_TRUE; } } else if (lf->cell->roomid != preshop) { // you've left the shop @@ -1532,7 +1535,7 @@ int opendoor(lifeform_t *lf, object_t *o) { // checking if we have LOS to the lifeform making // sound, but in this case it's the door making // the sound, not the lf. - noise(where, NULL, 2, "a door opening.", NULL); + noise(where, NULL, NC_OTHER, 2, "a door opening.", NULL); } if (player && haslos(player, where)) { needredraw = B_TRUE; @@ -1649,7 +1652,8 @@ int closedoor(lifeform_t *lf, object_t *o) { int tryrun(lifeform_t *lf, int dir) { if (!trymove(lf, dir, B_TRUE)) { - addflag(lf->flags, F_RUNNING, dir, NA, NA, NULL); + // success! + addflag(lf->flags, F_RUNNING, dir, B_FALSE, NA, NULL); } return B_FALSE; } diff --git a/objects.c b/objects.c index 18d64e5..9c7274c 100644 --- a/objects.c +++ b/objects.c @@ -2070,6 +2070,11 @@ void brightflash(cell_t *centre, int range, lifeform_t *immunelf) { } } +void calcshopprice(object_t *o, flag_t *shopitemflag) { + // initial value + shopitemflag->val[0] = (int) getshopprice(o, o->pile->owner); +} + int canbepoisoned(enum OBTYPE oid) { flag_t *f; objecttype_t *ot; @@ -2602,6 +2607,7 @@ objecttype_t *findotn(char *name) { modname = strrep(modname, "scrolls ", "scroll ", NULL); modname = strrep(modname, "sets ", "set ", NULL); modname = strrep(modname, "splashes ", "splash ", NULL); + modname = strrep(modname, "sprigs ", "sprig ", NULL); modname = strrep(modname, "suits ", "suit ", NULL); modname = strrep(modname, "vials ", "vial ", NULL); @@ -3186,6 +3192,26 @@ object_t *getammo(lifeform_t *lf) { return o; } +objecttype_t *getbasicweaponforskill(enum SKILL skid) { + switch (skid) { + case SK_AXES: + return findot(OT_AXE); + case SK_CLUBS: + return findot(OT_CLUB); + case SK_LONGBLADES: + return findot(OT_LONGSWORD); + case SK_POLEARMS: + return findot(OT_SPEAR); + case SK_SHORTBLADES: + return findot(OT_SHORTSWORD); + case SK_STAVES: + return findot(OT_QUARTERSTAFF); + default: + break; + } + return NULL; +} + object_t *getrandomammo(lifeform_t *lf) { object_t *gun; object_t *o; @@ -3211,6 +3237,26 @@ object_t *getrandomammo(lifeform_t *lf) { return NULL; } +objecttype_t *getrandomammofor(object_t *o) { + objecttype_t *ot; + objecttype_t *poss[MAXCANDIDATES]; + int nposs = 0; + if (!o || !isfirearm(o)) { + return NULL; + } + for (ot = objecttype ; ot ; ot = ot->next) { + if (isammofor(ot, o)) { + poss[nposs++] = ot; + } + } + if (nposs) { + ot = poss[rnd(0,nposs-1)]; + } else { + ot = NULL; + } + return ot; +} + brand_t *getrandombrandfor(objecttype_t *ot) { brand_t *br, **poss; brand_t *result = NULL; @@ -3643,11 +3689,15 @@ char *getobequipinfo(object_t *o, char *buf) { if (f->val[0] == BP_WEAPON) { if (hasflag(o->flags, F_TWOHANDED)) { strcat(buf, " (two-handed weapon)"); - } else { + } else if (ismeleeweapon(o)) { strcat(buf, " (weapon)"); + } else { + strcat(buf, " (makeshift weapon)"); } } else if (f->val[0] == BP_SECWEAPON) { - if (isshield(o)) { + if (hasflag(o->flags, F_TWOHANDED)) { + strcat(buf, " (two-handed weapon)"); + } else if (isshield(o)) { strcat(buf, " (shield)"); } else if (ismeleeweapon(o)) { strcat(buf, " (second weapon)"); @@ -3734,6 +3784,7 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan obmod_t *om; int hasunknownmod = B_FALSE; cell_t *where; + int no_a = B_FALSE; // default to normal name if (hasflag(o->flags, F_VENDITEM)) { @@ -3824,6 +3875,14 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } // end if sight/smell } else if ((o->type->id == OT_SIGN) && !hasflag(o->flags, F_SIGNTEXT)) { strcpy(basename, "blank sign"); + } else if (o->type->id == OT_MAP) { + flag_t *f; + f = hasflag(o->flags, F_MAPTO); + if (f && getskill(player, SK_CARTOGRAPHY)) { + sprintf(basename, "map to %s", f->text); + } else { + strcpy(basename, "map"); + } } else if (o->type->id == OT_WATERDEEP) { sprintf(basename, "%s water", getwaterdepthname(getobdepth(o, player))); } else { @@ -3906,7 +3965,12 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan if (f) { race_t *corpserace; corpserace = findrace(f->val[0]); - sprintf(basename, "%s corpse",corpserace->name); + if (hasflag(corpserace->flags, F_UNIQUE)) { + sprintf(basename, "%s%s corpse",corpserace->name, getpossessive(corpserace->name)); + no_a = B_TRUE; + } else { + sprintf(basename, "%s corpse",corpserace->name); + } } } else if (o->type->id == OT_HEAD) { f = hasflag(o->flags, F_CORPSEOF); @@ -4169,13 +4233,18 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan f = hasflag(o->flags, F_SHOPITEM); if (f) { char pricebuf[BUFLEN]; - sprintf(pricebuf, " [$%d%s]", f->val[0], o->pile->owner ? ", unpaid" : ""); + // get price for _player_ + sprintf(pricebuf, " [$%d%s]", (int)getshopprice(o, player), o->pile->owner ? ", unpaid" : ""); strcat(localbuf, pricebuf); } // apply prefix now! if (count == 1) { if (hasflag(o->flags, F_NO_A)) { + no_a = B_TRUE; + } + + if (no_a) { if (o->type->id == OT_GOLD) { sprintf(prefix, "%d ",count); } else { @@ -4706,6 +4775,25 @@ int getshatterdam(object_t *o) { return shatterdam; } +float getshopprice(object_t *o, lifeform_t *buyer) { + float val; + val = getobvalue(o); + if (buyer) { + float pricepctmod = 0; + enum SKILLLEVEL slev; + // price goes up/down for charisma (+/- 25%) + pricepctmod -= ((getstatmod(buyer, A_CHA)/2) * -1); + + // modify for speech (up to -30%); + slev = getskill(buyer, SK_SPEECH); + if (slev) { + pricepctmod -= (slev*5); + } + val = pctof(val, 100 + pricepctmod); + } + return val; +} + enum SKILLLEVEL gettechlevel(object_t *o) { flag_t *f; enum SKILLLEVEL tlev = PR_INEPT; @@ -5289,9 +5377,8 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addoc(OC_FLORA, "Plants", "All kinds of plants and foliage", ',', C_GREEN); + addoc(OC_FLORA, "Plants", "Some kind of plant/foliage.", ',', C_GREEN); addocnoun(lastobjectclass, "plant"); - addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addoc(OC_ROCK, "Rocks/Gems", "Boring (or not so boring) rocks or plants.", '*', C_GREY); addoc(OC_FOOD, "Food", "Yum!", '%', C_GREY); addocnoun(lastobjectclass, "food"); @@ -5657,7 +5744,15 @@ void initobjects(void) { addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6"); - addot(OT_SHRUB, "shrub", "A small but dense shrub.", MT_PLANT, 40, OC_FLORA); + addot(OT_MISTLETOE, "sprig of mistletoe", "A small cutting of mistletoe.", MT_PLANT, 0.01, OC_FLORA); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "leaf"); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, ""); + addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); + addflag(lastot->flags, F_GLYPH, C_WHITE, NA, NA, ","); + addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, NULL); + addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "3d6"); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addot(OT_SHRUB, "shrub", "A small but dense shrub.", MT_PLANT, 50, OC_FLORA); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, ""); addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_MEDIUM, NA, NULL); @@ -5788,6 +5883,8 @@ void initobjects(void) { addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_POT_RUM, "potion of rum", "String liqour which is sure to make you tipsy.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL); + addflag(lastot->flags, F_FLAMMABLE, 1, NA, NA, "medium fire"); + addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "2d6"); addot(OT_POT_RESTORATION, "potion of restoration", "Restores lost abilities to the drinker.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addot(OT_POT_SLEEP, "potion of sleep", "Puts the drinker into a deep sleep.", MT_GLASS, 1, OC_POTION); @@ -5868,10 +5965,11 @@ void initobjects(void) { addot(OT_SCR_NOTHING, "scroll of nothing", "Looks like a magic scroll, but doesn't do anything.", MT_PAPER, 0.5, OC_SCROLL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 84, RR_UNCOMMON, NULL); - addot(OT_MAP, "piece of graph paper", "Paper containing a set of grid-lines, intended for mapping.", MT_PAPER, 0.5, OC_SCROLL); + addot(OT_GRAPHPAPER, "piece of graph paper", "Paper containing a set of grid-lines, intended for mapping.", MT_PAPER, 0.5, OC_SCROLL); addflag(lastot->flags, F_HOLDCONFER, F_PHOTOMEM, NA, IFKNOWN, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, RR_UNCOMMON, NULL); + addot(OT_MAP, "map", "A visual representation of the area.", MT_PAPER, 0.5, OC_SCROLL); addot(OT_SCR_CREATEMONSTER, "scroll of create monster", "Summons a (probably hostile) monster to a nearby location.", MT_PAPER, 0.5, OC_SCROLL); addflag(lastot->flags, F_LINKSPELL, OT_S_CREATEMONSTER, 4, NA, NULL); @@ -6267,6 +6365,7 @@ void initobjects(void) { // l1 addot(OT_S_CALMANIMALS, "calm animals", "Makes animals within the casters line of sight become peaceful.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addot(OT_S_DETECTPOISON, "detect poison", "Detects any poisoned object in sight of the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); @@ -6560,10 +6659,11 @@ void initobjects(void) { // l3 addot(OT_S_INVISIBILITY, "invisibility", "Temporarily renders the target invisible.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); - addflag(lastot->flags, F_XPVAL, 50, NA, NA, NULL); + //addflag(lastot->flags, F_XPVAL, 50, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_PASSWALL, "passwall", "Allows the caster to temporarily walk through walls.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MODIFICATION, NA, NA, NULL); @@ -6617,11 +6717,12 @@ void initobjects(void) { // translocation /////////////////// // l2 - addot(OT_S_BLINK, "blink", "Teleports the caster to a random location within view.", MT_NOTHING, 0, OC_SPELL); + addot(OT_S_BLINK, "blink", "Teleports the caster to a random location within view. Becomes controlled at power VI.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); - addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_PULL, "pull", "Pulls lifeforms towards the caster.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); @@ -6902,7 +7003,7 @@ void initobjects(void) { addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_EXPLODEONDAM, NA, NA, NA, "8d2"); + addflag(lastot->flags, F_EXPLODEONDAM, DT_FIRE, NA, NA, "8d2"); addflag(lastot->flags, F_DTVULN, DT_FIRE, NA, NA, "2d6"); addflag(lastot->flags, F_FLAMMABLE, 3, NA, NA, NULL); addflag(lastot->flags, F_POWDER, B_TRUE, NA, NA, NULL); @@ -7944,7 +8045,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, 1, NULL); // '1' is randomized during generation addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); - addot(OT_RING_CON, "ring of constitution", "Increases the wearer's constitution.", MT_METAL, 0.1, OC_RING); + addot(OT_RING_CON, "ring of fitness", "Increases the wearer's fitness.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, 1, NULL); // '1' is randomized during generation addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); @@ -8284,7 +8385,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 13, NA, NULL); addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8+4"); + addflag(lastot->flags, F_DAM, DT_SLASH, NA, NA, "1d8"); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, NA, NULL); @@ -8584,8 +8685,8 @@ int isactivated(object_t *o) { return B_FALSE; } -int isammofor(object_t *ammo, object_t *gun) { - if (hasflagval(gun->flags, F_AMMOOB, ammo->type->id, NA, NA, NULL)) { +int isammofor(objecttype_t *ammo, object_t *gun) { + if (hasflagval(gun->flags, F_AMMOOB, ammo->id, NA, NA, NULL)) { return B_TRUE; } return B_FALSE; @@ -8903,7 +9004,7 @@ int ismagical(object_t *o) { switch (o->type->obclass->id) { case OC_SCROLL: switch (o->type->id) { - case OT_MAP: + case OT_GRAPHPAPER: case OT_SCR_NOTHING: // these scrolls are non-magical break; @@ -9513,6 +9614,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { object_t *o, *existob; int i; int db = B_FALSE; + flag_t *f; reason = E_OK; @@ -9524,6 +9626,14 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { cell_t *newcell; newcell = getstairdestination(pit); if (newcell) { + if (haslos(player, dst->where)) { + char obname[BUFLEN]; + char pitname[BUFLEN]; + getobname(src, obname, src->amt); + getobname(pit, pitname, 1); + + msg("%s fall%s down %s.", obname, (src->amt == 1) ? "s" : "", pitname); + } dst = newcell->obpile; } } @@ -9618,6 +9728,13 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { drawscreen(); } + // special effects when an object moves + f = hasflag(o->flags, F_SHOPITEM); + if (f) { + // recalculate object price baesd on who is holding it + calcshopprice(o, f); + } + // special effects if a lifeform picked up an object if (dst->owner) { flag_t *f; @@ -9625,13 +9742,10 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { f = hasflag(o->flags, F_SHOPITEM); if (f) { lifeform_t *shk; - shk = findshopkeeper(dst->owner->cell->map, f->val[1]); - if (shk && cansee(shk, dst->owner)) { - askforpayment(shk, dst->owner); - } - if (!isplayer(dst->owner)) { - msg("xxxxxxxxxxxx"); + shk = findshopkeeper(dst->owner->cell->map, f->val[1]); + if (shk) { + askforpayment(shk, dst->owner); } } @@ -9975,6 +10089,9 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (!lfhasflag(lf, F_HUMANOID) || !hasbp(lf, BP_HANDS)) { // only humanoids can zap things + if (isplayer(lf)) { + msg("You lack the manual dexterity to operate this."); + } return B_TRUE; } @@ -9988,7 +10105,11 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // if not a wand, must know what a tool is before you can use it - if (!isknown(o) && (o->type->obclass->id != OC_WAND)) { + + // also use the same message whn you try to operate something non-operable + // to avoid using this to identify mistletoe. + if (!isoperable(o) || + (!isknown(o) && (o->type->obclass->id != OC_WAND)) ) { if (isplayer(lf)) { msg("You don't know how to use %s!", obname); } @@ -10124,7 +10245,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { // construct list of possible ammo clearretobs(); for (oo = lf->pack->first ; oo ; oo = oo->next) { - if (isammofor(oo, o)) { + if (isammofor(oo->type, o)) { retobs[nretobs] = oo; nretobs++; } @@ -10311,7 +10432,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { } // announce if (!seen) { - noise(where, NULL, 0, "something spraying.", NULL); + noise(where, NULL, NC_OTHER, 0, "something spraying.", NULL); } } else if ((o->type->id == OT_EMPTYFLASK) || (o->type->id == OT_EMPTYVIAL)) { object_t *oo,*nextoo; @@ -10389,6 +10510,32 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { msg("There is nothing here to fill your %s from.",noprefix(obname)); } } + } else if (o->type->id == OT_MISTLETOE) { + if (hasjob(lf, J_DRUID)) { + int amt; + if (isplayer(lf)) { + msg("You sacrifice %s.", obname); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s sacrifices %s.", lfname, obname); + } + + removeob(o, 1); + + // regain mp + amt = getspellduration(getmaxmp(lf)/2, getmaxmp(lf), o->blessed); + if (amt > 0) { + if (isplayer(lf)) { + msg("You feel a surge of magical power!"); + } + gainmp(lf, amt); + } + } else { + if (isplayer(lf)) { + msg("You don't know how to use this."); + } + } } else if (o->type->id == OT_ORBDUNGEONEXIT) { map_t *m; m = lf->cell->map; @@ -10518,7 +10665,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { if (isplayer(lf)) { msg("You play a few notes on your panpipes."); } else { - noise(lf->cell, lf, 3, "the sound of panpipes.", "plays a tune on its panpipes."); + noise(lf->cell, lf, NC_OTHER, 3, "the sound of panpipes.", "plays a tune on its panpipes."); } } else if (o->type->id == OT_PICKAXE) { int ch,dir; @@ -11533,9 +11680,167 @@ int readsomething(lifeform_t *lf, object_t *o) { // removeob one of the object if (isplayer(lf)) msg("The scroll crumbles to dust."); removeob(o, 1); + } else if (o->type->id == OT_GRAPHPAPER) { + if (isplayer(lf)) { + msg("You study your hand-drawn map for a while."); + } } else if (o->type->id == OT_MAP) { if (isplayer(lf)) { - msg("You study your map for a while."); + if (!getskill(lf, SK_CARTOGRAPHY)) { + msg("You can't comprehend this map."); + } else if (lf->cell->map->region->rtype->id == RG_WORLDMAP) { + int lfmx,lfmy,tmx,tmy; + int dist; + cell_t *c; + enum SKILLLEVEL slev; + + f = hasflag(o->flags, F_MAPTO); + getmapcoords(lf->cell->map, &lfmx, &lfmy); + tmx = f->val[0]; + tmy = f->val[1]; + + dist = abs(tmx - lfmx) + abs(tmy - lfmy); + slev = getskill(lf, SK_CARTOGRAPHY); + switch (slev) { + default: + msg("You can't comprehend this map."); + break; + case PR_NOVICE: + // here/not here + if (dist == 0) { + msg("%s is in this area!", f->text); + } else { + msg("%s isn't in this area.", f->text); + } + break; + case PR_BEGINNER: + // near/far dist to that map + if (dist == 0) { + msg("%s is in this area!", f->text); + } else if (dist == 1) { + msg("%s is very nearby.", f->text); + } else { + msg("%s isn't nearby.", f->text); + } + break; + case PR_ADEPT: + // x areas away + if (dist == 0) { + msg("%s is in this area!", f->text); + } else if (dist == 1) { + msg("%s is one area away.", f->text); + } else { + msg("%s is %d areas away.", f->text, dist); + } + break; + case PR_SKILLED: + // x areas away + // plus direction. + if (dist == 0) { + msg("%s is in this area!", f->text); + } else { + char dirbuf[BUFLEN]; + if (dist == 1) { + sprintf(buf, "%s is one area away to the ", f->text); + } else { + sprintf(buf, "%s is %d areas away to the ", f->text, dist); + } + strcpy(dirbuf, ""); + if (tmy < lfmy) { + strcpy(dirbuf, "north"); + } else if (tmy > lfmy) { + strcpy(dirbuf, "south"); + } + if (tmx > lfmx) { + strcat(dirbuf, "east"); + } else if (tmx < lfmx) { + strcat(dirbuf, "west"); + } + strcat(buf, dirbuf); + strcat(buf, "."); + msg("%s", buf); + } + break; + case PR_EXPERT: + // x areas away + // plus direction. + // plus distance within area. + if (dist == 0) { + int dist2; + char distbuf[BUFLEN]; + c = findobinmap(lf->cell->map, f->val[2]); + dist2 = getcelldist(lf->cell, c); + if (dist2 >= 20) { + strcpy(distbuf, "(very far away)"); + } else if (dist2 >= 10) { + strcpy(distbuf, "(far away)"); + } else if (dist2 >= 5) { + strcpy(distbuf, "(nearby)"); + } else { + strcpy(distbuf, "(very nearby)"); + } + msg("%s is in this area %s!", f->text, distbuf); + } else { + char dirbuf[BUFLEN]; + if (dist == 1) { + sprintf(buf, "%s is one area away to the ", f->text); + } else { + sprintf(buf, "%s is %d areas away to the ", f->text, dist); + } + strcpy(dirbuf, ""); + if (tmy < lfmy) { + strcpy(dirbuf, "north"); + } else if (tmy > lfmy) { + strcpy(dirbuf, "south"); + } + if (tmx > lfmx) { + strcat(dirbuf, "east"); + } else if (tmx < lfmx) { + strcat(dirbuf, "west"); + } + strcat(buf, dirbuf); + strcat(buf, "."); + msg("%s", buf); + } + break; + case PR_MASTER: + // x,y coords. + // plus direction. + // plus show on map if in area. + if (dist == 0) { + msg("You have located %s in this area.", f->text); + c = findobinmap(lf->cell->map, f->val[2]); + setcellknownradius(c, slev, 5, DT_ORTH); + } else { + char dirbuf[BUFLEN]; + char buf2[BUFLEN]; + sprintf(buf, "%s is at %d,%d",f->text, tmx,tmy); + if (dist == 1) { + sprintf(buf2, " (one area away to the "); + } else { + sprintf(buf2, " (%d areas away to the ", dist); + } + strcpy(dirbuf, ""); + if (tmy < lfmy) { + strcpy(dirbuf, "north"); + } else if (tmy > lfmy) { + strcpy(dirbuf, "south"); + } + if (tmx > lfmx) { + strcat(dirbuf, "east"); + } else if (tmx < lfmx) { + strcat(dirbuf, "west"); + } + strcat(buf2, dirbuf); + strcat(buf2, ")"); + + msg("%s%s", buf, buf2); + } + break; + } + } else { + msg("You need to be outside to get your bearings first."); + } } } else if (o->type->id == OT_SCR_NOTHING) { if (isplayer(lf)) { @@ -11914,7 +12219,7 @@ int shatter(object_t *o, int hitlf, char *damstring, lifeform_t *fromlf) { seen = B_TRUE; } else { - noise(where, NULL, 3, "shattering glass.", NULL); + noise(where, NULL, NC_OTHER, 3, "shattering glass.", NULL); } if (target) { @@ -12252,8 +12557,10 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); } else { // explode - explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0); - return howmuch; + if ((f->val[0] == NA) || (f->val[0] == damtype)) { + explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0); + return howmuch; + } } } } else { @@ -12261,9 +12568,11 @@ int real_takedamage(object_t *o, unsigned int howmuch, int damtype, int wantanno // object dies! addflag(o->flags, F_DEAD, B_TRUE, NA, NA, NULL); } else { - // explode - explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0); - return howmuch; + if ((f->val[0] == NA) || (f->val[0] == damtype)) { + // explode + explodeob(o, f, (f->val[1] == B_BIG) ? 1 : 0); + return howmuch; + } } } } diff --git a/objects.h b/objects.h index 8c526e3..fa3fff8 100644 --- a/objects.h +++ b/objects.h @@ -26,6 +26,7 @@ void appendinscription(object_t *o, char *text); void applyobmod(object_t *o, obmod_t *om); int blessob(object_t *o); void brightflash(cell_t *centre, int range, lifeform_t *immunelf); +void calcshopprice(object_t *o, flag_t *shopitemflag); int canbepoisoned(enum OBTYPE oid); int canseeob(lifeform_t *lf, object_t *o); object_t *canstackob(obpile_t *op, object_t *match); @@ -67,7 +68,9 @@ int getobvalue(object_t *o); //int getobtypevalue(objecttype_t *ot); char *getaccuracyname(int accpct); object_t *getammo(lifeform_t *lf); +objecttype_t *getbasicweaponforskill(enum SKILL skid); object_t *getrandomammo(lifeform_t *lf); +objecttype_t *getrandomammofor(object_t *o); brand_t *getrandombrandfor(objecttype_t *ot); objecttype_t *getrandomobofclass(enum OBCLASS ocid, int minrarity, int maxrarity); char *getdamname(enum DAMTYPE damtype); @@ -110,6 +113,7 @@ enum SPELLSCHOOL getschool(enum OBTYPE sid); char *getschoolname(enum SPELLSCHOOL sch); char *getschoolnameshort(enum SPELLSCHOOL sch); int getshatterdam(object_t *o); +float getshopprice(object_t *o, lifeform_t *buyer); enum SKILLLEVEL gettechlevel(object_t *o); int getthrowdam(object_t *o); char *gettopobname(cell_t *c, char *retbuf); @@ -128,7 +132,7 @@ void ignite(object_t *o); void initobjects(void); flag_t *isarmour(object_t *o); int isactivated(object_t *o); -int isammofor(object_t *ammo, object_t *gun); +int isammofor(objecttype_t *ammo, object_t *gun); int isbadfood(object_t *o); int isbetterarmourthan(object_t *a, object_t *b); int isbetterwepthan(object_t *a, object_t *b); diff --git a/spell.c b/spell.c index b0405dd..e1e9bd3 100644 --- a/spell.c +++ b/spell.c @@ -1345,9 +1345,10 @@ 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)) { + if (canhear(target, user->cell, 4)) { scare(target, user, rnd(5,10), 0); } } @@ -1355,7 +1356,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } else if (abilid == OT_A_HURRICANESTRIKE) { int dir; cell_t *c; - flag_t *f,*f2; + flag_t *f,*f2,*f3; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You cannot do that while swimming."); @@ -1370,6 +1371,9 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef f = addflag(user->flags, F_NOTIME, B_TRUE, NA, NA, NULL); // lower accuracy f2 = addflag(user->flags, F_ACCURACYMOD, -20, NA, NA, NULL); + // remember we are doing a hurricane attack to avoid lots of + // "there is nothing to attack there" messages. + f3 = addflag(user->flags, F_HURRICANESTRIKE, B_TRUE, NA, NA, NULL); // attack all adjacent enemies for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(user->cell, dir); @@ -1380,6 +1384,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // remove temporary flags killflag(f); killflag(f2); + killflag(f3); } else if (abilid == OT_A_HIDE) { int penalty = 0; @@ -1547,6 +1552,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ addflag(caster->flags, F_BOOSTSPELL, spellid, cost, power, NULL); } } + + // druids gain power from nearby plants + if (hasjob(caster, J_DRUID)) { + cell_t *c; + int d; + float totweight = 0; + int powerinc = 0; + for (d = DC_N; d <= DC_NW; d++) { + c = getcellindir(caster->cell, d); + if (c) { + object_t *o; + for (o = c->obpile->first ; o ; o = o->next){ + if (o->type->obclass->id == OC_FLORA) totweight += getobweight(o); + } + } + } + powerinc = totweight / 50; + if (powerinc > 0) { + power += powerinc; + } + } } // switch based on spell effects... @@ -1843,16 +1869,28 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); } else { int tries = 0,maxtries = 10; - // pick a random location - targcell = NULL; - while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, B_FALSE, NULL)) { - int i; - i = rnd(0,caster->nlos-1); - targcell = caster->los[i]; - tries++; - if (tries >= maxtries) { + if (lfhasflag(caster, F_CONTROL) && (power < 6)) { + power = 6; + } + if (power >= 6) { + // controlled + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power, frompot)) return B_TRUE; + if (!targcell) { fizzle(caster); - return B_FALSE; + return B_TRUE; + } + } else { + // pick a random location + targcell = NULL; + while (!targcell || !cellwalkable(caster, targcell, NULL) || celldangerous(caster, targcell, B_FALSE, NULL)) { + int i; + i = rnd(0,caster->nlos-1); + targcell = caster->los[i]; + tries++; + if (tries >= maxtries) { + fizzle(caster); + return B_FALSE; + } } } teleportto(caster, targcell, B_TRUE); @@ -4532,7 +4570,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (ismetal(o->material->id)) { flag_t *f; f = isequipped(o); - if ((f->val[0] != BP_WEAPON) && (f->val[0] != BP_SECWEAPON)) { + if (f && (f->val[0] != BP_WEAPON) && (f->val[0] != BP_SECWEAPON)) { gotmetal = B_TRUE; metalweight += getobweight(o); break; @@ -4639,7 +4677,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // find new map ! - newmap = findmapofdepth(newdepth); + + //newmap = findmapofdepth(newdepth); + newmap = findregionmap(caster->cell->map->region->id, newdepth); if (!newmap) { // create new map newmap = addmap(); @@ -4739,7 +4779,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } getlfname(target, targname); - howlong = getspellduration(20,40,blessed) + (power*2); + // time is based on spellpower + howlong = getspellduration(5,10,blessed) + (power*2); if (!isplayer(target) && cansee(player, target) ) { willannounce = B_TRUE; if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -5218,6 +5259,19 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_MENDING) { object_t *o; + int donesomething = B_FALSE; + flag_t *f; + char fullobname[BUFLEN]; + char obname[BUFLEN]; + getobname(o, obname, o->amt); + + if (isplayer(caster)) { + sprintf(fullobname, "Your %s", noprefix(obname)); + } else if (cansee(player, caster)) { + sprintf(fullobname, "%s%s %s", castername, getpossessive(castername), noprefix(obname)); + } else { + strcpy(fullobname, ""); + } if (targob) { o = targob; @@ -5230,34 +5284,43 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } - if (isplayer(caster)) { - flag_t *f; - f = hasflag(o->flags, F_OBHP); - if (!f) { - nothinghappens(); - return B_TRUE; + f = hasflag(o->flags, F_OBHP); + if (f && isdamaged(o)) { + if (blessed == B_CURSED) { + if (isplayer(caster) || cansee(player, caster)) msg("%s deteriorates!", fullobname); + takedamage(o, rnd(1,6) + power, DT_DIRECT); + donesomething = B_TRUE; } else { - char obname[BUFLEN]; - getobname(o, obname, o->amt); + f->val[0] += (rnd(1,6) + power); - if (blessed) { - f->val[0] += (rnd(1,6) + power); - - if (f->val[0] >= f->val[1]) { - msg("Your %s is completely repaired!", noprefix(obname)); - f->val[0] = f->val[1]; - } else { - msg("Your %s is repaired a little!", noprefix(obname)); - } + if (f->val[0] >= f->val[1]) { + if (isplayer(caster) || cansee(player, caster)) msg("%s is completely repaied!", fullobname); + f->val[0] = f->val[1]; } else { - msg("Your %s deteriorates!", noprefix(obname)); - takedamage(o, rnd(1,6) + power, DT_DIRECT); + if (isplayer(caster) || cansee(player, caster)) msg("%s is repaired a little!", fullobname); } + donesomething = B_TRUE; + } + } + + // fix dulled weapons + if (!iscursed(o)) { + f = hasflag(o->flags, F_BONUS); + if (f && (f->val[0] < 0)) { + killflag(f); + if (isplayer(caster) || cansee(player, caster)) msg("%s seems more effective!", fullobname); + donesomething = B_TRUE; + } + } + + if (donesomething) { + if (strlen(fullobname)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } } else { - // monsters can't repair things! + nothinghappens(); + return B_TRUE; } } else if (spellid == OT_S_PACIFY) { char targetname[BUFLEN]; @@ -6712,7 +6775,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ o = relinkob(o, newloc->obpile); } if (o) { - noise(caster->cell, NULL, 1, "something hitting the ground.", NULL); + noise(caster->cell, NULL, NC_OTHER, 1, "something hitting the ground.", NULL); if (!isblind(caster)) { msg("%s appear%s on the ground!", obname, (o->amt == 1) ? "s" : ""); } @@ -6913,6 +6976,10 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf) { } if (spellid == OT_S_DETECTLIFE) { + if (power >= 6) { + strcat(buf, "(ctrl)"); + } + } else if (spellid == OT_S_DETECTLIFE) { if (power >= 5) { strcat(buf, "(enhanced)"); } diff --git a/text.c b/text.c index dd73cdf..70a24ff 100644 --- a/text.c +++ b/text.c @@ -119,14 +119,16 @@ char *getattrabbrev(enum ATTRIB att) { switch (att) { case A_NONE: return "??"; - case A_STR: - return "St"; - case A_IQ: - return "Iq"; + case A_CHA: + return "Ch"; + case A_CON: + return "Fi"; case A_DEX: return "Dx"; - case A_CON: - return "Cn"; + case A_IQ: + return "Iq"; + case A_STR: + return "St"; } return "??"; } @@ -135,14 +137,16 @@ char *getattrname(enum ATTRIB att) { switch (att) { case A_NONE: return "?attrib_none?"; - case A_STR: - return "strength"; - case A_IQ: - return "intelligence"; + case A_CHA: + return "charisma"; + case A_CON: + return "fitness"; case A_DEX: return "dexterity"; - case A_CON: - return "constitution"; + case A_IQ: + return "intelligence"; + case A_STR: + return "strength"; } return "?badattrib?"; } @@ -396,6 +400,8 @@ char *makeplural(char *text) { if (rv) return newtext; newtext = strrep(newtext, "set ", "sets ", &rv); if (rv) return newtext; + newtext = strrep(newtext, "sprig ", "sprigs ", &rv); + if (rv) return newtext; newtext = strrep(newtext, "suit ", "suits ", &rv); if (rv) return newtext; newtext = strrep(newtext, "vial ", "vials ", &rv);