diff --git a/ai.c b/ai.c index 3248a7e..d6e8057 100644 --- a/ai.c +++ b/ai.c @@ -488,7 +488,7 @@ void aimove(lifeform_t *lf) { } // if not adjacent, check for guns, wands, throwing - if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf, target->cell, B_FALSE, NULL)) { + if (goingtomove && (getcelldist(lf->cell, target->cell) > 1) && haslof(lf->cell, target->cell, LOF_NEED, NULL)) { // can we attack by firing a weapon? gun = getfirearm(lf); if (goingtomove && gun && getammo(lf)) { @@ -609,6 +609,7 @@ void aimove(lifeform_t *lf) { if (db) dblog(".oO { walking from %d,%d towards f_targetcell (%d,%d) ... }", lf->cell->x, lf->cell->y, x, y); c = getcellat(lf->cell->map, x, y); if (c) { + // target cell adjacent and something in the way? if (movetowards(lf, c, DT_ORTH)) { // couldn't move towards it for some reason. // so stop trying. @@ -929,7 +930,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG srange = srflag->val[0]; } - if (!haslof(lf, victim->cell, LOF_NEED,NULL)) { + if (!haslof(lf->cell, victim->cell, LOF_NEED,NULL)) { specificcheckok = B_FALSE; } else if (isimmobile(lf) || !lfhasflag(lf, F_FLYING)) { specificcheckok = B_FALSE; diff --git a/attack.c b/attack.c index 5fe6b8e..d6bd84f 100644 --- a/attack.c +++ b/attack.c @@ -23,7 +23,7 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty // figure out what bit of armour was hit - // special case - missiles against flak jacket + // special case - missiles always hit flak jacket if (damtype == DT_PROJECTILE) { object_t *o; o = getequippedob(lf->pack, BP_BODY); @@ -38,8 +38,6 @@ int applyarmourdamage(lifeform_t *lf, object_t *wep, int dam, enum DAMTYPE damty armour = getrandomarmour(lf); } - - if (armour) { int actualdam; flag_t *rust; @@ -573,7 +571,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim) { if (lfhasflag(victim, F_DODGES)) { cell_t *adj; - adj = getrandomadjcell(victim->cell, WE_NOTSOLID); + adj = getrandomadjcell(victim->cell, WE_WALKABLE, B_NOEXPAND); if (adj) { flag_t *f; f = addflag(victim->flags, F_NOTIME, B_TRUE, NA, NA, NULL); @@ -827,8 +825,10 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam } else { return "bash"; } - } else { + } else if (pct <= 30) { return "pummel"; + } else { + return "slam"; } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { @@ -1332,6 +1332,30 @@ obpile_t *getunarmedweapon(lifeform_t *lf,flag_t **uflag) { return op; } +int isphysicaldam(enum DAMTYPE damtype) { + switch (damtype) { + case DT_BASH: + case DT_BITE: + case DT_CHOP: + case DT_CLAW: + case DT_COLD: + case DT_CRUSH: + case DT_ELECTRIC: + case DT_EXPLOSIVE: + case DT_FALL: + case DT_FIRE: + case DT_MAGIC: + case DT_PIERCE: + case DT_PROJECTILE: + case DT_SLASH: + case DT_UNARMED: + return B_TRUE; + default: + break; + } + return B_FALSE; +} + int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical) { int acc,ev; object_t *wep; @@ -1475,6 +1499,53 @@ void wepeffects(flagpile_t *fp, cell_t *where, int dam) { } // end if dampct > 50 } } + } else if ((f->id == F_DISARMATTACK) && victim && owner && !isdead(victim)) { + object_t *victimwep; + skill_t *sk; + int skillmod; + + victimwep = getweapon(victim); + if (victimwep) { + sk = getobskill(wep); + if (sk) { + skillmod = getskill(owner, sk->id); + if (skillmod == 0) skillmod = -5; + } else { + skillmod = 0; + } + + if (skillcheckvs(owner, SC_DEX, skillmod, victim, SC_SLIP, 0)) { + char lfname[BUFLEN]; + char victimname[BUFLEN]; + getlfname(owner,lfname); + getlfname(victim, victimname); + if (cansee(player, owner)) { + msg("%s disarm%s %s!",lfname, isplayer(owner) ? "" : "s", victimname); + } + drop(victimwep, ALL); + } + } + } else if ((f->id == F_TRIPATTACK) && victim && owner && !isdead(victim)) { + skill_t *sk; + int skillmod; + sk = getobskill(wep); + if (sk) { + skillmod = getskill(owner, sk->id); + if (skillmod == 0) skillmod = -5; + } else { + skillmod = 0; + } + + if (skillcheckvs(owner, SC_DEX, skillmod, victim, SC_SLIP, 0)) { + char lfname[BUFLEN]; + char victimname[BUFLEN]; + getlfname(owner,lfname); + getlfname(victim, victimname); + if (cansee(player, owner)) { + msg("%s trip%s %s.",lfname, isplayer(owner) ? "" : "s", victimname); + } + fall(victim, B_TRUE); + } } else if ((f->id == F_HEAVYBLOW) && victim && owner) { int dir; // knock back victim @@ -1487,7 +1558,8 @@ void wepeffects(flagpile_t *fp, cell_t *where, int dam) { enum FLAG fid; int min,max,howlong; fid = f->val[0]; - if (!lfhasflag(victim, fid)) { + // the f_poisoned flag stacks, others don't. + if (!lfhasflag(victim, fid) || (fid == F_POISONED)) { int passedcheck = B_FALSE; // do they get a saving throw? if (f->val[1] != NA) { @@ -1544,7 +1616,7 @@ void wepeffects(flagpile_t *fp, cell_t *where, int dam) { } else { strcpy(frombuf, "something unknown"); } - addtempflag(victim->flags, fid, NA, NA, NA, frombuf, howlong); + poison(victim, howlong, frombuf); } else { addtempflag(victim->flags, fid, NA, NA, NA, NULL, howlong); } diff --git a/attack.h b/attack.h index 70fe95b..eecc6f7 100644 --- a/attack.h +++ b/attack.h @@ -20,5 +20,6 @@ int getdamroll(object_t *o, lifeform_t *victim); int getdamrollfromflag(flag_t *f); float getstrdammod(lifeform_t *lf); obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag); +int isphysicaldam(enum DAMTYPE damtype); int rolltohit(lifeform_t *lf, lifeform_t *victim, int *critical); void wepeffects(flagpile_t *fp, cell_t *where, int dam); diff --git a/defs.h b/defs.h index 25582bc..60a004f 100644 --- a/defs.h +++ b/defs.h @@ -8,6 +8,9 @@ #define WETTIME 10 // how long it takes for things to dry +#define POISONDAMCHANCE 33 // chance of vomitting when poisoned +#define POISONDAM 2 // damage taken from vomiting when poisoned + // ncurses colours enum COLOUR { C_BLACK = 0, @@ -607,6 +610,7 @@ enum OBTYPE { OT_ROASTMEAT, OT_BREADFRESH, OT_CHOCOLATE, + OT_CLOVER, // corpses OT_CORPSE, OT_HEAD, @@ -642,6 +646,7 @@ enum OBTYPE { OT_POT_INVULN, OT_POT_MAGIC, OT_POT_OIL, + OT_POT_POISON, OT_POT_POLYMORPH, OT_POT_RESTORATION, OT_POT_SANCTUARY, @@ -678,6 +683,7 @@ enum OBTYPE { OT_MAN_LOCKPICKING, OT_MAN_MAGITEMUSAGE, OT_MAN_RESEARCH, + OT_MAN_SHIELDS, OT_MAN_SPELLCASTING, OT_MAN_STEALTH, OT_MAN_TECHUSAGE, @@ -798,6 +804,7 @@ enum OBTYPE { // -- elemental - air OT_S_AIRBLAST, OT_S_CLOUDKILL, + OT_S_WINDSHIELD, // -- elemental - fire OT_S_SPARK, OT_S_FIREDART, @@ -869,6 +876,7 @@ enum OBTYPE { OT_A_EMPLOY, OT_A_HEAVYBLOW, OT_A_INSPECT, + OT_A_POLYREVERT, OT_A_STINGACID, // need to define dam in f_canwill // wands OT_WAND_COLD, @@ -989,16 +997,23 @@ enum OBTYPE { OT_BUCKLER, OT_SHIELD, OT_SHIELDLARGE, + OT_SHIELDTOWER, // rings OT_RING_INVIS, OT_RING_INVULN, OT_RING_LUCK, + OT_RING_CONTROL, + OT_RING_CON, + OT_RING_DEX, + OT_RING_IQ, + OT_RING_STR, OT_RING_MANA, + OT_RING_MIRACLES, OT_RING_MPREGEN, OT_RING_PROTFIRE, OT_RING_REGENERATION, OT_RING_RESISTMAG, - OT_RING_SEEINVIS, + OT_RING_SIGHT, OT_RING_WOUNDING, // animal weapons OT_CLAWS, @@ -1021,48 +1036,57 @@ enum OBTYPE { OT_JAVELIN, OT_BULLET, OT_RUBBERBULLET, - // stabbing weapons - OT_DAGGER, - OT_COMBATKNIFE, - OT_ORNDAGGER, - OT_RAPIER, - OT_TRIDENT, - OT_QUICKBLADE, - // chopping weapons + // axes OT_AXE, OT_HANDAXE, OT_BATTLEAXE, OT_GREATAXE, - // slashing weapons + // short blades + OT_COMBATKNIFE, + OT_DAGGER, OT_KNIFE, - OT_STEAKKNIFE, - OT_SCYTHE, + OT_ORNDAGGER, + OT_QUICKBLADE, + OT_RAPIER, + OT_SAI, OT_SHORTSWORD, - OT_SCIMITAR, - OT_LONGSWORD, + OT_STEAKKNIFE, + OT_SICKLE, + // long swords + OT_FALCHION, OT_GREATSWORD, + OT_LONGSWORD, OT_ORNSWORD, + OT_SCIMITAR, // polearms + OT_GLAIVE, + OT_GUISARME, + OT_HALBERD, + OT_LANCE, + OT_RANSEUR, + OT_SCYTHE, OT_SPEAR, + OT_TRIDENT, + // staves OT_QUARTERSTAFF, - // bashing weapons - OT_STICK, - OT_SPANNER, + // clubs OT_CLUB, OT_FLAIL, OT_FLAILHEAVY, + OT_GREATCLUB, OT_MACE, OT_MORNINGSTAR, - OT_GREATCLUB, - OT_SICKLE, + OT_NUNCHAKU, + OT_SPANNER, + OT_STICK, // projectile weapons - OT_REVOLVER, - OT_SLING, OT_BOW, - OT_LONGBOW, OT_CROSSBOW, OT_CROSSBOWHAND, - // holy weapons + OT_LONGBOW, + OT_REVOLVER, + OT_SLING, + // special weapons OT_HANDOFGOD, @@ -1087,7 +1111,7 @@ enum BODYPART { #define MAXBODYPARTS (12) // empty types -#define WE_NOTSOLID 1 +#define WE_WALKABLE 1 #define WE_EMPTY 2 #define WE_PORTAL 3 @@ -1126,6 +1150,7 @@ 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_IDWHENUSED, // fully identify an object when worn/weilded/operated/etc // for items in shops F_SHOPITEM, // causes shops to show this item as identified F_VALUE, // how much an item is worth (over its base weight+material) @@ -1148,6 +1173,7 @@ enum FLAG { F_DIECONVERTTEXTPL, // text when the object converts, if there are more than 1. eg. "melt" F_DIECONVERT, // val0 = what this turns into when dying F_NOBLESS, // can't be blessed or cursed + F_NOQUALITY, // can't be masterwork / shoddy F_CORPSEOF, // this is a corpse of montype val0. F_DTCONVERT, // damtype val0 converts this to f->text F_NODTCONVERT, // overrides DTCONVERT . @@ -1245,6 +1271,8 @@ enum FLAG { F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better) F_ARMOURPIERCE, // goes through armour F_TWOHANDED, // weapon uses two hands to weild + F_TRIPATTACK, // weapon can trip the victim + F_DISARMATTACK, // weapon can disarm the victim F_FIREARM, // this weapon is equipped in bp_secweapon, not _weapon. F_FIRESPEED, // how fast this weapon shoots projectiles F_AMMOOB, // what object this weapon fires @@ -1286,9 +1314,13 @@ enum FLAG { F_WALKDAM, // val0 = damtype, text = dam per sec // abilities F_NEEDSGRAB, // this ability needs to to grab someone first. + F_NOANNOUNCE, // don't announce when you gain/lose this ability // magic F_SPELLSCHOOL, // val0 = SPELLSCHOOL enum F_SPELLLEVEL, // val0 = difficulty level of spell + F_VARPOWER, // can cast this spell at variable power level + // for spells with this flag, the MP cost goes up + // based on the power level. F_MAXPOWER, // val0 = max power of this spell (1-10) F_MPCOST, // v0=mp cost of spell. if missing, mpcost if splev^2 F_ONGOING, // this spell has an ongoing cost @@ -1309,6 +1341,8 @@ enum FLAG { F_DONEDARKMSG, // tells the game not to say 'it is very dark here' // lifeform flags / lf flags F_DEBUG, // debugging enabled + F_SHIELDPENALTY, // modify your accuracy by val0 due to a cumbersome + // shield F_ATTRMOD, // modify attribute val0 by val1. ie. 0=A_STR,1=-3 F_ATTRSET, // forces attribute val0 to be val1. ie. 0=A_STR,1=18 F_SIZE, // val0 = lf size (enum LFSIZE) @@ -1318,6 +1352,7 @@ enum FLAG { F_RESTHEALMPAMT, // val0 = how many MP to gain after resting x turns F_AUTOCMD, // val0 = how many times to repeat this F_LASTCMD, // text[0] = last command performed, v0/1 = x/y of cell, v2=various + F_CANLEARN, // lf is able to learn skill val0 F_STARTOB, // val0 = %chance of starting with it, text = ob name // val1,2 = min/max amounts. if NA, min=max=1. F_STARTSKILL, // val0 = skill id @@ -1333,6 +1368,8 @@ enum FLAG { F_GUNTARGET, // current projectile weapon target F_CASTINGSPELL, // set while the player is casting a spell // v0 is spell id + F_AVOIDCURSEDOB, // for AI animals - they will avoid walking on obid 'text' + // (text is a long) // ABILITY/SPELL FLAGS / ability flags / spell flags F_FAILEDINSPECT, // lf has failed an inspect check for item id v0 F_BOOSTSPELL, // v0 is active boost spell @@ -1402,11 +1439,14 @@ enum FLAG { // to the victim F_PHALANX, // gain v0 AR if v2 or more adj monsters matching f->text // INTRINSICS - F_ARBOOST,// armour is magically boosted + F_MAGICARMOUR,// armour is magically boosted. f->text is the description + // ie 'magic armour', 'force field' F_ASLEEP, // is asleep F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn) F_BLIND, // cannot see anything F_CANCAST, // can cast the spell val0 (need MP) + F_CANHEARLF, // you can hear lifeform id v0 (show their glyph) + // this flag does not get announced. F_CANWILL, // can cast the spell/ability val0 without using MP // v1 is counter untiluse // v2 is what you need to use it @@ -1416,8 +1456,11 @@ enum FLAG { // dam:xdy+b; damage // needgrab:xx; do you need to grab first? F_CHARMEDBY,// you've been charmed by lf id v0 + F_CONTROL,// you control polymorphs, teleports and createmonsters F_DETECTAURAS, // autodetect bless/curse F_DETECTLIFE, // autodetect nearby lifeforms in orthogonal dist v0 + // if v1 is true, actual lf glyphs are shown. + // otherwise just an indicative size is shown F_DETECTMAGIC, // autodetect magic/special objects F_DETECTMETAL, // autodetect nearby metal F_DETECTOBS, // autodetect nearby obs in orthog dist v0 @@ -1467,6 +1510,8 @@ enum FLAG { F_CANSEETHROUGHMAT, //val0=kind of material you can see through F_SPRINTING, // v0=true: you are sprinting. false=you are tired F_TIRED, // you are too tired to sprint + F_WINDSHIELD,// has a windshield protecting against missiles of speed + // v0 or lower. F_DODGES, // you dodge missed attacks F_NOTIME, // this lf's actions don't take time F_PERCEPTION, // v0 = 0-20. perception level. @@ -1584,6 +1629,8 @@ enum SPELLTARGET { #define B_TRANSPARENT (-1) #define B_TRANS (-1) +#define B_ALLOWEXPAND (-1) +#define B_NOEXPAND (0) #define B_IFACTIVATED (-1) @@ -1857,6 +1904,7 @@ enum SKILL { SK_LOCKPICKING, SK_MAGITEMUSAGE, SK_RESEARCH, + SK_SHIELDS, SK_SPELLCASTING, SK_STEALTH, SK_TECHUSAGE, @@ -1883,7 +1931,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 31 +#define MAXSKILLS 32 // proficiency levels enum SKILLLEVEL { diff --git a/doc/add_damtype.txt b/doc/add_damtype.txt index f337380..2bcd3f3 100644 --- a/doc/add_damtype.txt +++ b/doc/add_damtype.txt @@ -6,6 +6,8 @@ in objcets.c: update getdamnamenoun() - eg. you are immune to "electricity" in attack.c + update isphysicaldam() + update getattackverb if required update getkillverb if required @@ -14,3 +16,4 @@ in attack.c ie. hitting a door with DT_CHOP won't damage the weapon ie. hitting a door with DT_SLASH _will_ damage the weapon + diff --git a/flag.c b/flag.c index 3ad2aa0..247076d 100644 --- a/flag.c +++ b/flag.c @@ -342,7 +342,9 @@ void killflag(flag_t *f) { // we will revert to our original form at the end of timeeffectslf(). if (lf && (f->id == F_POLYMORPHED)) { - lf->polyrevert = B_TRUE; + if (lfhasflag(lf, F_ORIGRACE)) { + lf->polyrevert = B_TRUE; + } } // free mem diff --git a/io.c b/io.c index 1ef7172..d8ca87e 100644 --- a/io.c +++ b/io.c @@ -357,6 +357,7 @@ char askchar(char *prompt, char *validchars, char *def, int showchars) { } cell_t *askcoords(char *prompt, int targettype) { + static int startlf = -1; int finished = B_FALSE; int moved = B_FALSE; cell_t *c,*newcell; @@ -365,6 +366,13 @@ cell_t *askcoords(char *prompt, int targettype) { int ntargets = 0,curtarget = -1; int x,y; + // remember previously targetted lifeforms + if (startlf > 0) { + if (!findlf(player->cell->map, startlf)) { + startlf = -1; + } + } + // build list of targets if required if (targettype != TT_NONE) { for (y = 0; y < player->cell->map->h; y++) { @@ -392,11 +400,21 @@ cell_t *askcoords(char *prompt, int targettype) { } } + // start prompting if (curtarget == -1) { c = player->cell; } else { + int i; + // override curtarget based on previous target + for (i = 0; i < ntargets; i++) { + if (target[i]->lf && (target[i]->lf->id == startlf)) { + curtarget = i; + break; + } + } + c = target[curtarget]; } @@ -481,7 +499,7 @@ cell_t *askcoords(char *prompt, int targettype) { if (strlen(extrainfo)) strcat(extrainfo, ", "); secwep = getequippedob(c->lf->pack, BP_SECWEAPON); - if (secwep) { + if (secwep && (secwep != wep)) { getobname(secwep, obname, secwep->amt); strcat(buf2, " and "); strcat(buf2, obname); @@ -584,6 +602,11 @@ cell_t *askcoords(char *prompt, int targettype) { ch = getch(); if (ch == '.') { clearmsg(); + + // remember this target + if (c->lf) { + startlf = c->lf->id; + } return c; } else if (ch == 27) { // ESC - cancel finished = B_TRUE; @@ -685,13 +708,13 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "weaker" : "stronger"); break; case A_IQ: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less smart" : "smarter"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "foolish" : "smarter"); break; case A_DEX: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less agile" : "more agile"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "sluggish" : "agile"); break; case A_CON: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less healthy" : "healthier"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "frail" : "healthier"); break; } donesomething = B_TRUE; @@ -711,14 +734,14 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < myatt) ? "sluggish" : "agile"); break; case A_CON: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "less healthy" : "healthier"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] < 0) ? "frail" : "healthier"); break; } } donesomething = B_TRUE; break; - case F_ARBOOST: - msg("A magical shield appears around %s!",lfname); + case F_MAGICARMOUR: + msg("%s %s appears around %s!",needan(f->text) ? "An" : "A", f->text, lfname); donesomething = B_TRUE; break; case F_ASLEEP: @@ -751,7 +774,7 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { if (isplayer(lf)) { // don't know if monsters get it objecttype_t *ot; ot = findot(f->val[0]); - if (ot) { + if (ot && (!hasflag(ot->flags, F_NOANNOUNCE))) { msg("You have learned the ability '%s'.", ot->name); donesomething = B_TRUE; } @@ -765,6 +788,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_CONTROL: + if (isplayer(lf)) { // don't know if monsters get it + msg("You feel very in control of yourself."); + donesomething = B_TRUE; + } + break; case F_DTIMMUNE: if (isplayer(lf)) { // don't know if monsters get it msg("You feel immune to %s!", getdamnamenoun(f->val[0])); @@ -915,8 +944,10 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; break; case F_NAUSEATED: - msg("%s %s nauseated by a disgusting stench!",lfname, isplayer(lf) ? "are" : "is"); - donesomething = B_TRUE; + if (isplayer(lf)) { + msg("You are nauseated by a disgusting stench!"); + donesomething = B_TRUE; + } break; case F_NONCORPOREAL: msg("%s%s body becomes transparent!",lfname, getpossessive(lfname)); @@ -988,6 +1019,13 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s looks exhausted.",lfname); } break; + case F_WINDSHIELD: + if (isplayer(lf)) { + msg("You are surrounded by a whirling cyclone!"); + } else if (cansee(player, lf)) { + msg("%s is surrounded by a whirling cyclone!",lfname); + } + break; case F_VISRANGEMOD: if (isplayer(lf)) { // don't know if monsters get it char fartext[BUFLEN]; @@ -1025,6 +1063,9 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { default: // no message break; } + + if (donesomething) statdirty = B_TRUE; + return donesomething; } @@ -1048,16 +1089,16 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { case F_ATTRMOD: switch (f->val[0]) { case A_STR: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "weaker" : "stronger"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less strong" : "less weak"); break; case A_IQ: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less smart" : "smarter"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less smart" : "less foolish"); break; case A_DEX: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less agile" : "more agile"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less agile" : "less sluggish"); break; case A_CON: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "healthier"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "less frail"); break; } donesomething = B_TRUE; @@ -1068,23 +1109,23 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { myatt = getattr(lf, f->val[0]); switch (f->val[0]) { case A_STR: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "weak" : "strong"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less strong" : "less weak"); break; case A_IQ: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "foolish" : "smart"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less smart" : "less foolish"); break; case A_DEX: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "sluggish" : "agile"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > myatt) ? "less agile" : "less sluggish"); break; case A_CON: - msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "healthier"); + msg("%s %s %s!",lfname, isplayer(lf) ? "feel" : "seems", (f->val[1] > 0) ? "less healthy" : "less frail"); break; } donesomething = B_TRUE; } break; - case F_ARBOOST: - msg("%s%s magical shield vanishes.",lfname,getpossessive(lfname)); + case F_MAGICARMOUR: + msg("%s%s %s vanishes.",lfname,getpossessive(lfname), f->text); donesomething = B_TRUE; break; case F_ASLEEP: @@ -1113,7 +1154,7 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { if (isplayer(lf)) { // don't know if monsters lose it objecttype_t *ot; ot = findot(f->val[0]); - if (ot) { + if (ot && (!hasflag(ot->flags, F_NOANNOUNCE))) { msg("You can no longer use the ability '%s'.", ot->name); donesomething = B_TRUE; } @@ -1128,6 +1169,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; } break; + case F_CONTROL: + if (isplayer(lf)) { // don't know if monsters lose it + msg("You feel less controlled."); + donesomething = B_TRUE; + } + break; case F_DTIMMUNE: if (isplayer(lf)) { // don't know if monsters lose it msg("You are no longer immune to %s.", getdamnamenoun(f->val[0])); @@ -1370,6 +1417,11 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { } donesomething = B_TRUE; break; + case F_WINDSHIELD: + if (isplayer(lf) || cansee(player, lf)) { + msg("%s%s cyclonic shield vanishes.", lfname, getpossessive(lfname)); + } + break; case F_VISRANGEMOD: if (isplayer(lf)) { // don't know if monsters get it char fartext[BUFLEN]; @@ -1407,6 +1459,9 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { default: // no message break; } + + if (donesomething) statdirty = B_TRUE; + return donesomething; } @@ -1485,9 +1540,9 @@ void announceobflagloss(object_t *o, flag_t *f) { } if (o->amt == 1) { - strcat(isare, "is"); + strcpy(isare, "is"); } else { - strcat(isare, "are"); + strcpy(isare, "are"); } switch (f->id) { @@ -1507,16 +1562,18 @@ void announceobflagloss(object_t *o, flag_t *f) { object_t *askobject(obpile_t *op, char *prompt, int *count, long opts) { - return doaskobject(op, prompt, count, opts, F_NONE, OC_NULL); + return doaskobject(op, prompt, count, opts, F_NONE); } object_t *askobjectwithflag(obpile_t *op, char *prompt, int *count, long opts, enum FLAG withflag) { - return doaskobject(op, prompt, count, opts, withflag, OC_NULL); + return doaskobject(op, prompt, count, opts, withflag, F_NONE); } +/* object_t *askobjectofclass(obpile_t *op, char *prompt, int *count, long opts, enum OBCLASS obclass) { return doaskobject(op, prompt, count, opts, F_NONE, obclass, OC_NULL); } +*/ int contains(enum OBCLASS *array, int nargs, enum OBCLASS want) { @@ -1529,7 +1586,77 @@ int contains(enum OBCLASS *array, int nargs, enum OBCLASS want) { return B_FALSE; } -object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, enum FLAG withflag, ...) { +void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters) { + int lastclass = OC_NULL; + int i; + int useobletters = B_TRUE; + if (myletters) { + useobletters = B_FALSE; + } + for (i = firstob ; (mylist[i] != NULL) && (*y < lastline); i++) { + char selchar; + char buf[BUFLEN]; + char obname[BUFLEN]; + char infobuf[BUFLEN]; + char equipbuf[BUFLEN]; + if (mylist[i]->type->obclass->id != lastclass) { + // print class heading + wattron(win, A_STANDOUT); + mvwprintw(win, *y, 0, "%s", mylist[i]->type->obclass->name); + (*y)++; + wattroff(win, A_STANDOUT); + + lastclass = mylist[i]->type->obclass->id; + + } + // print object name + getobname(mylist[i], obname,mylist[i]->amt); + + if (sellist && sellist[i]) { + if ((selcount[i] == ALL) || (selcount[i] == mylist[i]->amt)) { + selchar = '*'; + } else { + selchar = '#'; + } + } else { + selchar = ' '; + } + + sprintf(buf, "%c %c - %s", selchar, useobletters ? mylist[i]->letter : myletters[i], + obname); + + if (mylist[i]->blessknown) { + if (iscursed(mylist[i])) { + setcol(win, C_RED); + } else if (isblessed(mylist[i])) { + setcol(win, C_CYAN); + } + } + getobextrainfo(mylist[i], infobuf); + getobequipinfo(mylist[i], equipbuf); + + mvwprintw(win, *y, 0, "%s%s", buf, infobuf); + + if (mylist[i]->blessknown) { + if (iscursed(mylist[i])) { + unsetcol(win, C_RED); + } else if (isblessed(mylist[i])) { + unsetcol(win, C_CYAN); + } + } + + if (strlen(equipbuf)) { + setcol(win, C_BROWN); + wprintw(win, "%s", equipbuf); + unsetcol(win, C_BROWN); + } + (*y)++; + + } + *counter = i; +} + +object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, ...) { int c,i; object_t *mylist[MAXPILEOBS+1]; char myletters[MAXPILEOBS+1]; @@ -1537,26 +1664,25 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, enum FL int firstob = 0; int nextpage = -1; int lastline = SCREENH-4; - char buf[BUFLEN],buf2[BUFLEN]; int finished; char nextlet = 'a'; int useobletters; //flag_t *f; object_t *ammo; - enum OBCLASS wantoc[MAXCANDIDATES]; - va_list classes; - int nclasses; + enum FLAG wantflag[MAXCANDIDATES]; + va_list flags; + int nwantflags; // construct list of valid obclasses - va_start(classes, withflag); - nclasses = 0; - wantoc[nclasses] = va_arg(classes, enum OBCLASS); - while (wantoc[nclasses] != OC_NULL) { - nclasses++; - wantoc[nclasses] = va_arg(classes, enum OBCLASS); + va_start(flags, opts); + nwantflags = 0; + wantflag[nwantflags] = va_arg(flags, enum FLAG); + while (wantflag[nwantflags] != F_NONE) { + nwantflags++; + wantflag[nwantflags] = va_arg(flags, enum FLAG); } - va_end(classes); - dblog("nclasses is %d",nclasses); + va_end(flags); + dblog("nwantflags is %d",nwantflags); // remember player's current ammo if (op->owner) { @@ -1592,19 +1718,23 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, enum FL while (sortorder[c] != OC_NULL) { object_t *o; //if (!wantoc || (sortorder[c] == wantoc->id)) { - if (!nclasses || contains(wantoc, nclasses, sortorder[c])) { - // add all objects of this class - for (o = op->first ; o ; o = o->next) { - if (o->type->obclass->id == sortorder[c]) { - int ok; - // can we include this object? - ok = B_TRUE; + //if (!nwantflags || contains(wantflag, nwantflags, sortorder[c])) { + // add all objects of this class + for (o = op->first ; o ; o = o->next) { + if (o->type->obclass->id == sortorder[c]) { + int ok; + int n; + // can we include this object? + ok = B_TRUE; - if (withflag != F_NONE) { - if (!hasflag(o->flags, withflag)) { - ok = B_FALSE; - } + // check for wanted flags + for (n = 0; n < nwantflags; n++) { + if (!hasflag(o->flags, wantflag[n])) { + ok = B_FALSE; + break; } + } + if (ok) { if (opts & AO_SPECIFIED) { int n; int found = B_FALSE; @@ -1619,16 +1749,20 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, enum FL ok = B_FALSE; } } - ok = obmatchescondition(o, opts); - if (ok) { - mylist[i] = o; - myletters[i] = nextlet; - if (++nextlet > 'z') nextlet = 'A'; - i++; - } } - } - } + + if (ok) { + ok = obmatchescondition(o, opts); + } + + if (ok) { + mylist[i] = o; + myletters[i] = nextlet; + if (++nextlet > 'z') nextlet = 'A'; + i++; + } + } // end if ob matches sortorder + } // end for each ob c++; } mylist[i] = NULL; @@ -1639,35 +1773,15 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, enum FL finished = B_FALSE; strcpy(numstring, ""); while (!finished) { - int lastclass = OC_NULL; int y; int ch; - cls(); // list the objects y = 2; - for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) { - if (mylist[i]->type->obclass->id != lastclass) { - // print class heading - mvwprintw(mainwin, y, 0, "%s", mylist[i]->type->obclass->name); - - lastclass = mylist[i]->type->obclass->id; - - y++; - } - // print object name - getobname(mylist[i], buf,mylist[i]->amt); - sprintf(buf2, " %c - %s", useobletters ? mylist[i]->letter : myletters[i], - buf); - - getobextrainfo(mylist[i], buf); - - mvwprintw(mainwin, y, 0, "%s%s", buf2, buf); - y++; - } + listobs(mainwin, mylist, NULL, NULL, firstob, &i, lastline, &y, useobletters ? NULL : myletters ); if (mylist[i] == NULL) { nextpage = -1; @@ -1774,13 +1888,11 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { int firstob = 0; int nextpage = -1; int lastline = SCREENH-4; - char buf[BUFLEN],buf2[BUFLEN]; int finished; int count = ALL; char nextlet = 'a'; int useobletters; objectclass_t *wantoc = NULL; - flag_t *f; object_t *ammo; // remember player's current ammo @@ -1849,96 +1961,16 @@ int askobjectmulti(obpile_t *op, char *prompt, long opts) { finished = B_FALSE; strcpy(numstring, ""); while (!finished) { - int lastclass = OC_NULL; int y; int ch; - cls(); // list the objects y = 2; - for (i = firstob ; (mylist[i] != NULL) && (y < lastline); i++) { - char selchar; - if (mylist[i]->type->obclass->id != lastclass) { - // print class heading - mvwprintw(mainwin, y, 0, "%s", mylist[i]->type->obclass->name); + listobs(mainwin, mylist, selected, selcount, firstob, &i, lastline, &y, useobletters ? NULL : myletters ); - lastclass = mylist[i]->type->obclass->id; - - y++; - } - // print object name - getobname(mylist[i], buf,mylist[i]->amt); - if (selected[i]) { - if ((selcount[i] == ALL) || (selcount[i] == mylist[i]->amt)) { - selchar = '*'; - } else { - selchar = '#'; - } - } else { - selchar = ' '; - } - sprintf(buf2, "%c %c - %s", - selchar, - useobletters ? mylist[i]->letter : myletters[i], - buf); - - // charges - f = hasflag(mylist[i]->flags, F_CHARGES); - if (f && f->known) { - if (!hasflag(mylist[i]->flags, F_DONTSHOWCHARGES)) { - char chargestr[BUFLEN]; - sprintf(chargestr, " (%d charges left)",f->val[0]); - strcat(buf2, chargestr); - } - } - - f = hasflag(mylist[i]->flags, F_ACTIVATED); - if (f) { - strcat(buf2, " [activated]"); - } - // condition - /* - f = hasflag(mylist[i]->flags, F_OBHP); - if (f) { - char condname[BUFLEN]; - getobconditionname(mylist[i], condname); - if (strlen(condname) > 0) { - strcat(buf2, " ["); - strcat(buf2, condname); - strcat(buf2, "]"); - } - } - */ - - - f = hasflag(mylist[i]->flags,F_EQUIPPED); - if (f) { - if (f->val[0] == BP_WEAPON) { - if (hasflag(mylist[i]->flags, F_TWOHANDED)) { - strcat(buf2, " (two-handed weapon)"); - } else { - strcat(buf2, " (weapon)"); - } - } else { - strcat(buf2, " ("); - strcat(buf2, getbodypartequipname(f->val[0])); - strcat(buf2, " "); - strcat(buf2, getbodypartname(f->val[0])); - strcat(buf2, ")"); - } - } - - // ammo? - if (ammo && (ammo == mylist[i])) { - strcat(buf2, " (current ammo)"); - } - - mvwprintw(mainwin, y, 0, buf2); - y++; - } if (mylist[i] == NULL) { nextpage = -1; } else { @@ -2100,6 +2132,16 @@ int chartodir(char c) { return D_NONE; } +char checkforkey(void) { + char ch; + nodelay(mainwin, TRUE); + ch = getch(); + nodelay(mainwin, FALSE); + if (ch == ERR) ch = '\0'; + + return ch; +} + void clearmsg(void) { real_clearmsg(B_FALSE); } @@ -2162,6 +2204,10 @@ void updateviewfor(cell_t *cell) { void drawscreen(void) { + if (gamemode < GM_GAMESTARTED) { + return; + } + if (statdirty) { drawstatus(); wrefresh(statwin); @@ -2289,7 +2335,7 @@ void describeob(object_t *o) { } } - // other extra damage? + // other extra damage or effects? f = hasflag(o->flags, F_ONFIRE); if (f) { mvwprintw(mainwin, y, 0, " It also inflicts extra burning damage."); @@ -2311,22 +2357,33 @@ void describeob(object_t *o) { mvwprintw(mainwin, y, 0, "It has %s accuracy.",getaccuracyname(acc)); y++; } + f = hasflag(o->flags, F_DISARMATTACK); + if (f) { + mvwprintw(mainwin, y, 0, "A skilled weilder can disarm opponents with it."); + y++; + } + f = hasflag(o->flags, F_TRIPATTACK); + if (f) { + mvwprintw(mainwin, y, 0, "A skilled weilder can trip opponents with it."); + y++; + } } // damage if (isarmour(o)) { - f = hasflag(o->flags, F_ARMOURRATING); - if (f) { - mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o)); - y++; - } f = hasflag(o->flags, F_GOESON); if (f) { mvwprintw(mainwin, y, 0, "It is worn %s your %s.",getbodypartequipname(f->val[0]), getbodypartname(f->val[0])); y++; } + f = hasflag(o->flags, F_ARMOURRATING); + if (f) { + mvwprintw(mainwin, y, 0, "It has an Armour Rating of %d.",f->val[0] + getobbonus(o)); + y++; + } } + f = hasflag(o->flags, F_THROWMISSILE); if (f) { if (lfhasflag(player, F_EXTRAINFO) || lfhasflag(player, F_OMNIPOTENT)) { @@ -2440,8 +2497,13 @@ void describeob(object_t *o) { // conferred intrinsics switch (f->val[0]) { + int amt; + case F_SHIELDPENALTY: + amt = adjustshieldpenalty(player, f->val[1]); + mvwprintw(mainwin, y, 0, "%s lowers your attack accuracy by %d%%.", buf, amt); y++; + break; case F_ATTRMOD: - mvwprintw(mainwin, y, 0, "%s %s your %s.", buf, (f->val[2] > 0) ? "increases" : "descreases", getattrname(f->val[1])); y++; + mvwprintw(mainwin, y, 0, "%s %s your %s.", buf, (f->val[2] > 0) ? "increases" : "decreases", getattrname(f->val[1])); y++; break; case F_ATTRSET: mvwprintw(mainwin, y, 0, "%s modifies your %s.", buf, getattrname(f->val[1])); y++; @@ -2449,6 +2511,9 @@ void describeob(object_t *o) { case F_BLIND: mvwprintw(mainwin, y, 0, "%s prevents you from seeing.", buf); y++; break; + case F_CONTROL: + mvwprintw(mainwin, y, 0, "%s lets you control teleportation and polymorphic effects.", buf); y++; + break; case F_DETECTLIFE: mvwprintw(mainwin, y, 0, "%s will detect nearby lifeforms.", buf); y++; break; @@ -2577,6 +2642,9 @@ void describeob(object_t *o) { case F_SLOWMOVE: mvwprintw(mainwin, y, 0, "%s will slow down your movement.", buf); y++; break; + case F_WINDSHIELD: + mvwprintw(mainwin, y, 0, "%s will surround you with a cyclonic shield.", buf); y++; + break; case F_TIRED: mvwprintw(mainwin, y, 0, "%s make you tired.", buf); y++; break; @@ -2849,7 +2917,7 @@ void docomms(void) { case 'c': msg("You say \"Come here!\" to %s.",lfname); // find adjacent cell - c = getrandomadjcell(player->cell, WE_NOTSOLID); + c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND); if (c) { aigoto(lf, c, AI_FOLLOWTIME); } @@ -3233,9 +3301,8 @@ void doknowledgelist(void) { int c; cls(); - mvwprintw(mainwin, y, 0, "Current Knowledge"); - y++; - y++; + mvwprintw(mainwin, 0, 0, "Current Knowledge"); + y = 2; for (c = 0; sortorder[c] != OC_NULL ; c++) { int first = B_TRUE; for (k = knowledge ; k ; k = k->next) { @@ -3255,11 +3322,13 @@ void doknowledgelist(void) { numfound++; - if (y >= (SCREENH-1)) { - mvwprintw(mainwin, y, 0, MORESTRING); + if (y >= (SCREENH-3)) { + mvwprintw(mainwin, (SCREENH-2), 0, MORESTRING); wrefresh(mainwin); getch(); cls(); + mvwprintw(mainwin, 0, 0, "Current Knowledge"); + y = 2; } } } @@ -3397,8 +3466,7 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2) deactspell[nposs] = B_FALSE; // default power = getspellpower(lf, ot->id); if (power > 0) { - - if (lfhasflagval(lf, F_BOOSTSPELL, ot->id, NA, NA, NULL)) { + if (hasactivespell(lf, ot->id)) { cost = 0; mpcost[nposs] = 0; strcpy(mpdesc[nposs], "(Deactivate, at will)"); @@ -3406,8 +3474,16 @@ void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2) } else { int ongoing = B_FALSE; if (hasflag(ot->flags, F_ONGOING)) ongoing = B_TRUE; - sprintf(mpdesc[nposs], "(%d MP%s)", mpcost[nposs], - ongoing ? ", ongoing" : ""); + + if (hasflag(ot->flags, F_VARPOWER)) { + + sprintf(mpdesc[nposs], "(%d-%d MP%s)", mpcost[nposs], + mpcost[nposs] * power, + ongoing ? ", ongoing" : ""); + } else { + sprintf(mpdesc[nposs], "(%d MP%s)", mpcost[nposs], + ongoing ? ", ongoing" : ""); + } } if (lf->mp >= mpcost[nposs]) { validspell[nposs] = B_TRUE; @@ -3693,28 +3769,31 @@ void doenter(lifeform_t *lf) { } } -void doexplain(void) { +void doexplain(char *question) { char buf[BUFLEN]; cell_t *where; + int done = B_FALSE; - sprintf(buf, "Select glyph to explain (ESC to cancel):"); - where = askcoords(buf, TT_NONE); - if (!where) { - clearmsg(); - return; - } - - // explain it - if (where->lf && cansee(player, where->lf)) { - showlfstats(where->lf, B_FALSE); - } else { - object_t *o; - // object description - o = gettopobject(where); - if (o) { - getobdesc(o, buf); + while (!done) { + //sprintf(buf, "Select glyph to explain (ESC to cancel):"); + where = askcoords(question, TT_NONE); + if (!where) { + clearmsg(); + return; + } + + // explain it + if (where->lf && cansee(player, where->lf)) { + showlfstats(where->lf, B_FALSE); + } else { + object_t *o; + // object description + o = gettopobject(where); + if (o) { + getobdesc(o, buf); + } + msg("%s", buf); } - msg("%s", buf); } msg("Done."); } @@ -3823,7 +3902,7 @@ void doquaff(obpile_t *op) { // ask which object to quaff if (!liquid) { - liquid = askobjectofclass(op, "Quaff what", NULL, AO_NONE, OC_POTION); + liquid = askobjectwithflag(op, "Quaff what", NULL, AO_NONE, F_DRINKABLE); } if (liquid) { if (canquaff(player, liquid)) { @@ -3924,7 +4003,7 @@ void donextguntarget(void) { cell_t *c; c = player->los[i]; if (c->lf && (c->lf != player) && (c->lf != targ)) { - if (haslof(player, c, LOF_NEED, NULL) && isingunrange(player, c)) { + if (haslof(player->cell, c, LOF_NEED, NULL) && isingunrange(player, c)) { // found one! setguntarget(player, c->lf); done = B_TRUE; @@ -4072,7 +4151,7 @@ void doselguntarget(void) { sprintf(buf, "Aim %s where?",gunname); where = askcoords(buf, TT_MONSTER); if (where) { - if (where->lf && haslof(player, where, LOF_NEED, NULL)) { + if (where->lf && haslof(player->cell, where, LOF_NEED, NULL)) { setguntarget(player, where->lf); } else { setguntarget(player, NULL); @@ -4146,7 +4225,7 @@ void dothrow(obpile_t *op) { if (where) { cell_t *newwhere = NULL; - if (!haslof(player, where, LOF_WALLSTOP, &newwhere)) { + if (!haslof(player->cell, where, LOF_WALLSTOP, &newwhere)) { if (newwhere) { // update destination cell. where = newwhere; @@ -4237,6 +4316,7 @@ int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, // draw a cell which we remember, but can't see +/* void drawunviscell(cell_t *cell, int x, int y) { glyph_t glyph; object_t *o; @@ -4262,6 +4342,7 @@ void drawunviscell(cell_t *cell, int x, int y) { //mvwprintw(gamewin, y, x, "%c", glyph); drawglyph(&glyph, x, y); } +*/ void drawglyph(glyph_t *g, int x, int y) { int col; @@ -4271,11 +4352,14 @@ void drawglyph(glyph_t *g, int x, int y) { unsetcol(gamewin, g->colour); } +/* void drawcell(cell_t *cell, int x, int y) { drawglyph(&cell->type->glyph, x, y); } +*/ // draw a cell that we have LOS to. +/* void drawcellwithcontents(cell_t *cell, int x, int y) { if (cell->lf && cansee(player, cell->lf)) { // lifeform here that we can see glyph_t *gl; @@ -4313,6 +4397,7 @@ void drawcellwithcontents(cell_t *cell, int x, int y) { drawcell(cell, x, y); } } +*/ void drawcursor(void) { // move cursor to player position @@ -4328,33 +4413,38 @@ void drawlevelfor(lifeform_t *lf) { numdraws++; + // turn off cursor + curs_set(0); + + // TODO: draw to buffer here... + // buffer is an array of 'glyph_t's wclear(gamewin); for (y = viewy; y < viewy + viewh; y++) { for (x = viewx; x < viewx + vieww; x++) { cell = getcellat(map, x, y); if (cell) { - void *thing; - char desc[BUFLEN]; - glyph_t glyph; - if (haslos(lf, cell)) { - drawcellwithcontents(cell, x-viewx, y-viewy); + glyph_t glyph,screenglyph; + getcellglyph(&glyph, cell, lf); + //drawglyph(&glyph, x - viewx, y - viewy); + + // only draw if screen char/colour is different + screenglyph.ch = mvwinch(gamewin, y - viewy, x - viewx) & A_CHARTEXT; + if (screenglyph.ch != glyph.ch) { + drawglyph(&glyph, x - viewx, y - viewy); } else { - //drawscannedcell(cell, x-viewx, y-viewy); - switch (isinscanrange(cell, &thing, desc, &glyph)) { - case TT_MONSTER: - case TT_OBJECT: - drawglyph(&glyph, x, y); - break; - default: - if (cell->known) { - drawunviscell(cell, x-viewx, y-viewy); - } - break; + screenglyph.colour = mvwinch(gamewin, y - viewy, x - viewx) & A_COLOR; + if (screenglyph.colour != glyph.colour) { + drawglyph(&glyph, x - viewx, y - viewy); } } + } } } + // turn on cursor + curs_set(1); + // move it to the player's position + wmove(gamewin, lf->y - viewy, lf->x - viewx); } void doheading(WINDOW *win, int *y, int x, char *what) { @@ -4446,8 +4536,12 @@ int drop(object_t *o, int count) { // if object wasn't changed... if (newob->type->id == origid) { if (op->owner) { - if (op->owner->controller == C_PLAYER) { + 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); } } } @@ -5043,7 +5137,7 @@ void handleinput(void) { domsghist(); break; case '/': // explain object - doexplain(); + doexplain("Select glyph to explain (ESC to cancel):"); break; case '\\': // list knowledge doknowledgelist(); @@ -5353,12 +5447,13 @@ void nothinghappens(void) { void drawstatus(void) { char buf[BUFLEN]; char buf2[BUFLEN]; - char mpbuf[BUFLEN]; + //char mpbuf[BUFLEN]; char waitbuf[BUFLEN]; char pname[BUFLEN]; char maxmpstr[BUFLEN]; flag_t *f; - int str,dex,iq,con; + enum ATTRIB a; + int myatt[MAXATTS]; long xpleft; getplayernamefull(pname); @@ -5445,9 +5540,21 @@ void drawstatus(void) { // show certain flags if (lfhasflag(player, F_POISONED)) { - setcol(statwin, C_GREEN); - wprintw(statwin, " Poisoned"); - unsetcol(statwin, C_GREEN); + if (getskill(player, SK_FIRSTAID) >= PR_ADEPT) { + if (poisonthreatenslife(player)) { + setcol(statwin, C_GREEN); + wprintw(statwin, " Poison(bad)"); + unsetcol(statwin, C_GREEN); + } else { + setcol(statwin, C_BROWN); + wprintw(statwin, " Poisoned(mild)"); + unsetcol(statwin, C_BROWN); + } + } else { + setcol(statwin, C_GREEN); + wprintw(statwin, " Poisoned"); + unsetcol(statwin, C_GREEN); + } } //mvwprintw(statwin, 0, 0, buf); @@ -5474,11 +5581,13 @@ void drawstatus(void) { // construct waiting string strcpy(waitbuf, ""); + /* // timespent > 0? if (player->timespent) { sprintf(buf, "busy: %d", player->timespent); strcat(waitbuf, buf); } + */ f = hasflag(player->flags, F_AUTOCMD); @@ -5494,10 +5603,9 @@ void drawstatus(void) { // SECOND LINE - str = getattr(player, A_STR); - dex = getattr(player, A_DEX); - iq = getattr(player, A_IQ); - con = getattr(player, A_CON); + for (a = 0; a < MAXATTS; a++) { + myatt[a] = getattr(player, a); + } //redraw(); if (getmaxmp(player) == player->maxmp) { @@ -5506,24 +5614,47 @@ void drawstatus(void) { sprintf(maxmpstr, "(%d)",player->maxmp); } + + // HP + mvwprintw(statwin, 1, 0, "HP:"); + setcol(statwin, getpctcol(player->hp, player->maxhp)); + wprintw(statwin, "%d",player->hp); + unsetcol(statwin, getpctcol(player->hp, player->maxhp)); + wprintw(statwin, "/%d ",player->maxhp); + + // MP if (getmaxmp(player) > 0) { - sprintf(mpbuf, "%d/%d%s", player->mp, getmaxmp(player), maxmpstr); + wprintw(statwin, "MP:"); + 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 { - strcpy(mpbuf, "-"); + wprintw(statwin, "MP:- "); } - sprintf(buf, "HP:%d/%d MP:%s $:%d AR:%d St:%d%c Dx:%d%c Iq:%d%c Cn:%d%c DLev:%d", - player->hp,player->maxhp, - mpbuf, - countmoney(player), - getarmourrating(player), - str, (str == player->baseatt[A_STR]) ? ' ' : '*', - dex, (dex == player->baseatt[A_DEX]) ? ' ' : '*', - iq, (iq == player->baseatt[A_IQ]) ? ' ' : '*', - con, (con == player->baseatt[A_CON]) ? ' ' : '*', - player->cell->map->depth - ); - mvwprintw(statwin, 1, 0, buf); + sprintf(buf, "$:%d AR:%d ", countmoney(player), getarmourrating(player)); + wprintw(statwin, buf); + + + for (a = 0; a < MAXATTS; a++) { + wprintw(statwin, "%s:", getattrabbrev(a)); + if (myatt[a] == player->baseatt[a]) { + wprintw(statwin, "%d ",myatt[a]); + } else { + if (myatt[a] > player->baseatt[a]) { + setcol(statwin, C_GREEN); + wprintw(statwin, "%d*",myatt[a]); + unsetcol(statwin, C_GREEN); + } else { + setcol(statwin, C_RED); + wprintw(statwin, "%d*",myatt[a]); + unsetcol(statwin, C_RED); + } + } + } + + wprintw(statwin, "DLev:%d", player->cell->map->depth); } void drawmsg(void) { @@ -5730,7 +5861,11 @@ void showlfstats(lifeform_t *lf, int showall) { h = getmaxy(mainwin); // override showall sometimes... - if (isplayer(lf) || isgenius(player)) { + // need 'player == lf' to cope with mind scans + // where we update the player pointer, but don't + // change the target's '->controller' setting (meaning + // that isplayer(target) still returns false). + if (isplayer(lf) || isgenius(player) || (player == lf)) { showall = B_TRUE; } @@ -6013,8 +6148,11 @@ void showlfstats(lifeform_t *lf, int showall) { // no damage sprintf(buf, "N/A"); } - mvwprintw(mainwin, y2, x2, ftext, "Attack Dmg"); - wprintw(mainwin, "%-20s", buf); y2++; + + if (showall) { + mvwprintw(mainwin, y2, x2, ftext, "Attack Dmg"); + wprintw(mainwin, "%-20s", buf); y2++; + } @@ -6513,9 +6651,15 @@ void showlfstats(lifeform_t *lf, int showall) { } } - f = lfhasknownflag(lf, F_ARBOOST); + f = lfhasknownflag(lf, F_MAGICARMOUR); if (f && (f->known)) { - mvwprintw(mainwin, y, 0, "%s %s protected by a magical shield.", you(lf), isplayer(lf) ? "are" : "is"); + mvwprintw(mainwin, y, 0, "%s %s protected by %s %s", you(lf), isplayer(lf) ? "are" : "is", + needan(f->text) ? "an" : "a", f->text); + if (isplayer(lf)) { + wprintw(mainwin, " (+%d AR).",f->val[0]); + } else { + wprintw(mainwin, "."); + } y++; } @@ -6547,6 +6691,11 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, buf); y++; } + f = lfhasknownflag(lf, F_CONTROL); + if (f) { + mvwprintw(mainwin, y, 0, "%s can control teleportation and polymorphic effects.", you(lf)); + y++; + } f = lfhasknownflag(lf, F_DETECTAURAS); if (f) { mvwprintw(mainwin, y, 0, "%s automatically detect blessings or curses.", you(lf)); @@ -6554,7 +6703,8 @@ void showlfstats(lifeform_t *lf, int showall) { } f = lfhasknownflag(lf, F_DETECTLIFE); if (f) { - mvwprintw(mainwin, y, 0, "%s automatically detect nearby lifeforms.", you(lf)); + mvwprintw(mainwin, y, 0, "%s automatically detect %snearby lifeforms.", you(lf), + (f->val[1] == B_TRUE) ? "" : "the size of "); y++; } f = lfhasknownflag(lf, F_DETECTMAGIC); @@ -6635,9 +6785,10 @@ void showlfstats(lifeform_t *lf, int showall) { f = lfhasknownflag(lf, F_POISONED); if (f && (f->known)) { sprintf(buf, "%s %s poisoned.", you(lf), isplayer(lf) ? "are" : "is"); - if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT)) { + if (lfhasflag(lf, F_EXTRAINFO) || lfhasflag(lf, F_OMNIPOTENT) || + (getskill(lf, SK_FIRSTAID) >= PR_ADEPT) ) { char buf2[BUFLEN]; - sprintf(buf2, " [%d left]", f->lifetime); + sprintf(buf2, " [max %d turns left]", f->lifetime); strcat(buf, buf2); } mvwprintw(mainwin, y, 0, buf); @@ -6756,6 +6907,17 @@ void showlfstats(lifeform_t *lf, int showall) { mvwprintw(mainwin, y, 0, "%s %s %s resistant to magic.", you(lf), isplayer(lf) ? "are" : "is", adjective); y++; } + f = lfhasknownflag(lf, F_WINDSHIELD); + if (f) { + mvwprintw(mainwin, y, 0, "%s %s protected from missiles by a cyclonic shield", you(lf), isplayer(lf) ? "are" : "is"); + + if (isplayer(lf)) { + wprintw(mainwin, " (power %d).",roman(f->val[0])); + } else { + wprintw(mainwin, "."); + } + y++; + } f = lfhasknownflag(lf, F_TIRED); if (f) { mvwprintw(mainwin, y, 0, "%s %s tired.", you(lf), isplayer(lf) ? "are" : "is"); diff --git a/io.h b/io.h index 6d2d65a..9a1a912 100644 --- a/io.h +++ b/io.h @@ -14,14 +14,14 @@ int announceobflaggain(object_t *o, flag_t *f); void announceobflagloss(object_t *o, flag_t *f); object_t *askobject(obpile_t *op, char *title, int *count, long opts); object_t *askobjectwithflag(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag); -object_t *askobjectofclass(obpile_t *op, char *title, int *count, long opts, enum OBCLASS obclass); -object_t *doaskobject(obpile_t *op, char *title, int *count, long opts, enum FLAG withflag, ...); +object_t *doaskobject(obpile_t *op, char *title, int *count, long opts, ...); int askobjectmulti(obpile_t *op, char *prompt, long opts); char askchar(char *prompt, char *validchars, char *def, int showchars); cell_t *askcoords(char *prompt, int targettype); char *askstring(char *prompt, char punc, char *retbuf, int retbuflen, char *def); void centre(WINDOW *win, int y, char *format, ... ); int chartodir(char ch); +char checkforkey(void); int cleanupgfx(void); void clearmsg(void); void real_clearmsg(int force); @@ -35,7 +35,7 @@ void docomms(void); void dodrop(obpile_t *op, int wantmulti, obpile_t *dst); void doeat(obpile_t *op); void doenter(lifeform_t *lf); -void doexplain(void); +void doexplain(char *question); void dofinaloblist(obpile_t *op); void dofire(void); void dohelp(void); @@ -63,8 +63,8 @@ int dowear(obpile_t *op); int doweild(obpile_t *op); int downline(int *y, int h, char *heading, char *subheading, char *bottomstring, char *cmdchars, char *retchar); void drawglyph(glyph_t *g, int x, int y); -void drawunviscell(cell_t *cell, int x, int y); -void drawcellwithcontents(cell_t *cell, int x, int y); +//void drawunviscell(cell_t *cell, int x, int y); +//void drawcellwithcontents(cell_t *cell, int x, int y); void drawcursor(void); void drawlevelfor(lifeform_t *lf); void drawmsg(void); @@ -79,6 +79,7 @@ void doheading(WINDOW *win, int *y, int x, char *what); void initgfx(void); void initprompt(prompt_t *p, char *q1); int keycodetokey(int keycode); +void listobs(WINDOW *win, object_t **mylist, int *sellist, int *selcount, int firstob, int *counter, int lastline, int *y, char *myletters); void makespellchoicelist(prompt_t *pr, lifeform_t *lf, char *ques, char *ques2); void more(void); void warn(char *format, ... ); diff --git a/lf.c b/lf.c index 9e3c7b0..af7a0e4 100644 --- a/lf.c +++ b/lf.c @@ -17,6 +17,8 @@ #include "spell.h" #include "text.h" +extern FILE *logfile; + extern map_t *firstmap; extern race_t *firstrace, *lastrace; extern job_t *firstjob, *lastjob; @@ -244,6 +246,12 @@ void adjustdamlf(lifeform_t *lf, int *amt, enum DAMTYPE damtype) { *amt = 0; return; } + + // water normally doesn't hurt. + if ((damtype == DT_WATER) && !isvulnto(lf->flags, damtype)) { + *amt = 0; + return; + } if (lfhasflag(lf, F_INVULNERABLE)) { switch (damtype) { @@ -303,7 +311,7 @@ lifeform_t *makezombie(object_t *o) { lf = addlf(where, r->id, 1); addflag(lf->flags, F_LFSUFFIX, B_TRUE, NA, NA, "zombie"); - addflag(lf->flags, F_GLYPH, NA, NA, NA, "Z"); + addflag(lf->flags, F_GLYPH, C_GREY, NA, NA, "Z"); addflag(lf->flags, F_UNDEAD, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_NOCORPSE, B_TRUE, NA, NA, NULL); addflag(lf->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); @@ -462,7 +470,7 @@ void autotarget(lifeform_t *lf) { if (isdead(targ)) { // clear target ? targ = NULL; - } else if (!haslof(lf, targ->cell, B_FALSE, NULL)) { + } else if (!haslof(lf->cell, targ->cell, B_FALSE, NULL)) { // clear target ? targ = NULL; } else { @@ -798,9 +806,29 @@ int canhear(lifeform_t *lf, cell_t *dest) { // can't hear when dead. if (isdead(lf)) return B_FALSE; - // can't hear on other maps + // can't hear noises from other maps if (lf->cell->map != dest->map) return B_FALSE; + // can't hear if you have a hostile mosnter next to you + // and you're not blind. + // (you're too engrossed in the battle) + if (!isblind(lf)) { + int dir; + int inbattle = B_FALSE; + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c; + c = getcellindir(lf->cell, dir); + if (c && c->lf && areenemies(lf, c->lf)) { + inbattle = B_TRUE; + break; + } + } + if (inbattle) { + return B_FALSE; + } + } + + map = dest->map; x1 = lf->cell->x; @@ -851,6 +879,16 @@ int cannotmove(lifeform_t *lf) { return B_FALSE; } +int canlearn(lifeform_t *lf, enum SKILL skid) { + if (lfhasflagval(lf, F_CANLEARN, skid, NA, NA, NULL)) { + return B_TRUE; + } + if (lfhasflagval(lf, F_CANLEARN, ALL, NA, NA, NULL)) { + return B_TRUE; + } + return B_FALSE; +} + int canpickup(lifeform_t *lf, object_t *o, int amt) { reason = E_OK; @@ -956,6 +994,9 @@ int canrest(lifeform_t *lf) { } int cansee(lifeform_t *viewer, lifeform_t *viewee) { + if (gamemode < GM_GAMESTARTED) { + return B_TRUE; + } // viewer asleep? if (lfhasflag(viewer, F_ASLEEP)) { return B_FALSE; @@ -1159,6 +1200,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar int cost; flag_t *f,*willflag; int power; + objecttype_t *sp; // check whether we _can_ cast it. // do we have this spell/ability? // enough mp? etc @@ -1182,16 +1224,37 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar willflag = lfhasflagval(lf, F_CANWILL, sid, NA, NA, NULL); + + power = getspellpower(lf, sid); + + sp = findot(sid); + + if (isplayer(lf) && (power > 1) && hasflag(sp->flags, F_VARPOWER)) { + if (!hasactivespell(lf, sp->id)) { + int max; + char buf[BUFLEN]; + int i; + char ch; + // ask what power + max = power; + sprintf(buf, "Cast %s at what power level?", sp->name); + initprompt(&prompt, buf); + for (i = 1; i <= max; i++) { + sprintf(buf, "Power %s (%d MP)", roman(i), getmpcost(lf, sid) * i); + addchoice(&prompt, '0' + i, buf, buf, NULL); + } + ch = getchoice(&prompt); + power = ch - '0'; + } + } + // take time taketime(lf, getspellspeed(lf)); // lose mp - lf->mp -= cost; + losemp(lf, cost); - - power = getspellpower(lf, sid); - - if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 20 + getspellpower(lf, sid), 0)) { + if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 20 + power, 0)) { if (power > 1) { // half strength power /= 2; @@ -1217,7 +1280,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar // cast the spell addflag(lf->flags, F_CASTINGSPELL, sid, NA, NA, NULL); - rv = dospelleffects(lf, sid, getspellpower(lf, sid), targlf, targob, targcell, B_UNCURSED, NULL); + rv = dospelleffects(lf, sid, power, targlf, targob, targcell, B_UNCURSED, NULL); f = lfhasflag(lf, F_CASTINGSPELL); if (f) { killflag(f); @@ -1250,6 +1313,21 @@ void die(lifeform_t *lf) { //int dropobs = B_TRUE; int vaporised = B_FALSE; + if (useringofmiracles(lf, 3)) { + int hunger; + // return to full health + lf->hp = lf->maxhp; + // cure poison + killflagsofid(lf->flags, F_POISONED); + // cure starvation + hunger = gethungerval(lf); + if (hunger > 0) { + modhunger(lf, -hunger); + } + return; + } + + if (isplayer(lf) && hasjob(lf, J_GOD)) { char ch; msg("You die..."); more(); @@ -1261,6 +1339,16 @@ void die(lifeform_t *lf) { } } + // revert to your original form first. + if (lfhasflag(lf, F_POLYMORPHED)) { + if (lfhasflag(lf, F_ORIGRACE)) { + abilityeffects(lf, OT_A_POLYREVERT, lf->cell, lf, NULL); + // ... but you're still dead + lf->hp = 0; + } + } + + lf->alive = B_FALSE; if (isplayer(lf)) { // force screen redraw so you see your hp = 0 @@ -1507,6 +1595,31 @@ void dumpxp(void) { } } +void dumpmonsters(void) { + int i; + race_t *r; + flag_t *f; + dblog("Start monster dump"); + dblog("------------------\n"); + // NOTE: this code copied from getrandomrace(), which is used by addmonster(). + for (i = 1; i <= 25; i++) { + int min,max; + fprintf(logfile, "Dlev %d: ",i); + getrarity(i, &min, &max, 5); + for (r = firstrace ; r; r = r->next) { + int rarity = 0; + f = hasflag(r->flags, F_RARITY); + if (f) { + rarity = f->val[1]; + } + if ((rarity >= min) && (rarity <= max)) { + fprintf(logfile, "%s, ", r->name); + } + } + fprintf(logfile, "\n"); + } +} + int eat(lifeform_t *lf, object_t *o) { char lfname[BUFLEN]; char obname[BUFLEN]; @@ -1605,10 +1718,15 @@ int eat(lifeform_t *lf, object_t *o) { // change hunger modhunger(lf, -nutrition); - // special case + // special cases if (hasflagval(o->flags, F_CORPSEOF, R_GLOWBUG, NA, NA, NULL)) { addtempflag(lf->flags, F_PRODUCESLIGHT, B_TRUE, NA, NA, NULL, 30); } + if (hasflagval(o->flags, F_CORPSEOF, R_NEWT, NA, NA, NULL)) { + // think "eye of newt" + gainmp(lf, 2); + } + // special case for bananas if (o->type->id == OT_BANANA) { @@ -1689,6 +1807,10 @@ void enhanceskills(lifeform_t *lf) { int moretraining = B_FALSE; int newskillcost = 1; + if (isplayer(lf)) { + statdirty = B_TRUE; + } + // increase str/int etc if we can f = lfhasflag(lf, F_STATGAINREADY); if (f) { @@ -1737,6 +1859,7 @@ void enhanceskills(lifeform_t *lf) { char eorl = 'e'; int skillstoenhance = 0; int skillstolearn = 0; + int done = B_FALSE; skillstoenhance = 0; for (f = lf->flags->first ; f ; f = f->next) { @@ -1747,93 +1870,99 @@ void enhanceskills(lifeform_t *lf) { skillstolearn = 0; for (sk = firstskill ; sk ; sk = sk->next) { - // TODO: && canlearn(player, sk->id) - if (!getskill(player, sk->id)) { + if (!getskill(player, sk->id) && canlearn(player, sk->id)) { skillstolearn++; } } - if (skillstolearn && (lf->skillpoints >= newskillcost)) { - if (skillstoenhance) { - eorl = askchar("Enhance your current skills or Learn a new one?","el","e", B_TRUE); - } else { - ch = askchar("Learn a new skill?","yn","y", B_TRUE); - if (ch == 'y') eorl = 'l'; + while (!done && lf->skillpoints && (skillstolearn || skillstoenhance)) { + if (skillstolearn && (lf->skillpoints >= newskillcost)) { + if (skillstoenhance) { + char buf[BUFLEN]; + sprintf(buf, "Enhance existing skills or Learn a new one (%d points left)?",lf->skillpoints); + eorl = askchar(buf,"eln","e", B_TRUE); + } else { + ch = askchar("Learn a new skill?","yn","y", B_TRUE); + if (ch == 'y') eorl = 'l'; + else eorl = 'n'; + } + } else if (skillstoenhance) { + ch = askchar("Enhance your current skills?","yn","y", B_TRUE); + if (ch == 'y') eorl = 'e'; else eorl = 'n'; + } else { + eorl = 'n'; } - } else if (skillstoenhance) { - ch = askchar("Enhance your current skills?","yn","y", B_TRUE); - if (ch == 'y') eorl = 'e'; - else eorl = 'n'; - } else { - eorl = 'n'; - } - if (eorl == 'e') { - // enhance an existing skill + if (eorl == 'e') { + // enhance an existing skill - // any skills to get? - if (skillstoenhance) { - char ques[BUFLEN]; - sprintf(ques, "Which skill will you enhance (%d point%s left)?", lf->skillpoints, - (lf->skillpoints == 1) ? "" : "s"); - initprompt(&prompt, ques); + // any skills to get? + if (skillstoenhance) { + char ques[BUFLEN]; + sprintf(ques, "Which skill will you enhance (%d point%s left)?", lf->skillpoints, + (lf->skillpoints == 1) ? "" : "s"); + initprompt(&prompt, ques); - ch = 'a'; - for (f = lf->flags->first ; f ; f = f->next) { - if ((f->id == F_HASSKILL) && (f->val[1] != PR_MASTER)) { - char buf[BUFLEN]; - sprintf(buf, "%s (%s -> %s)", getskillname(f->val[0]), - getskilllevelname(f->val[1]), getskilllevelname(f->val[1] + 1)); - addchoice(&prompt, ch++, buf, buf, f); + ch = 'a'; + for (f = lf->flags->first ; f ; f = f->next) { + if ((f->id == F_HASSKILL) && (f->val[1] != PR_MASTER)) { + char buf[BUFLEN]; + sprintf(buf, "%s (%s -> %s)", getskillname(f->val[0]), + getskilllevelname(f->val[1]), getskilllevelname(f->val[1] + 1)); + addchoice(&prompt, ch++, buf, buf, f); + } + } + addchoice(&prompt, '-', "None", "None", NULL); + getchoice(&prompt); + f = (flag_t *)prompt.result; + if (f) { + whichsk = f->val[0]; + giveskill(lf, whichsk); + lf->skillpoints--; + } + } else { + msg("You have already mastered all your current skills."); + } + } else if (eorl == 'l') { + // learn a new skill + + // enough points? + if (player->skillpoints < newskillcost) { + msg("You need at least %d skill points to learn a new skill.", newskillcost); + } else { + + if (skillstolearn) { + char ques[BUFLEN]; + sprintf(ques, "Which new skill will you learn (%d points left)?", player->skillpoints); + initprompt(&prompt, ques); + + ch = 'a'; + for (sk = firstskill ; sk ; sk = sk->next) { + // TODO: && canlearn(player, sk->id) + if (!getskill(player, sk->id)) { + char buf[BUFLEN]; + sprintf(buf, "%s (%s)", getskillname(sk->id), getskilldesc(sk->id)); + addchoice(&prompt, ch++, buf, buf, sk); + } + } + addchoice(&prompt, '-', "None", "None", NULL); + getchoice(&prompt); + sk = (skill_t *)prompt.result; + if (sk) { + giveskill(player, sk->id); + player->skillpoints -= newskillcost; + } + } else { + msg("There is nothing more that you can learn."); } } - addchoice(&prompt, '-', "None", "None", NULL); - getchoice(&prompt); - f = (flag_t *)prompt.result; - if (f) { - whichsk = f->val[0]; - giveskill(lf, whichsk); - lf->skillpoints--; - } - } else { - msg("You have already mastered all your current skills."); - } - } else if (eorl == 'l') { - // learn a new skill - - // enough points? - if (player->skillpoints < newskillcost) { - msg("You need at least %d skill points to learn a new skill.", newskillcost); - return; - } - - if (skillstolearn) { - char ques[BUFLEN]; - sprintf(ques, "Which new skill will you learn (%d points left)?", player->skillpoints); - initprompt(&prompt, ques); - - ch = 'a'; - for (sk = firstskill ; sk ; sk = sk->next) { - // TODO: && canlearn(player, sk->id) - if (!getskill(player, sk->id)) { - char buf[BUFLEN]; - sprintf(buf, "%s (%s)", getskillname(sk->id), getskilldesc(sk->id)); - addchoice(&prompt, ch++, buf, buf, sk); - } - } - addchoice(&prompt, '-', "None", "None", NULL); - getchoice(&prompt); - sk = (skill_t *)prompt.result; - if (sk) { - giveskill(player, sk->id); - player->skillpoints -= newskillcost; - } - } else { - msg("There is nothing more that you can learn."); - } - } // end enhance/learnnew + } else if (eorl == 'n') { + done = B_TRUE; + } // end enhance/learnnew + } // whiel skillstolearn || skillstoenhance + statdirty = B_TRUE; } else { enum SKILL poss[MAXSKILLS]; int nposs = 0; @@ -1850,6 +1979,7 @@ void enhanceskills(lifeform_t *lf) { giveskill(lf, poss[sel]); lf->skillpoints--; } // end if isplayer + } @@ -1863,6 +1993,23 @@ object_t *eyesshaded(lifeform_t *lf) { return NULL; } +int fall(lifeform_t *lf, int announce) { + char lfname[BUFLEN]; + getlfname(lf,lfname); + + if (lfhasflag(lf, F_STABILITY)) { + return B_TRUE; + } + if (announce) { + if (isplayer(lf) || cansee(player, lf)) { + msg("%s fall%s to the ground.",lfname, isplayer(lf) ? "" : "s"); + } + } + taketime(lf, getactspeed(lf)*2); + + loseconcentration(lf); + return B_FALSE; +} void fightback(lifeform_t *lf, lifeform_t *attacker) { // respond to damage @@ -2083,6 +2230,11 @@ int freezelf(lifeform_t *freezee, lifeform_t *freezer, int howlong) { void gainhp(lifeform_t *lf, int amt) { int gained = B_FALSE; int maxed = B_FALSE; + + if (isplayer(lf)) { + statdirty = B_TRUE; + } + if (lf->hp < lf->maxhp) { lf->hp += amt; gained = B_TRUE; @@ -2108,6 +2260,7 @@ void gainlevel(lifeform_t *lf) { float hpratio,mpratio; if (isplayer(lf)) { + statdirty = B_TRUE; drawstatus(); wrefresh(statwin); } @@ -2164,6 +2317,10 @@ void gainmp(lifeform_t *lf, int amt) { int maxed = B_FALSE; int max; + if (isplayer(lf)) { + statdirty = B_TRUE; + } + max = getmaxmp(lf); // magic resistance means you can't regenerate mana! @@ -2192,7 +2349,6 @@ void gainmp(lifeform_t *lf, int amt) { } void gainxp(lifeform_t *lf, long amt) { - if (isplayer(lf)) { statdirty = B_TRUE; } @@ -2282,7 +2438,7 @@ int getarmourrating(lifeform_t *lf) { if (f->id == F_ARMOURRATING) { ar += f->val[0]; } - if (f->id == F_ARBOOST) { + if (f->id == F_MAGICARMOUR) { ar += f->val[0]; } if (f->id == F_PHALANX) { @@ -2308,11 +2464,38 @@ int getarmourrating(lifeform_t *lf) { if (hasflag(o->flags, F_EQUIPPED)) { f = hasflag(o->flags, F_ARMOURRATING); if (f) { - int thisar; - float pct; + float thisar; - pct = getobhppct(o); - thisar = pctof(pct, f->val[0]); + thisar = f->val[0]; + + // adjust for skill + if (hasflag(o->flags, F_SHIELD)) { + switch (getskill(lf, SK_SHIELDS)) { + case PR_INEPT: + thisar *= 0.5; + break; + case PR_NOVICE: + break; + case PR_BEGINNER: + thisar *= 1.2; + break; + case PR_ADEPT: + thisar *= 1.4; + break; + case PR_SKILLED: + thisar *= 1.6; + break; + case PR_EXPERT: + thisar *= 1.8; + break; + case PR_MASTER: + thisar *= 2; + break; + } + } + + // adjust for condition + thisar = pctof(getobhppct(o), thisar); ar += thisar; @@ -2719,6 +2902,8 @@ job_t *getjob(lifeform_t *lf) { int getlfaccuracy(lifeform_t *lf) { obpile_t *op = NULL; object_t *wep; + flag_t *f; + int acc = 0; // get weapon wep = getweapon(lf); @@ -2739,6 +2924,12 @@ int getlfaccuracy(lifeform_t *lf) { if (op) killobpile(op); + for (f = lf->flags->first ;f ; f = f->next) { + if (f->id == F_SHIELDPENALTY) { + acc -= adjustshieldpenalty(lf, f->val[0]); + } + } + // modify for weilder's level acc += (lf->level * 2); @@ -2753,7 +2944,7 @@ int getlfaccuracy(lifeform_t *lf) { // modify for nausea if (lfhasflag(lf, F_NAUSEATED)) { - acc -= 20; + acc -= 25; } if (acc < 0) acc = 0; @@ -3107,7 +3298,7 @@ char *real_getlfname(lifeform_t *lf, char *buf, int usevis) { jobstring[1] = tolower(jobstring[1]); } - if (lf == player) { + if (isplayer(lf)) { sprintf(buf, "you"); } else { //if (isblind(player)) { @@ -3145,7 +3336,7 @@ char *getlfnamea(lifeform_t *lf, char *buf) { } char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis) { - if (lf == player) { + if (isplayer(lf)) { sprintf(buf, "you"); } else { char buf2[BUFLEN]; @@ -3272,6 +3463,7 @@ object_t *getrandomarmour(lifeform_t *lf) { } } + if (anyfound == B_FALSE) return NULL; // now figure out chances of each one getting hit @@ -3303,7 +3495,7 @@ int getrandommonlevel(int depth) { } */ -race_t *getrandomrace(map_t *map) { +race_t *getrandomrace(map_t *map, int forcedepth) { //int rarity; race_t *r; race_t *poss[MAXRANDOMLFCANDIDATES]; @@ -3314,10 +3506,14 @@ race_t *getrandomrace(map_t *map) { int raritymin,raritymax; // determine rarity of lf to generate - if (map) { - depth = map->depth; + if (forcedepth > 0) { + depth = forcedepth; } else { - depth = rnd(1,MAXDEPTH); + if (map) { + depth = map->depth; + } else { + depth = rnd(1,MAXDEPTH); + } } getrarity(depth, &raritymin, &raritymax, 5); @@ -3916,8 +4112,9 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) { if (flagsfound && (flagsknown == flagsfound)) { makeknown(o->type->id); // in some cases, identify the object fully + // (ie. make +xxx bonuses known too) if (isplayer(lf)) { - if (o->type->id == OT_RING_WOUNDING) { + if (hasflag(o->flags, F_IDWHENUSED)) { identify(o); } } @@ -3926,7 +4123,7 @@ void giveobflags(lifeform_t *lf, object_t *o, enum FLAG whattype) { int giveskill(lifeform_t *lf, enum SKILL id) { - flag_t *f; + flag_t *f, *newf; skill_t *sk; sk = findskill(id); @@ -3950,16 +4147,35 @@ int giveskill(lifeform_t *lf, enum SKILL id) { msg("You have learned the %s %s skill!", getskilllevelname(PR_NOVICE), getskillname(sk->id)); } - // special effects... + // special effects for gaining a skill. + + // there aren't REALLY "from job", but mark them as such anyway, so that + // they are invalidated if we get polymorphed. + + // NOTE: this WILL be a problem if i ever add code to allow change of jobs! if (id == SK_RESEARCH) { - addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL); + newf = addflag(lf->flags, F_CANWILL, OT_A_INSPECT, NA, NA, NULL); + newf->lifetime = FROMJOB; } else if (id == SK_ATHLETICS) { - addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); + newf = addflag(lf->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); + newf->lifetime = FROMJOB; } } - if (id == SK_TECHUSAGE) { + + // special effects based on skill level + if (id == SK_LISTEN) { + if (f->val[1] == PR_BEGINNER) { + msg("You can now gauge the distance of sounds."); + } else if (f->val[1] == PR_ADEPT) { + msg("You can now determine the direction sounds are coming from."); + } else if (f->val[1] == PR_EXPERT) { + msg("You can now recognise monsters based on sound."); + } else if (f->val[1] == PR_MASTER) { + msg("You can now accurately locate monsters based on sound."); + } + } else if (id == SK_TECHUSAGE) { objecttype_t *ot; // automatically make known all tech <= our skill level for (ot = objecttype ; ot ; ot = ot->next) { @@ -4417,8 +4633,13 @@ int hasbp(lifeform_t *lf, enum BODYPART bp) { return B_TRUE; } +flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid) { + return lfhasflagval(lf, F_BOOSTSPELL, sid, NA, NA, NULL); +} + // got line of fire to dest? if lof is blocked, return last cell in 'newdest' -int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) { +//int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) { +int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest) { int numpixels; int i; int x1,y1,x2,y2; @@ -4426,20 +4647,20 @@ int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newd cell_t *retcell[MAXRETCELLS]; reason = E_OK; - if (newdest) *newdest = viewer->cell; + if (newdest) *newdest = src; - if (!viewer) return B_FALSE; - if (!viewer->cell) return B_FALSE; + //if (!viewer) return B_FALSE; + if (!src) return B_FALSE; - if (viewer->cell->map != dest->map) { + if (src->map != dest->map) { reason = E_NOLOS; return B_FALSE; } map = dest->map; - x1 = viewer->cell->x; - y1 = viewer->cell->y; + x1 = src->x; + y1 = src->y; x2 = dest->x; y2 = dest->y; @@ -4667,13 +4888,14 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "a digital watch"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed scrolls of create monster"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 blessed potions of experience"); - addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ring of invulnerability"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "ring of miracles"); addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_DEATH, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_TRANSLOCATION, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_DIVINATION, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SS_SUMMONING, PR_MASTER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_RESEARCH, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, ALL, NA, NA, NULL); // gods may use all abilities and cast any spell at will for (i = SS_NONE+1; i < SS_LAST; i++) { if ((i == SS_ABILITY) || (i == SS_DIVINE)) { @@ -4697,6 +4919,8 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, ALL, NA, NA, NULL); addjob(J_ALLOMANCER, "Allomancer"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "1 gold coins"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "club"); @@ -4712,6 +4936,13 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_SS_ALLOMANCY, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LOCKPICKING, PR_NOVICE, NA, NULL); mayusespellschool(lastjob->flags, SS_ALLOMANCY, F_CANCAST); + addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, 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); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); // TODO skill: court knowledge ?? // TODO skill: bartering 2 addjob(J_BARBARIAN, "Barbarian"); @@ -4728,6 +4959,17 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LOCKPICKING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STEALTH, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_AXES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_CLUBS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LONGBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); addjob(J_COMMANDO, "Commando"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "combat knife"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "revolver"); @@ -4746,6 +4988,14 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); addflag(lastjob->flags, F_STARTATT, A_CON, CN_HEALTHY, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_ADEPT, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_FIRSTAID, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_BACKSTAB, 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_STEALTH, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TECHUSAGE, 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_PLUMBER, "Plumber"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spanner"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "10 gold coins"); @@ -4756,6 +5006,11 @@ void initjobs(void) { addflag(lastjob->flags, F_EVASION, 30, NA, NA, NULL); addflag(lastjob->flags, F_OBESE, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SPELLCASTING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_ICE, NA, NA, NULL); addjob(J_PRINCE, "Prince"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "blessed ornamental sword"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "100 gold coins"); @@ -4765,10 +5020,19 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "silk shirt"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "riding trousers"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather boots"); + addflag(lastjob->flags, F_STARTSKILL, SK_SHIELDS, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_SHORTBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_LONGBLADES, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_ATHLETICS, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_MAGITEMUSAGE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_RESEARCH, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); addjob(J_WIZARD, "Wizard"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "knife"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "robe"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "2 potions of magic"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 potions of experience"); addflag(lastjob->flags, F_CANCAST, OT_S_MANASPIKE, NA, NA, NULL); /* @@ -4796,7 +5060,23 @@ void initjobs(void) { addflag(lastjob->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_RESEARCH, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_SPELLCASTING, PR_NOVICE, NA, NULL); - // TODO skill: magic knowledge + addflag(lastjob->flags, F_STARTSKILL, SK_MAGITEMUSAGE, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_LISTEN, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_MAGITEMUSAGE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SHORTBLADES, 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); + addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_FIRE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_ICE, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_GRAVITY, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_MODIFICATION, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_SUMMONING, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_SS_WILD, NA, NA, NULL); + // for monster wizards only: addflag(lastjob->flags, F_IFMONSTER, NA, NA, NA, NULL); addflag(lastjob->flags, F_IFPCT, 50, NA, NA, NULL); @@ -4914,7 +5194,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, DX_SUPERSONIC, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, CN_HARDY, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 9, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); @@ -5117,7 +5397,7 @@ void initrace(void) { addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, NULL); addflag(lastrace->flags, F_HITDICE, 6, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); @@ -5142,7 +5422,7 @@ void initrace(void) { addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "gnoll corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addflag(lastrace->flags, F_HITDICE, 10, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); @@ -5241,7 +5521,7 @@ void initrace(void) { lastrace->baseid = R_GOBLIN; addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "goblin corpse"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 68, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 5, 6, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); @@ -5731,6 +6011,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); addrace(R_ANT, "giant worker ant", 4, 'a', C_BROWN, MT_FLESH); lastrace->baseid = R_ANT; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL); @@ -5751,6 +6032,7 @@ void initrace(void) { addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); addrace(R_ANTS, "giant soldier ant", 5, 'a', C_BROWN, MT_FLESH); lastrace->baseid = R_ANT; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL); @@ -5863,7 +6145,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, 1, 4, 0, "teeth"); - addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 20, "2-5"); + addflag(lastrace->flags, F_HITCONFER, F_POISONED, SC_POISON, 20, "3-5"); 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); @@ -5871,9 +6153,8 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_COLD, NA, NA, NULL); - addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^hissing"); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^hissing"); addrace(R_WOLF, "wolf", 10, 'd', C_BROWN, MT_FLESH); addflag(lastrace->flags, F_ANIMAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -6431,6 +6712,17 @@ void killrace(race_t *race) { } } +void loseconcentration(lifeform_t *lf) { + flag_t *f; + // stop sprinting + f = lfhasflag(lf, F_SPRINTING); + if (f && f->val[0]) { + killflag(f); + } + // boost spells end + stopallspells(lf); +} + // lose hp, and adjust damage based on resistances int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc) { return losehp_real(lf, amt, damtype, fromlf, damsrc, B_TRUE); @@ -6439,11 +6731,52 @@ int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, ch int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam) { char buf[BUFLEN]; char buf2[BUFLEN]; + char lfname[BUFLEN]; + flag_t *f; + + getlfname(lf, lfname); if (isplayer(lf)) { statdirty = B_TRUE; } + // check for psychic armour etc + if (amt > 0) { + if (isphysicaldam(damtype)) { + for (f = lf->flags->first ; f ; f = f->next) { + if (f->id == F_MAGICARMOUR) { + int damtaken; + damtaken = amt; + if (damtaken > f->val[0]) { + damtaken = f->val[0]; + } + f->val[0] -= damtaken; + if (f->val[0] <= 0) { + // from a spell? + if (f->lifetime == FROMSPELL) { + flag_t *spellflag; + spellflag = hasactivespell(lf, f->obfrom); + if (spellflag) { + killflag(spellflag); + } + } + killflag(f); + } else { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s%s %s pulses!", lfname, getpossessive(lfname), f->text); + } + } + + // reduce damage + amt -= damtaken; + } + } + } + } + + // adjust damage! if (reducedam) { adjustdamlf(lf, &amt, damtype); @@ -6452,6 +6785,13 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // stop resting/running! interrupt(lf); + // large damage? + if ((amt >= (lf->maxhp / 2)) && (amt >= 20)) { + if (useringofmiracles(lf, 1)) { + return 0; + } + } + // occasionally drop blood if ((damtype != DT_POISON) && (damtype != DT_POISONGAS)) { if (rnd(1,3) == 1) { @@ -6460,8 +6800,6 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } if (hasflag(lf->flags, F_DEBUG)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); msg("[%s takes %d dam]",lfname, amt); } @@ -6528,6 +6866,18 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml return amt; } +void losemp(lifeform_t *lf, int amt) { + if (isplayer(lf)) { + statdirty = B_TRUE; + } + lf->mp -= amt; + + if (lf->mp < 0) { + lf->mp = 0; + } +} + + void makefriendly(lifeform_t *who, int howlong) { char lfname[BUFLEN]; @@ -6552,6 +6902,8 @@ void makenauseated(lifeform_t *lf, int amt, int howlong) { if (lfhasflag(lf, F_UNDEAD)) return; if (isdead(lf)) return; + if (!lfhasflag(lf, F_HUMANOID)) return; + f = lfhasflag(lf, F_NAUSEATED); if (f) { if ((f->lifetime >= 0) && (f->lifetime < howlong)) { @@ -6635,6 +6987,10 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { + + if (isplayer(lf)) { + statdirty = B_TRUE; + } // already at max/min? if ((amt > 0) && (lf->att[attr] >= 18)) { return B_TRUE; @@ -6682,7 +7038,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { strcpy(adverb, "weaker"); break; case A_CON: - strcpy(adverb, "less healthy"); + strcpy(adverb, "frail"); break; case A_DEX: strcpy(adverb, "sluggish"); @@ -6710,6 +7066,7 @@ void modhunger(lifeform_t *lf, int amt) { f->val[0] += amt; posthlev = gethungerlevel(f->val[0]); + // announce if (isplayer(lf)) { if (posthlev == H_STARVED) { @@ -6754,10 +7111,16 @@ void modhunger(lifeform_t *lf, int amt) { if ((posthlev >= H_PECKISH) && (amt > 0)) { stopresting(lf); } + if (posthlev >= H_STARVING) { + useringofmiracles(lf, 2); + // reset hunger + f->val[0] = 0; + } + } } } - f->val[0] += amt; + } float modifybystat(float num, lifeform_t *lf, enum ATTRIB att) { @@ -6784,7 +7147,66 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { msg("%s %s.", lfname, seetext); } } else if (text) { - msg("You hear %s", text); + char textnopunc[BUFLEN]; + char punc; + int dist; + + punc = text[strlen(text)-1]; + strncpy(textnopunc, text, strlen(text)-1); + + dist = getcelldist(l->cell, c); + + // listen skill gives you more info about monsters + if (noisemaker) { + enum SKILLLEVEL slev; + char lfname[BUFLEN]; + char distbuf[BUFLEN]; + char dirbuf[BUFLEN]; + int dir; + + real_getlfnamea(noisemaker, lfname, B_FALSE); + if (dist >= 20) { + strcpy(distbuf, " far away"); + } else if (dist >= 10) { + strcpy(distbuf, ""); + } else if (dist >= 5) { + strcpy(distbuf, " nearby"); + } else { + strcpy(distbuf, " very nearby"); + } + + dir = getdirtowards(l->cell, c, NULL, B_FALSE, DT_COMPASS); + strcpy(dirbuf, getdirname(dir)); + dirbuf[0] = tolower(dirbuf[0]); + + slev = getskill(l, SK_LISTEN); + // + // high listen skill lets you know more info. + // + // beginner = distance + // adept = distance and direction + // expert = monstername and distance and direction + // master = temporary scan of where they are! + if (slev >= PR_MASTER) { + flag_t *f; + f = lfhasflagval(l, F_CANHEARLF, noisemaker->id, NA, NA, NULL); + if (f) { + if (f->lifetime > 0) f->lifetime = 2; + } else { + addtempflag(l->flags, F_CANHEARLF, noisemaker->id, NA, NA, NULL, 2); + } + } else if (slev >= PR_EXPERT) { + msg("You hear %s%s to the %s%c", lfname, distbuf, dirbuf, punc); + } else if (slev >= PR_ADEPT) { + msg("You hear %s%s to the %s%c", textnopunc, distbuf, dirbuf, punc); + } else if (slev >= PR_BEGINNER) { + msg("You hear %s%s%c", textnopunc, distbuf, punc); + } else { + msg("You hear %s", text); + } + } else { + msg("You hear %s", text); + } } } // wake up a little @@ -6950,6 +7372,48 @@ int pickup(lifeform_t *lf, object_t *what, int howmany, int fromground) { return B_FALSE; } +void poison(lifeform_t *lf, int howlong, char *fromwhat) { + flag_t *f; + int found = B_FALSE; + + // adjust time based on first aid skill + howlong -= getskill(lf, SK_FIRSTAID); + if (howlong <= 0) { + return; + } + + for (f = lf->flags->first ; f ; f = f->next) { + if ( (f->id == F_POISONED) && + (f->lifetime > 0) ){ + f->lifetime += howlong; + found = B_TRUE; + } + } + + if (!found) { + addtempflag(lf->flags, F_POISONED, B_TRUE, NA, NA, fromwhat, howlong); + } +} + +int poisonthreatenslife(lifeform_t *lf) { + flag_t *f; + float time,dam,totaldam; + f = lfhasflag(lf, F_POISONED); + if (!f) return B_FALSE; + + time = f->lifetime; + dam = POISONDAM; + + totaldam = time * dam; + totaldam = pctof(POISONDAMCHANCE, totaldam); + + if (totaldam >= lf->hp) { + return B_TRUE; + } + + return B_FALSE; +} + void practice(lifeform_t *lf, enum SKILL skid) { flag_t *f; @@ -7461,12 +7925,22 @@ void setrace(lifeform_t *lf, enum RACE rid) { } // announce if (origrace && (newrace == origrace)) { - if (isplayer(lf)) { - msg("You revert to your original form!"); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("The %s transforms back to its original form!", newrace->name); + // reverting to original form.... + if (!isdead(lf)) { + if (isplayer(lf)) { + msg("You revert to your original form!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("The %s transforms back to its original form!", newrace->name); + } } + + f = lfhasflagval(lf, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL); + if (f) { + killflag(f); + } + killflagsofid(lf->flags, F_ORIGRACE); + killflagsofid(lf->flags, F_POLYMORPHED); } else { if (isplayer(lf)) { msg("You transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name); @@ -7603,11 +8077,12 @@ void setlastdam(lifeform_t *lf, char *buf) { void initskills(void) { addskill(SK_ATHLETICS, "Athletics", "Assists with sprinting and exhaustion recovery."); addskill(SK_BACKSTAB, "Backstab", "Lets you inflict massive damage with stabs when unseen."); - addskill(SK_FIRSTAID, "First Aid", "Increases the rate at which you regain health."); + addskill(SK_FIRSTAID, "First Aid", "Increases your healing rate and reduces duration of poison."); addskill(SK_LISTEN, "Listen", "How good you are at hearing and interpreting sounds."); addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks."); addskill(SK_MAGITEMUSAGE, "Magic Item Usage", "Lets you make better use of magical items."); addskill(SK_RESEARCH, "Research", "Allows you a chance of recognising unknown objects."); + addskill(SK_SHIELDS, "Shields", "Reduces your accuracy penalty when using a shield."); addskill(SK_SPELLCASTING, "Spellcasting", "Determines your ability to cast spells from all schools."); addskill(SK_STEALTH, "Stealth", "Affects your ability to move silently."); addskill(SK_TECHUSAGE, "Technology", "Determines your comprehension of modern technological items."); @@ -7843,7 +8318,6 @@ int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, int slipon(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; char lfname[BUFLEN]; - flag_t *f; getlfname(lf,lfname); getobname(o, obname, 1); // slip! @@ -7853,12 +8327,12 @@ int slipon(lifeform_t *lf, object_t *o) { sprintf(damstring, "slipping on %s",obname); losehp(lf, 1, DT_FALL, NULL, damstring); } - taketime(lf, getactspeed(lf)); + taketime(lf, getactspeed(lf)*2); // object moves? if (hasflag(o->flags, F_SLIPMOVE)) { cell_t *cur, *new; cur = getoblocation(o); - new = getrandomadjcell(cur, WE_NOTSOLID); + new = getrandomadjcell(cur, WE_WALKABLE, B_NOEXPAND); if (new) { if (haslos(player, cur) || haslos(player, new)) { msg("%s slips across the floor.", obname); @@ -7866,13 +8340,7 @@ int slipon(lifeform_t *lf, object_t *o) { moveob(o, new->obpile, 1); } } - // stop sprinting - f = lfhasflag(lf, F_SPRINTING); - if (f && f->val[0]) { - killflag(f); - } - // boost spells end - stopallspells(lf); + loseconcentration(lf); return B_FALSE; } @@ -8097,9 +8565,11 @@ void taketime(lifeform_t *lf, long howlong) { return; } + /* if (isplayer(lf)) { statdirty = B_TRUE; } + */ map = lf->cell->map; @@ -8156,14 +8626,14 @@ void timeeffectslf(lifeform_t *lf) { f = hasflag(lf->flags, F_POISONED); if (f) { - // chance of fighting it off - if (skillcheck(lf, SC_POISON, (f->lifetime * 7), getskill(lf, SK_FIRSTAID))) { + // chance of fighting it off - gets easier over time. + // + if (skillcheck(lf, SC_POISON, (f->lifetime * 9), 0 )) { killflag(f); } else { // chance of losing hp - if (rnd(0,3)) { + if (rnd(1,100) <= POISONDAMCHANCE) { char buf[BUFLEN]; - flag_t *sf; if (isplayer(lf)) { msg("You vomit violently."); } else if (cansee(player, lf)) { @@ -8172,21 +8642,31 @@ void timeeffectslf(lifeform_t *lf) { msg("%s vomits violently.", lfname); } sprintf(buf, "poisoning^from %s",f->text); - losehp(lf, 2, DT_DIRECT, NULL, buf); + losehp(lf, POISONDAM, DT_DIRECT, NULL, buf); taketime(lf,5); addob(lf->cell->obpile, "pool of vomit"); - // stop sprinting - sf = lfhasflag(lf, F_SPRINTING); - if (sf && sf->val[0]) { - killflag(sf); - } - // boost spells end - stopallspells(lf); + loseconcentration(lf); } } } + f = hasflag(lf->flags, F_NAUSEATED); + if (f) { + // chance of being delayed + if (rnd(0,3) == 0) { + if (isplayer(lf)) { + msg("You %s!", rnd(0,1) ? "retch" : "gag"); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s %s.", lfname, rnd(0,1) ? "retches" : "gags"); + } + taketime(lf,5); + + loseconcentration(lf); + } + } // decrement flags timeeffectsflags(lf->flags); @@ -8289,7 +8769,7 @@ void turneffectslf(lifeform_t *lf) { if (f && ((f->val[0] == BP_WEAPON) || (f->val[0] == BP_SECWEAPON))) { cell_t *c; // weapon flies away - c = getrandomadjcell(lf->cell, WE_NOTSOLID); + c = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND); if (!c) c = lf->cell; moveob(o, c->obpile, o->amt); if (isplayer(lf)) { @@ -8311,7 +8791,7 @@ void turneffectslf(lifeform_t *lf) { if (ismetal(o->material->id)) { cell_t *c; // object flies away - c = getrandomadjcell(lf->cell, WE_NOTSOLID); + c = getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND); if (!c) c = lf->cell; moveob(o, c->obpile, o->amt); if (isplayer(lf)) { @@ -8440,6 +8920,16 @@ void turneffectslf(lifeform_t *lf) { default: break; } + } else { + switch (f->val[0]) { + case DT_WATER: + if (isplayer(lf) && hasbp(lf, BP_FEET)) { + msg("Your feet get wet."); + } + break; + default: + break; + } } } } @@ -8699,6 +9189,11 @@ int usestairs(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; int isportal = B_FALSE; + // need up update 'dlev:' + if (isplayer(lf)) { + statdirty = B_TRUE; + } + getlfname(lf, lfname); getobname(o, obname, 1); @@ -8781,6 +9276,22 @@ int usestairs(lifeform_t *lf, object_t *o) { } if (newcell) { + // check noone is in the way + if (newcell->lf) { + cell_t *c; + // if they are, move them + c = getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND); + if (c) { + // move them there + movelf(newcell->lf, c); + } else { + // TODO: handle this differently - ie always allow the player + // go there? + if (isplayer(lf)) msg("The stairs seem to be blocked."); + return B_TRUE; + } + } + // announce if (isplayer(lf)) { msg("You arrive at level %d.", newcell->map->depth); f = hasflag(o->flags, F_MAPLINK); @@ -8792,6 +9303,7 @@ int usestairs(lifeform_t *lf, object_t *o) { } else { dblog("ERROR - can't find opposite end of stairs/portal!"); msg("ERROR - can't find opposite end of stairs/portal!"); + return B_TRUE; } if (isplayer(lf)) { @@ -8805,6 +9317,37 @@ int usestairs(lifeform_t *lf, object_t *o) { return B_FALSE; } +// use a ring of miracles if we have one, and drain 'charges' +// charges from it. if expired, it will vanish. +// returns B_TRUE if we found one. +int useringofmiracles(lifeform_t *lf, int charges) { + object_t *o; + char lfname[BUFLEN]; + getlfname(lf, lfname); + for (o = lf->pack->first ; o ; o = o->next) { + if ( (o->type->id == OT_RING_MIRACLES) && + isequipped(o) && + getcharges(o) ) { + char obname[BUFLEN]; + getobname(o, obname, 1); + if (isplayer(lf) || cansee(player, lf)) { + msg("%s%s %s flashes!", lfname, getpossessive(lfname), noprefix(obname)); + } + + // use a charge + if (usecharge(o) <= 0) { + if (isplayer(lf) || cansee(player, lf)) { + msg("%s%s %s crumbles to dust.", lfname, getpossessive(lfname), noprefix(obname)); + } + removeob(o, ALL); + } + makeknown(OT_RING_MIRACLES); + return B_TRUE; + } + } + return B_FALSE; +} + int validateraces(void) { int goterror = B_FALSE; race_t *r; @@ -8884,6 +9427,14 @@ int validateraces(void) { } } } + } else if (f->id == F_NOISETEXT) { + if (f->val[0] == N_FLY) { + if (!hasflag(r->flags, F_FLYING) && !hasflag(r->flags, F_LEVITATING)) { + printf("ERROR in race '%s' - has NOISETEXT N_FLY but isn't flying.", r->name); + goterror = B_TRUE; + + } + } } } } @@ -8982,11 +9533,50 @@ int rest(lifeform_t *lf, int onpurpose) { if (rf->val[2] == 0) { // ask about gaining skills if (isplayer(lf)) msg("You finish training."); - if (lf->skillpoints) { + if (lf->skillpoints || getattpoints(player)) { if (isplayer(lf)) more(); enhanceskills(lf); } killflag(rf); + if (hasjob(lf, J_WIZARD)) { + objecttype_t *ot; + char ch = 'a'; + initprompt(&prompt, "Which new spell will you learn?"); + // gain your choice of spell from any known school. + for (ot = objecttype ; ot ; ot = ot->next) { + if (ot->obclass->id == OC_SPELL) { + if (!lfhasflagval(lf, F_CANCAST, ot->id, NA, NA, NULL) && + getspellpower(lf, ot->id) && + (getmaxmp(lf) >= getmpcost(lf, ot->id)) ) { + enum SPELLSCHOOL ss; + + ss = getspellschool(ot->id); + if (ss != SS_NONE) { + enum SKILLLEVEL slev; + slev = getskill(lf, getschoolskill(ss)); + if (slev >= PR_NOVICE) { + char buf[BUFLEN]; + // add this one + sprintf(buf, "%s (Lv %d %s)", ot->name, getspelllevel(ot->id), getschoolname(ss)); + addchoice(&prompt, ch++, buf, buf, ot); + } + } + } + } + } + if (isplayer(lf)) { + getchoice(&prompt); + ot = (objecttype_t *)prompt.result; + } else { + // pick randomly + ot = (objecttype_t *) prompt.choice[rnd(0,prompt.nchoices)].data; + } + if (ot) { + addflag(lf->flags, F_CANCAST, ot->id, NA, NA, NULL); + } else { + if (isplayer(lf)) msg("Not learning anything."); + } + } } } else { // resting @@ -9026,6 +9616,11 @@ int wear(lifeform_t *lf, object_t *o) { int nparts = 0; enum BODYPART bp; + // this might impact your AR + if (isplayer(lf)) { + statdirty = B_TRUE; + } + getobname(o, obname, 1); @@ -9202,6 +9797,15 @@ int wear(lifeform_t *lf, object_t *o) { } } + + // warn if it will be cumbersome + if (isplayer(lf)) { + f = hasflag(o->flags, F_SHIELD); + if (f && (getskill(lf, SK_SHIELDS) <= PR_INEPT) ) { + msg("You find this shield very cumbersome to use."); + } + } + // give flags giveobflags(lf, o, F_EQUIPCONFER); @@ -9215,6 +9819,12 @@ int weild(lifeform_t *lf, object_t *o) { int twohanded = B_FALSE; enum BODYPART weildloc,otherloc; + // this might impact your AR + if (isplayer(lf)) { + statdirty = B_TRUE; + } + + if (o) { getobname(o, buf, o->amt); } @@ -9494,13 +10104,4 @@ int willflee(lifeform_t *lf) { return B_FALSE; } -/* -int youhear(cell_t *c, char *text) { - if (canhear(player, c)) { - msg("You hear %s.", text); - return B_TRUE; - } - return B_FALSE; -} -*/ diff --git a/lf.h b/lf.h index b850255..a18d142 100644 --- a/lf.h +++ b/lf.h @@ -19,6 +19,7 @@ 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 canlearn(lifeform_t *lf, enum SKILL skid); int canpickup(lifeform_t *lf, object_t *o, int amt); int canpush(lifeform_t *lf, object_t *o, int dir); int canquaff(lifeform_t *lf, object_t *o); @@ -35,6 +36,7 @@ void dumpxp(void); int eat(lifeform_t *lf, object_t *o); void enhanceskills(lifeform_t *lf); object_t *eyesshaded(lifeform_t *lf); +int fall(lifeform_t *lf, int announce); void fightback(lifeform_t *lf, lifeform_t *attacker); job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); @@ -104,7 +106,7 @@ char *getplayernamefull(char *buf); int getracerarity(enum RACE rid); object_t *getrandomarmour(lifeform_t *lf); //int getrandommonlevel(int depth); -race_t *getrandomrace(map_t *map); +race_t *getrandomrace(map_t *map, int forcedepth); race_t *getreallyrandomrace(void); enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id); char *getspeedname(int speed, char *buf); @@ -135,7 +137,8 @@ flag_t *lfhasknownflagval(lifeform_t *lf, enum FLAG fid, int val0, int val1, int int lockpick(lifeform_t *lf, object_t *target, object_t *device); void loseobflags(lifeform_t *lf, object_t *o, int kind); int hasbp(lifeform_t *lf, enum BODYPART bp); -int haslof(lifeform_t *viewer, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest); +flag_t *hasactivespell(lifeform_t *lf, enum OBTYPE sid); +int haslof(cell_t *src, cell_t *dest, enum LOFTYPE loftype, cell_t **newdest); int haslos(lifeform_t *viewer, cell_t *dest); void initjobs(void); void initrace(void); @@ -162,8 +165,10 @@ flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); void killjob(job_t *job); void killlf(lifeform_t *lf); void killrace(race_t *race); +void loseconcentration(lifeform_t *lf); int losehp(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc); int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *fromlf, char *damsrc, int reducedam); +void losemp(lifeform_t *lf, int amt); void makefriendly(lifeform_t *lf, int howlong); void makenauseated(lifeform_t *lf, int amt, int howlong); void makenoise(lifeform_t *lf, enum NOISETYPE nid); @@ -175,6 +180,8 @@ float modifybystat(float num, lifeform_t *lf, enum ATTRIB att); void noise(cell_t *c, lifeform_t *noisemaker, 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, char *fromwhat); +int poisonthreatenslife(lifeform_t *lf); void practice(lifeform_t *lf, enum SKILL skid); void precalclos(lifeform_t *lf); int push(lifeform_t *lf, object_t *o, int dir); @@ -211,6 +218,7 @@ void turneffectslf(lifeform_t *lf); int touch(lifeform_t *lf, object_t *o); int unweild(lifeform_t *lf, object_t *o); int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where); +int useringofmiracles(lifeform_t *lf, int charges); int usestairs(lifeform_t *lf, object_t *o); int validateraces(void); int wear(lifeform_t *lf, object_t *o); diff --git a/log.txt b/log.txt index bf33f56..ea04015 100644 --- a/log.txt +++ b/log.txt @@ -8,190 +8,6 @@ xxx xxx xxx xxx -xxx -xxx -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. -finding random lf with rarity val 85-100 - --> possibility: goblin, rarity=85 --> possibility: troglodyte, rarity=85 --> possibility: xat, rarity=90 --> possibility: giant bat, rarity=90 --> possibility: giant worker ant, rarity=85 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=90 --> possibility: brown snake, rarity=85 --> possibility: giant fly, rarity=85 --> possibility: glowbug, rarity=85 -got 10 possibilities. finding random lf with rarity val 85-100 -> possibility: goblin, rarity=85 @@ -388,239 +204,118 @@ finding random lf with rarity val 85-100 -> possibility: glowbug, rarity=85 got 10 possibilities. rollhitdice() - rolling 2d4 + 2 -rollhitdice() - mod is +-5% +rollhitdice() - mod is +32% rollhitdice() ---- die 1/2 == 4 rollhitdice() ---- die 2/2 == 4 TOTAL: 8 - -> modified to: 8 + -> modified to: 10 givejob() starting. -processing normal flag: 191 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 149 -processing normal flag: 150 -processing normal flag: 150 -processing normal flag: 150 -processing normal flag: 150 -processing normal flag: 150 -processing normal flag: 150 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 219 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -processing normal flag: 218 -nclasses is 0 -nclasses is 0 -nclasses is 0 -nclasses is 0 -nclasses is 0 -nclasses is 0 -initial dam[0] = 1 -adjusted for lf to dam[0] = 1 -reduced by armour to dam[0] = 0 -initial dam[0] = 1 -adjusted for lf to dam[0] = 1 -reduced by armour to dam[0] = 0 -initial dam[0] = 26 -heavy blow makes dam[0] = 39 -adjusted for lf to dam[0] = 39 -reduced by armour to dam[0] = 39 -initial dam[1] = 10 -heavy blow makes dam[1] = 15 -adjusted for lf to dam[1] = 15 -reduced by armour to dam[1] = 15 -nclasses is 0 -nclasses is 0 -initial dam[0] = 19 -heavy blow makes dam[0] = 28 -adjusted for lf to dam[0] = 28 -reduced by armour to dam[0] = 23 -initial dam[1] = 6 -heavy blow makes dam[1] = 9 -adjusted for lf to dam[1] = 4 -reduced by armour to dam[1] = 3 -nclasses is 0 -nclasses is 0 -initial dam[0] = 2 -adjusted for lf to dam[0] = 2 -reduced by armour to dam[0] = 1 -initial dam[0] = 0 -adjusted for lf to dam[0] = 0 -reduced by armour to dam[0] = 0 -initial dam[0] = 2 -adjusted for lf to dam[0] = 2 -reduced by armour to dam[0] = 1 -initial dam[0] = 4 -adjusted for lf to dam[0] = 4 -reduced by armour to dam[0] = 2 -initial dam[0] = 1 -adjusted for lf to dam[0] = 1 -reduced by armour to dam[0] = 0 -initial dam[0] = 2 -adjusted for lf to dam[0] = 2 -reduced by armour to dam[0] = 1 -initial dam[0] = 2 -adjusted for lf to dam[0] = 2 -reduced by armour to dam[0] = 1 -initial dam[0] = 30 -heavy blow makes dam[0] = 45 -adjusted for lf to dam[0] = 45 -reduced by armour to dam[0] = 45 -initial dam[1] = 3 -heavy blow makes dam[1] = 4 -adjusted for lf to dam[1] = 4 -reduced by armour to dam[1] = 4 -rollhitdice() - rolling 49d4 + 0 -rollhitdice() - mod is +22% -rollhitdice() ---- die 1/49 == 1 -rollhitdice() ---- die 2/49 == 1 -rollhitdice() ---- die 3/49 == 2 -rollhitdice() ---- die 4/49 == 2 -rollhitdice() ---- die 5/49 == 4 -rollhitdice() ---- die 6/49 == 2 -rollhitdice() ---- die 7/49 == 3 -rollhitdice() ---- die 8/49 == 4 -rollhitdice() ---- die 9/49 == 4 -rollhitdice() ---- die 10/49 == 2 -rollhitdice() ---- die 11/49 == 1 -rollhitdice() ---- die 12/49 == 3 -rollhitdice() ---- die 13/49 == 1 -rollhitdice() ---- die 14/49 == 1 -rollhitdice() ---- die 15/49 == 4 -rollhitdice() ---- die 16/49 == 1 -rollhitdice() ---- die 17/49 == 3 -rollhitdice() ---- die 18/49 == 3 -rollhitdice() ---- die 19/49 == 4 -rollhitdice() ---- die 20/49 == 4 -rollhitdice() ---- die 21/49 == 1 -rollhitdice() ---- die 22/49 == 4 -rollhitdice() ---- die 23/49 == 1 -rollhitdice() ---- die 24/49 == 3 -rollhitdice() ---- die 25/49 == 3 -rollhitdice() ---- die 26/49 == 1 -rollhitdice() ---- die 27/49 == 2 -rollhitdice() ---- die 28/49 == 2 -rollhitdice() ---- die 29/49 == 4 -rollhitdice() ---- die 30/49 == 1 -rollhitdice() ---- die 31/49 == 1 -rollhitdice() ---- die 32/49 == 1 -rollhitdice() ---- die 33/49 == 3 -rollhitdice() ---- die 34/49 == 1 -rollhitdice() ---- die 35/49 == 4 -rollhitdice() ---- die 36/49 == 3 -rollhitdice() ---- die 37/49 == 2 -rollhitdice() ---- die 38/49 == 3 -rollhitdice() ---- die 39/49 == 3 -rollhitdice() ---- die 40/49 == 3 -rollhitdice() ---- die 41/49 == 4 -rollhitdice() ---- die 42/49 == 1 -rollhitdice() ---- die 43/49 == 2 -rollhitdice() ---- die 44/49 == 2 -rollhitdice() ---- die 45/49 == 1 -rollhitdice() ---- die 46/49 == 3 -rollhitdice() ---- die 47/49 == 3 -rollhitdice() ---- die 48/49 == 1 -rollhitdice() ---- die 49/49 == 2 -TOTAL: 115 - -> modified to: 140 -initial dam[0] = 0 -adjusted for lf to dam[0] = 0 -reduced by armour to dam[0] = 0 -initial dam[0] = 19 -heavy blow makes dam[0] = 28 -adjusted for lf to dam[0] = 28 -reduced by armour to dam[0] = 28 -initial dam[1] = 11 -heavy blow makes dam[1] = 16 -adjusted for lf to dam[1] = 16 -reduced by armour to dam[1] = 16 -nclasses is 1 +processing normal flag: 200 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 157 +processing normal flag: 158 +processing normal flag: 158 +processing normal flag: 158 +processing normal flag: 158 +processing normal flag: 158 +processing normal flag: 158 +processing normal flag: 156 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 229 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +processing normal flag: 227 +nwantflags is 1 +nwantflags is 0 diff --git a/map.c b/map.c index eb930be..7bf04a9 100644 --- a/map.c +++ b/map.c @@ -90,7 +90,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { } if ((raceid == R_NONE) || (raceid == R_RANDOM)) { - r = getrandomrace(c->map); + r = getrandomrace(c->map, 0); } else { r = findrace(raceid); } @@ -147,7 +147,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { // starting with the first one adjcell = NULL; for (n = 0; n < nmoncells; n++) { - adjcell = getrandomadjcell(moncell[n], WE_NOTSOLID); + adjcell = getrandomadjcell(moncell[n], WE_WALKABLE, B_ALLOWEXPAND); if (adjcell) break; } // did we find one? @@ -172,7 +172,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt) { // sometimes give the lf random objects (extra monsters through // 'numappears' don't get them. - if (!lfhasflag(lf, F_NOPACK)) { + if (lfhasflag(lf, F_HUMANOID) && !lfhasflag(lf, F_NOPACK)) { if (rnd(1,3) == 1) { int nobs = rnd(1,3); char buf[BUFLEN]; @@ -360,6 +360,89 @@ int getcelldistorth(cell_t *src, cell_t *dst) { // add x/y return abs(dst->x - src->x) + abs(dst->y - src->y); } +//populates 'g' with the contects of cell 'c', as seen by 'viewer' +// if we can't see anything there, set g->ch to NUL. +void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer) { + glyph_t tempgl; + + // default + g->ch = '\0'; + + if (haslos(viewer, c)) { + // show cell contents + //drawcellwithcontents(cell, x-viewx, y-viewy); + + if (c->lf && cansee(viewer, c->lf)) { // lifeform here which we can see + // draw the lf's race glyph + *g = *(getlfglyph(c->lf)); + return; + } else { // we can see the floor here + void *thing; + // scanned lf here? + if (isinscanrange(c, &thing, NULL, &tempgl) == TT_MONSTER) { + *g = tempgl; + //mvwprintw(gamewin, y-viewy, x-viewx, "%c", glyph); + //drawglyph(&glyph, x, y); + return; + } + } + + // objects here? + if ((countobs(c->obpile) > 0)) { + object_t *o; + + // draw highest object in sort order + o = gettopobject(c); + if (o) { + *g = *(getglyph(o)); + } else { + // should never happen. if it does, just show the + // first object + dblog("Warn: sorted object glyph drawing matching nothing!"); + //mvwprintw(gamewin, y, x, "%c", cell->obpile->first->type->obclass->glyph); + //drawglyph(&cell->obpile->first->type->obclass->glyph, x, y); + *g = c->obpile->first->type->obclass->glyph; + } + } else { + // draw cell normally + //drawcell(cell, x, y); + *g = c->type->glyph; + } + } else { // can't see the cell + void *thing; + //drawscannedcell(cell, x-viewx, y-viewy); + switch (isinscanrange(c, &thing, NULL, &tempgl)) { + case TT_MONSTER: + case TT_OBJECT: + *g = tempgl; + break; + default: + if (c->known) { + //drawunviscell(cell, x-viewx, y-viewy); + object_t *o; + + // copy from cell + *g = c->type->glyph; + if (g->ch == '.') { + g->ch = ' '; + } + + // show staircases... + o = hasobwithflag(c->obpile, F_CLIMBABLE); + if (o) { + *g = *(getglyph(o)); + } + // show dungeon features + o = hasobofclass(c->obpile, OC_DFEATURE); + if (o) { + *g = *(getglyph(o)); + } + } + break; + } + } +} + enum CELLTYPE getemptycelltype(enum HABITAT hab) { switch (hab) { case H_DUNGEON: @@ -1785,41 +1868,62 @@ int getobchance(int habitat) { return 0; } -cell_t *getrandomadjcell(cell_t *c, int wantempty) { - int dir; - int ntries = 0; +cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) { + int radius = 1; + int x,y; + cell_t *poss[MAXCANDIDATES]; + int nposs = 0; cell_t *new; - dir = getrandomdir(DT_COMPASS); - while (ntries < 8) { - new = getcellindir(c, dir); - if (new) { - if (wantempty == WE_EMPTY) { - // make sure it's empty - if (isempty(new)) { - return new; - } - } else if (wantempty == WE_NOTSOLID) { - if (cellwalkable(NULL, new, NULL)) { - return new; - } - } else if (wantempty == WE_PORTAL) { - if (cellwalkable(NULL, new, NULL) && !hasenterableobject(new) ) { - if (!hasobwithflag(new->obpile, F_DOOR)) { - return new; + int done = B_FALSE; + + while (!done) { + int numwithlof = 0; + for (y = c->y - radius ; y <= c->y + radius ; y++) { + for (x = c->x - radius ; x <= c->x + radius ; x++) { + new = getcellat(c->map, x, y); + if (new && (getcelldist(c,new) == radius) && haslof(c, new, LOF_WALLSTOP, NULL)) { + numwithlof++; + if (wantempty == WE_EMPTY) { + // make sure it's empty + if (isempty(new)) { + poss[nposs++] = new; + } + } else if (wantempty == WE_WALKABLE) { + if (cellwalkable(NULL, new, NULL)) { + poss[nposs++] = new; + } + } else if (wantempty == WE_PORTAL) { + if (cellwalkable(NULL, new, NULL) && !hasenterableobject(new) ) { + if (!hasobwithflag(new->obpile, F_DOOR)) { + poss[nposs++] = new; + } + } + } else { + // always ok + poss[nposs++] = new; } } - } else { - // always ok - return new; } } - // not found yet... - dir++; - if (dir > DC_NW) dir = DC_N; - ntries++; + + // found any possibilities ? + if (nposs) { + done = B_TRUE; + } else { + if (allowexpand) { + if (numwithlof) { + // increment radius + radius++; + } else { + return NULL; + } + } else { + return NULL; + } + } } - return NULL; + return poss[rnd(0,nposs-1)]; } cell_t *getrandomcell(map_t *map) { @@ -1985,15 +2089,25 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { if (c->lf) { if (getcelldistorth(player->cell, c) <= f->val[0]) { *thing = c->lf; - if (desc) { - char *p; - p = getsizetext(getlfsize(c->lf)); - sprintf(desc, "%s %s monster", isvowel(*p) ? "an" : "a", p); - } - if (glyph) { - // select glyph based on size - glyph->ch = '0' + ((int) getlfsize(c->lf)); - glyph->colour = C_GREY; + if (f->val[1] == B_TRUE) { + if (desc) { + real_getlfnamea(c->lf, desc, B_FALSE); + strcat(desc, " (detected)"); + } + if (glyph) { + *glyph = *(getlfglyph(c->lf)); + } + } else { + if (desc) { + char *p; + p = getsizetext(getlfsize(c->lf)); + sprintf(desc, "%s %s monster", isvowel(*p) ? "an" : "a", p); + } + if (glyph) { + // select glyph based on size + glyph->ch = '0' + ((int) getlfsize(c->lf)); + glyph->colour = C_GREY; + } } return TT_MONSTER; } @@ -2026,6 +2140,21 @@ int isinscanrange(cell_t *c, void **thing, char *desc, glyph_t *glyph) { } } } + + // can hear them using master level listen skill? + if (c->lf && lfhasflagval(player, F_CANHEARLF, c->lf->id, NA, NA, NULL)) { + if (glyph) { + *glyph = *(getlfglyph(c->lf)); + } + if (desc) { + real_getlfnamea(c->lf, desc, B_FALSE); + strcat(desc, " (heard)"); + } + + *thing = c->lf; + return TT_MONSTER; + } + f = lfhasflag(player, F_DETECTOBS); if (f) { if (getcelldistorth(player->cell, c) <= f->val[0]) { diff --git a/map.h b/map.h index c4ea096..ef3ca6f 100644 --- a/map.h +++ b/map.h @@ -9,6 +9,7 @@ int cellhaslos(cell_t *c1, cell_t *dest); cell_t *getcellat(map_t *map, int x, int y); int getcelldist(cell_t *src, cell_t *dst); int getcelldistorth(cell_t *src, cell_t *dst); +void getcellglyph(glyph_t *g, cell_t *c, lifeform_t *viewer); enum CELLTYPE getemptycelltype(enum HABITAT hab); object_t *gettopobject(cell_t *where); void calclight(map_t *map); @@ -30,7 +31,7 @@ void forgetcells(map_t *map, int amt); cell_t *getcellindir(cell_t *cell, int dir); int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved); int getobchance(int habitat); -cell_t *getrandomadjcell(cell_t *c, int wantempty); +cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand); cell_t *getrandomcell(map_t *map); cell_t *getrandomcelloftype(map_t *map, int id); int getrandomdir(int dirtype); diff --git a/move.c b/move.c index caa5603..260f378 100644 --- a/move.c +++ b/move.c @@ -1093,7 +1093,7 @@ int pullnextto(lifeform_t *lf, cell_t *c) { return B_TRUE; } - if (!haslof(lf, dst, B_FALSE, &newdst)) { + if (!haslof(lf->cell, dst, B_FALSE, &newdst)) { if (newdst) { // update destination dst = newdst; @@ -1170,6 +1170,13 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { int slip; // check for cursed objects + animals + // do this AFTER checking if we will move, so that + // they will actually try the move and fail (this lets + // the player find out about the cursed object). + // + // note however that if a monster is chasing a player (ie + // has F_TARGET,player) then they will simply avoid the cursed + // object rather than failing the movement. for (o = cell->obpile->first ; o ; o = o->next) { if (!isplayer(lf)) { if (o->blessed == B_CURSED) { @@ -1184,6 +1191,9 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } taketime(lf, getmovespeed(lf)); reason = E_OK; + // avoid this object in future + sprintf(buf, "%ld",o->id); + addflag(lf->flags, F_AVOIDCURSEDOB, NA, NA, NA, buf); return B_FALSE; } } @@ -1225,7 +1235,7 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { moveto(lf, cell, onpurpose); taketime(lf, getmovespeed(lf)); } else { - object_t *inway; + object_t *inway = NULL; int door, dooropen; reason = errcode; switch (errcode) { @@ -1313,8 +1323,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { } } } - } else { // object is in the way - if (lf->controller == C_PLAYER) { + } else { // somethign random is in the way + if (isplayer(lf) && inway) { char obname[BUFLEN]; getobname(inway, obname, 1); msg("There is %s in your way.",obname); @@ -1406,6 +1416,8 @@ int trymove(lifeform_t *lf, int dir, int onpurpose) { int willmove(lifeform_t *lf, int dir, enum ERROR *error) { cell_t *cell; enum IQBRACKET iq; + object_t *o; + char buf[BUFLEN]; //object_t *o; iq = getiqname(getattr(lf, A_IQ), NULL); @@ -1417,6 +1429,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { cell = getcellindir(lf->cell, dir); if (celldangerous(lf, cell, B_TRUE, error)) { + if (error) *error = E_WONT; return B_FALSE; } @@ -1429,6 +1442,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { if (canswapwith(lf, cell->lf)) { return B_TRUE; } + if (error) *error = E_WONT; return B_FALSE; } } @@ -1438,9 +1452,28 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { if (iq >= IQ_AVERAGE) { // don't move if in pain if (lfhasflag(lf, F_PAIN)) { + if (error) *error = E_WONT; return B_FALSE; } } + + // look for avoided objects (because they are cursed). + for (o = cell->obpile->first ; o ; o = o->next) { + flag_t *f; + sprintf(buf, "%ld",o->id); + f = lfhasflagval(lf, F_AVOIDCURSEDOB, NA, NA, NA, buf); + if (f) { + // still cursed? + if (iscursed(o)) { + if (error) *error = E_WONT; + return B_FALSE; + } else { + // remove the flag. + killflag(f); + } + } + } + return B_TRUE; } diff --git a/nexus.c b/nexus.c index b680b90..28b5f28 100644 --- a/nexus.c +++ b/nexus.c @@ -433,8 +433,14 @@ void donextturn(map_t *map) { if (donormalmove) { f = hasflag(who->flags, F_RESTING); if (f) { - rest(who, B_TRUE); - donormalmove = B_FALSE; + // check for interrupt of resting... + if (isplayer(who) && checkforkey()) { + msg("Stopped resting."); + killflag(f); + } else { + rest(who, B_TRUE); + donormalmove = B_FALSE; + } } } @@ -523,6 +529,25 @@ char *getdirname(int dir) { return "?errordir?"; } +enum COLOUR getpctcol(float num, float max) { + float pct; + pct = (num / max) * 100; + if (pct > 100) { + return C_BOLDBLUE; + } else if (pct == 100) { + return C_BOLDGREEN; + } else if (pct >= 75) { + return C_GREEN; + } else if (pct >= 50) { + return C_BROWN; + } else if (pct >= 25) { + return C_RED; + } else { // ie. < 25% + return C_ORANGE; + } + return C_ORANGE; +} + void getrarity(int depth, int *min, int *max, int range) { int mid; mid = 100 - (depth * 3); @@ -752,6 +777,7 @@ float pctof(float pct, float num) { return ((pct / 100.0) * num); } + // get a random number between min and max int rnd(int min, int max) { int res; @@ -1024,9 +1050,11 @@ void timeeffectsworld(map_t *map) { //dblog("shuffling id %d %s timespent=%d -> %d",l->id,l->race->name, l->timespent, l->timespent - firstlftime); l->timespent -= firstlftime; assert(l->timespent >= 0); + /* if (isplayer(l)) { statdirty = B_TRUE; } + */ } //dblog("after shuffle:"); diff --git a/nexus.h b/nexus.h index 2a97ffa..045f935 100644 --- a/nexus.h +++ b/nexus.h @@ -9,6 +9,7 @@ void dobresnham(int d, int xinc1, int yinc1, int dinc1, int xinc2, int yinc2, in void donextturn(map_t *map); celltype_t *findcelltype(int id); char *getdirname(int dir); +enum COLOUR getpctcol(float num, float max); void getrarity(int depth, int *min, int *max, int range); int init(void); void calcbresnham(map_t *m, int x1, int y1, int x2, int y2, cell_t **retcell, int *numpixels); diff --git a/objects.c b/objects.c index e48c81b..e752b48 100644 --- a/objects.c +++ b/objects.c @@ -42,6 +42,7 @@ extern lifeform_t *player; extern int reason; extern int needredraw; +extern int statdirty; char letorder[MAXPILEOBS] = { @@ -641,6 +642,14 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { } } + // charge flag always starts unknown. + f = hasflag(o->flags, F_CHARGES); + if (f) { + f->known = B_FALSE; + } + + + // non-inherited from here on: // if adding to a player... if (where->owner) { @@ -736,10 +745,10 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { where = getoblocation(o); // select random race if (where) { - corpserace = getrandomrace(where->map); + corpserace = getrandomrace(where->map, 0); } else { // ie. vending machine - corpserace = getrandomrace(NULL); + corpserace = getrandomrace(NULL, 0); } } @@ -941,8 +950,44 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { bonus -= atoi(numbuf); } - addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); - + if (bonus) { + if (hasflag(o->flags, F_ENCHANTABLE)) { + // for swords, armour etc + addflag_real(o->flags, F_BONUS, bonus, NA, NA, NULL, PERMENANT, B_UNKNOWN, -1); + } + } + + // special rings which get randomized... + if (o->type->id == OT_RING_CON) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_CON, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + } else if (o->type->id == OT_RING_DEX) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + } else if (o->type->id == OT_RING_IQ) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_IQ, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + } else if (o->type->id == OT_RING_STR) { + flag_t *f; + f = hasflagval(o->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, NA, NULL); + if (f) { + if (bonus) f->val[2] = bonus; + else f->val[2] = rnd(1,3); + } + } + // check for postmods. eg. "xxx of pyromania" for (br = firstbrand ; br ; br = br->next) { if (strstr(name, br->suffix)) { @@ -1315,6 +1360,34 @@ void adjustprice(objecttype_t *ot, float *price) { } */ +int adjustshieldpenalty(lifeform_t *lf, float amt) { + enum SKILLLEVEL slev; + slev = getskill(lf, SK_SHIELDS); + switch (slev) { + case PR_INEPT: + amt *= 10; + break; + case PR_NOVICE: + break; + case PR_BEGINNER: + amt *= 0.8; + break; + case PR_ADEPT: + amt *= 0.6; + break; + case PR_SKILLED: + amt *= 0.4; + break; + case PR_EXPERT: + amt *= 0.2; + break; + case PR_MASTER: + amt = 0; + break; + } + return amt; +} + void appendinscription(object_t *o, char *text) { if (o->inscription) { int len; @@ -1333,6 +1406,13 @@ void appendinscription(object_t *o, char *text) { void applyobmod(object_t *o, obmod_t *om) { flag_t *f; + + if ((om->id == OM_MASTERWORK) || (om->id == OM_SHODDY)) { + if (hasflag(o->flags, F_NOQUALITY)) { + return; + } + } + if (om->id == OM_FROZEN) { // frozen things don't decay f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL); @@ -1679,14 +1759,38 @@ int countobs(obpile_t *op) { int curseob(object_t *o) { int rv = B_FALSE; + lifeform_t *lf; + + // announce + lf = o->pile->owner; + + // announce + if (lf) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + char obname[BUFLEN]; + getlfname(lf, lfname); + getobname(o, obname,o->amt); + msg("A black aura surrounds %s%s %s.",lfname,getpossessive(lfname),noprefix(obname)); + } + } else { // not held + cell_t *loc = NULL; + loc = getoblocation(o); + if (haslos(player, loc)) { + char obname[BUFLEN]; + getobname(o, obname,o->amt); + msg("A black aura surrounds %s.",obname); + } + } + switch (o->blessed) { - case B_BLESSED: + case B_BLESSED: // uncurse it setblessed(o, B_UNCURSED); break; - case B_CURSED: + case B_CURSED: // nothing happens rv = B_TRUE; break; - case B_UNCURSED: + case B_UNCURSED: // curse it setblessed(o, B_CURSED); break; } @@ -2749,6 +2853,39 @@ char *getobdesc(object_t *o, char *buf) { return buf; } +char *getobequipinfo(object_t *o, char *buf) { + object_t *ammo = NULL; + flag_t *f; + + strcpy(buf, ""); + + if (o->pile->owner) { + ammo = getammo(o->pile->owner); + } + + f = hasflag(o->flags,F_EQUIPPED); + if (f) { + if (f->val[0] == BP_WEAPON) { + if (hasflag(o->flags, F_TWOHANDED)) { + strcat(buf, " (two-handed weapon)"); + } else { + strcat(buf, " (weapon)"); + } + } else { + strcat(buf, " ("); + strcat(buf, getbodypartequipname(f->val[0])); + strcat(buf, " "); + strcat(buf, getbodypartname(f->val[0])); + strcat(buf, ")"); + } + } + + // ammo? + if (ammo && (ammo == o)) { + strcat(buf, " (current ammo)"); + } + return buf; +} char *getobextrainfo(object_t *o, char *buf) { object_t *ammo = NULL; @@ -2780,27 +2917,6 @@ char *getobextrainfo(object_t *o, char *buf) { strcat(buf, " [activated]"); } - f = hasflag(o->flags,F_EQUIPPED); - if (f) { - if (f->val[0] == BP_WEAPON) { - if (hasflag(o->flags, F_TWOHANDED)) { - strcat(buf, " (two-handed weapon)"); - } else { - strcat(buf, " (weapon)"); - } - } else { - strcat(buf, " ("); - strcat(buf, getbodypartequipname(f->val[0])); - strcat(buf, " "); - strcat(buf, getbodypartname(f->val[0])); - strcat(buf, ")"); - } - } - - // ammo? - if (ammo && (ammo == o)) { - strcat(buf, " (current ammo)"); - } return buf; } @@ -3024,6 +3140,25 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan } } + // special rings + if (isidentified(o)) { + switch (o->type->id) { + char buf2[BUFLENSMALL]; + case OT_RING_CON: + case OT_RING_DEX: + case OT_RING_IQ: + case OT_RING_STR: + f = hasflag(o->flags, F_EQUIPCONFER); + if (f) { + sprintf(buf2, "+%d ",f->val[2]); + strcat(buf, buf2); + } + break; + default: + break; + } + } + // object name strcat(buf, pluralname); free(pluralname); @@ -3123,6 +3258,9 @@ char *real_getobname(object_t *o, char *buf, int count, int wantpremods, int wan default: break; } + if (hasflag(o->flags, F_ENCHANTABLE) && hasflag(o->flags, F_BONUS)) { + ismagic = B_TRUE; + } if (ismagic) { @@ -3436,15 +3574,16 @@ char *real_getrandomob(map_t *map, char *buf, int cond, int cval, int forcedepth if ((ot->obclass->id == OC_WEAPON) || (ot->obclass->id == OC_ARMOUR)) { obmod_t *om; - // 1 in 6 of masterwork - if (rnd(1,6) == 1) { - om = findobmod(OM_MASTERWORK); - strcat(cursestr, om->prefix); - } else if (rnd(1,3) == 1) { // 1 in 3 of shoddy - om = findobmod(OM_SHODDY); - strcat(cursestr, om->prefix); + if (!hasflag(ot->flags, F_NOQUALITY)) { + // 1 in 6 of masterwork + if (rnd(1,6) == 1) { + om = findobmod(OM_MASTERWORK); + strcat(cursestr, om->prefix); + } else if (rnd(1,3) == 1) { // 1 in 3 of shoddy + om = findobmod(OM_SHODDY); + strcat(cursestr, om->prefix); + } } - } if (canbepoisoned(ot->id)) { @@ -3751,7 +3890,7 @@ char *getschoolname(enum SPELLSCHOOL sch) { case SS_AIR: return "Elemental/Air Magic"; case SS_FIRE: return "Elemental/Fire Magic"; case SS_ICE: return "Elemental/Ice Magic"; - case SS_MODIFICATION: return "Transmutation Magic"; + case SS_MODIFICATION: return "Modification Magic"; case SS_DEATH: return "Necromancy"; case SS_LIFE: return "Life Magic"; case SS_DIVINATION: return "Divination Magic"; @@ -4186,6 +4325,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_POURABLE, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_DRINKABLE, B_TRUE, NA, NA, NULL); addoc(OC_RING, "Rings", "A circular band, worn on the finger.", '=', C_GREY); addflag(lastobjectclass->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_GOESON, BP_RIGHTHAND, NA, NA, NULL); @@ -4378,6 +4518,11 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.5, OC_FOOD); + addflag(lastot->flags, F_GLYPH, C_GREEN, NA, NA, "%"); + addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_HOLDCONFER, F_EXTRALUCK, 1, NA, NULL); addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "%"); addflag(lastot->flags, F_EDIBLE, B_TRUE, 110, NA, ""); @@ -4423,6 +4568,9 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AIFLEEITEM, B_TRUE, NA, NA, NULL); + addot(OT_POT_POISON, "potion of poison", "Poisons the drinker.", MT_GLASS, 1, OC_POTION); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addot(OT_POT_ACID, "flask of battery acid", "Causes massive internal burning if ingested.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of acid"); @@ -4439,6 +4587,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); addot(OT_POT_EXPERIENCE, "potion of experience", "Instantly grants the imbiber the next experience level.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 40, NA, NULL); + addflag(lastot->flags, F_AIBOOSTITEM, B_TRUE, 40, NA, NULL); addot(OT_POT_BLOODC, "potion of cockatrice blood", "A small quantity of cockatrice blood.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); @@ -4672,6 +4821,12 @@ void initobjects(void) { addot(OT_S_CLOUDKILL, "cloudkill", "Creates a cloud of poisonous gas.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addot(OT_S_WINDSHIELD, "cyclonic shield", "Surrounds the caster with a whirling cyclone to repel missiles.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_AIR, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); /////////////////// // elemental - fire /////////////////// @@ -4788,6 +4943,7 @@ void initobjects(void) { addot(OT_S_PSYARMOUR, "psychic armour", "Mentally block incoming attacks.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); // TODO: hardcode how ai casts this @@ -4951,6 +5107,9 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addot(OT_A_INSPECT, "inspect", "Try to identify an unknown object from your pack.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_NOANNOUNCE, B_TRUE, NA, NA, NULL); addot(OT_A_STINGACID, "sting (acid)", "You can sting your enemies.", MT_NOTHING, 0, OC_ABILITY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -4972,6 +5131,8 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_RESEARCH, NA, NA, NULL); addot(OT_MAN_MAGITEMUSAGE, "manual of magic item usage", "Teaches you the skill 'magic item usage'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_MAGITEMUSAGE, NA, NA, NULL); + addot(OT_MAN_SHIELDS, "manual of shields", "Teaches you the skill 'shields'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_SHIELDS, NA, NA, NULL); addot(OT_MAN_SPELLCASTING, "manual of spellcasting", "Teaches you the skill 'spellcasting'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SPELLCASTING, NA, NA, NULL); addot(OT_MAN_STEALTH, "manual of stealth", "Teaches you the skill 'stealth'.", MT_PAPER, 3, OC_BOOK); @@ -5576,7 +5737,7 @@ void initobjects(void) { addot(OT_SPLASHWATER, "splash of water", "A small splash of water.", MT_NOTHING, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); + addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, ","); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DIETEXT, NA, NA, NA, "evaporates"); @@ -5589,7 +5750,7 @@ void initobjects(void) { addot(OT_PUDDLEWATER, "small puddle of water", "A small puddle of water.", MT_WATER, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); + addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice"); @@ -5601,7 +5762,7 @@ void initobjects(void) { addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, "{"); + addflag(lastot->flags, F_GLYPH, C_BLUE, NA, NA, "{"); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DTCONVERT, DT_COLD, NA, NA, "sheet of ice"); @@ -5613,7 +5774,7 @@ void initobjects(void) { addot(OT_BLOODSTAIN, "blood stain", "A dried stain of blood.", MT_BLOOD, 0, OC_MISC); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_GLYPH, NA, NA, NA, ","); + addflag(lastot->flags, F_GLYPH, C_RED, NA, NA, ","); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -6023,24 +6184,32 @@ void initobjects(void) { addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 4, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 6, NA, NA, NULL); - addflag(lastot->flags, F_ACCURACY, -10, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR); - addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 78, NA, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_ARMOURRATING, 8, NA, NA, NULL); - addflag(lastot->flags, F_ACCURACY, -15, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); + addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR); + addflag(lastot->flags, F_RARITY, H_ALL, 65, NA, NULL); + addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); + addflag(lastot->flags, F_ARMOURRATING, 12, NA, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL); + addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); // rings - addot(OT_RING_SEEINVIS, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING); + addot(OT_RING_SIGHT, "ring of sight", "Allows the caster to see the invisible, and in the dark.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 75, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINVIS, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SEEINDARK, 5, NA, NULL); @@ -6048,13 +6217,31 @@ void initobjects(void) { addot(OT_RING_LUCK, "ring of luck", "Makes the wearer more lucky.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_EXTRALUCK, 5, NA, NULL); + + addot(OT_RING_STR, "ring of strength", "Increases the wearer's strength.", MT_METAL, 0.1, OC_RING); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_STR, 1, NULL); // '1' is randomized during generation + addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); + addot(OT_RING_IQ, "ring of intelligence", "Increases the wearer's intelligence.", MT_METAL, 0.1, OC_RING); + 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); + 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); + addot(OT_RING_DEX, "ring of dexterity", "Increases the wearer's dexterity.", MT_METAL, 0.1, OC_RING); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_ATTRMOD, A_DEX, 1, NULL); // '1' is randomized during generation + addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); addot(OT_RING_MANA, "ring of mana", "Increases the wearer's MP pool.", MT_METAL, 0.1, OC_RING); - addflag(lastot->flags, F_RARITY, H_ALL, 65, NA, ""); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_EXTRAMP, 10, NA, NULL); addot(OT_RING_WOUNDING, "ring of wounding", "Increases the damage output of the wearer.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 65, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_EXTRADAM, NA, NA, "0d0+4"); addflag(lastot->flags, F_ENCHANTABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_IDWHENUSED, B_TRUE, NA, NA, NULL); addot(OT_RING_INVIS, "ring of invisibility", "Renders the wearer invisible.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_INVISIBLE, NA, NA, NULL); @@ -6066,12 +6253,18 @@ void initobjects(void) { addot(OT_RING_PROTFIRE, "ring of fire immunity", "Grants the caster complete immunity to fire.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_DTIMMUNE, DT_FIRE, NA, NULL); + addot(OT_RING_CONTROL, "ring of control", "Allows the wearer control over teleportation and polymorphic effects.", MT_METAL, 0.1, OC_RING); + addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, ""); + addflag(lastot->flags, F_EQUIPCONFER, F_CONTROL, NA, NA, NULL); addot(OT_RING_REGENERATION, "ring of regeneration", "Slowly regenerates the wearer's health, even when not resting.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_REGENERATES, 1, NA, NULL); addot(OT_RING_RESISTMAG, "ring of magic resistance", "Renders the wearer immune to most magical effects.", MT_METAL, 0.1, OC_RING); addflag(lastot->flags, F_RARITY, H_ALL, 50, NA, ""); addflag(lastot->flags, F_EQUIPCONFER, F_RESISTMAG, 5, NA, NULL); + addot(OT_RING_MIRACLES, "ring of miracles", "For a limited time, grants miracles to the wearer.", MT_METAL, 0.1, OC_RING); + addflag(lastot->flags, F_RARITY, H_ALL, 40, NA, ""); + addflag(lastot->flags, F_CHARGES, 3, 3, NA, NULL); // unarmed weapons - note these damage/accuracys can be // overridded with the lifeform flag F_HASATTACK @@ -6207,67 +6400,8 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 1, 1, NA, NULL); addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); - // stabbing weapons - addot(OT_DAGGER, "dagger", "A short stabbing weapon with a pointed blade.", MT_METAL, 1, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); - addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_ORNDAGGER, "ornamental dagger", "This dagger is pretty, but not particularly effective.", MT_METAL, 1, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); - addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 3, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 6, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); - addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 2.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); - addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 3, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 10, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); - addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 1, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 35, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 4, 1, NULL); - addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); - addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); - addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - // chopping weapons + // axes addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 4, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); @@ -6276,15 +6410,6 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); - addot(OT_HANDAXE, "hand axe", "A fast one-handed axe made for combat.", MT_METAL, 2, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_CHOP, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 6, 1, NULL); - addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); - addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); addot(OT_BATTLEAXE, "battleaxe", "An axe specifically designed for combat.", MT_METAL, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -6303,8 +6428,37 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_MIGHTY, NA, NULL); + addot(OT_HANDAXE, "hand axe", "A fast one-handed axe made for combat.", MT_METAL, 2, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_CHOP, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 6, 1, NULL); + addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); - // slashing weapons + // short blades + addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 4, 1, NULL); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addot(OT_DAGGER, "dagger", "A short stabbing weapon with a pointed blade.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); + addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 1, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); @@ -6315,6 +6469,50 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addot(OT_ORNDAGGER, "ornamental dagger", "This dagger is pretty, but not particularly effective.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 3, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_PICKLOCKS, 7, B_BLUNTONFAIL, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality, which somehow allows its bearer to attack faster.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 35, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 2.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, DX_DEXTROUS, NA, NULL); + addot(OT_SHORTSWORD, "short sword", "A short blade for fighting. Better for stabbing.", MT_METAL, 2.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 6, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 0.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 6, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addot(OT_STEAKKNIFE, "steak knife", "A common kitchen knife.", MT_METAL, 0.2, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); @@ -6324,33 +6522,30 @@ void initobjects(void) { addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 3, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 2, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); - addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 0.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 6, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 60, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); - addot(OT_SCIMITAR, "scimitar", "A sharp, curved blade.", MT_METAL, 2, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 8, 2, NULL); + + // long blades + addot(OT_FALCHION, "falchion", "A single-edged heavy sword made for chopping.", MT_METAL, 4.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 135, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_CHOP, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 8, 3, NULL); 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, ST_WEAK, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addot(OT_GREATSWORD, "greatsword", "A massive two-handed sword.", MT_METAL, 10, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 12, 6, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 8, 3, NULL); + addflag(lastot->flags, F_DAM, 1, 8, 2, NULL); 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, ST_AVERAGE, NA, NULL); @@ -6362,28 +6557,78 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, 1, 6, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addot(OT_GREATSWORD, "greatsword", "A massive two-handed sword.", MT_METAL, 10, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); + addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 2, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 12, 6, NULL); + addflag(lastot->flags, F_DAM, 1, 8, 2, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); // polearms - addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); + addot(OT_GLAIVE, "glaive", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 7, 3, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addot(OT_GUISARME, "guisarme", "A hooked polearm.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 2, 4, 0, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AWKWARD, NA, NULL); + addot(OT_HALBERD, "halberd", "A spiked axe blade mounted on a long shaft, with a hook on the back.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 71, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_CHOP, NA, NA, NULL); + addflag(lastot->flags, F_TRIPATTACK, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 9, 2, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AVERAGE, NA, NULL); + addot(OT_LANCE, "lance", "A pole weapon designed for use while mounted.", MT_METAL, 4, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 8, 2, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addot(OT_RANSEUR, "ranseur", "A long spear and cross hilt, resembling a pole-mounted sai. Good for disarming.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 2, 4, 0, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, DX_AVERAGE, NA, NULL); + addot(OT_SCYTHE, "scythe", "An agricultural hand tool for mowing grass, or reaping crops.", MT_METAL, 3, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 2, 4, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); addot(OT_SPEAR, "spear", "A long pole with a sharpened head.", MT_METAL, 4, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); @@ -6393,24 +6638,27 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 15, 15, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); - - // bashing weapons - addot(OT_STICK, "stick", "A sturdy wooden stick.", MT_WOOD, 0.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 2, NA, NULL); + addot(OT_TRIDENT, "trident", "A three-pronged stabbing weapon.", MT_METAL, 3, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 10, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addot(OT_SPANNER, "spanner", "A long, heavy metal wrench.", MT_METAL, 1, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); + + // staves + addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 2, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 130, NA, NA, NULL); addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); - addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OPERNEEDDIR, B_TRUE, NA, NA, "Use your spanner in which direction"); - addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_STAVES, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_VWEAK, NA, NULL); + + // clubs (bashing) addot(OT_CLUB, "club", "A heavy, blunt wooden instrument to hit things with.", MT_STONE, 1.5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -6419,14 +6667,6 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_WEAK, NA, NULL); - addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 3, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 6, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); @@ -6443,15 +6683,6 @@ void initobjects(void) { addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); - addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 3.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); - addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); - addflag(lastot->flags, F_DAM, 1, 10, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 180, NA, NA, NULL); @@ -6461,17 +6692,51 @@ void initobjects(void) { addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_MIGHTY, NA, NULL); + addot(OT_MACE, "mace", "A weapon with a heavy head on a solid shaft used to bludgeon opponents.", MT_METAL, 3, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 140, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 8, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); + addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 3.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 10, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); + addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 1.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 100, NA, NA, NULL); + addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 6, 1, NULL); + addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_DEX, DX_DEXTROUS, NA, NULL); + addot(OT_SPANNER, "spanner", "A long, heavy metal wrench.", MT_METAL, 1, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 120, NA, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 4, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERNEEDDIR, B_TRUE, NA, NA, "Use your spanner in which direction"); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addot(OT_STICK, "stick", "A sturdy wooden stick.", MT_WOOD, 0.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_DAMTYPE, DT_BASH, NA, NA, NULL); + addflag(lastot->flags, F_DAM, 1, 2, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); // projectile weapons - addot(OT_SLING, "sling", "Stretchy piece of rubber for launching projectiles.", MT_RUBBER, 0.5, OC_WEAPON); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); - addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 3, NA, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); - addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); - addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL); - addot(OT_BOW, "bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 3, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); @@ -6482,14 +6747,14 @@ void initobjects(void) { addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_AVERAGE, NA, NULL); - addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 6, OC_WEAPON); + addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 5, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 7, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 9, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); - addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); + addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); addot(OT_CROSSBOWHAND, "hand crossbow", "A small one-handed crossbow. Lightweight, but less powerful than a full-sized one.", MT_WOOD, 3, OC_WEAPON); @@ -6501,14 +6766,14 @@ void initobjects(void) { addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); - addot(OT_CROSSBOW, "crossbow", "A standard crossbow. Very powerful, but needs high strength to use.", MT_WOOD, 5, OC_WEAPON); + addot(OT_LONGBOW, "longbow", "A very large (human-sized) bow, capable of firing arrows with great power.", MT_WOOD, 6, OC_WEAPON); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_FIRESPEED, 9, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 7, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_RANGE, 10, NA, NA, NULL); - addflag(lastot->flags, F_AMMOOB, OT_BOLT, NA, NA, NULL); + addflag(lastot->flags, F_AMMOOB, OT_ARROW, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, ST_STRONG, NA, NULL); addot(OT_REVOLVER, "revolver", "Basic one-handed firearm.", MT_METAL, 1, OC_WEAPON); @@ -6523,6 +6788,16 @@ void initobjects(void) { addflag(lastot->flags, F_AMMOOB, OT_BULLET, NA, NA, NULL); addflag(lastot->flags, F_AMMOOB, OT_RUBBERBULLET, NA, NA, NULL); + addot(OT_SLING, "sling", "Stretchy piece of rubber for launching projectiles.", MT_RUBBER, 0.5, OC_WEAPON); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_FIREARM, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_FIRESPEED, 3, NA, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 5, NA, NA, NULL); + addflag(lastot->flags, F_AMMOOB, OT_STONE, NA, NA, NULL); + + // holy weapons addot(OT_HANDOFGOD, "hand of god", "The ultimate power.", MT_FLESH, 0.1, OC_WEAPON); //addflag(lastot->flags, F_RARITY, H_DUNGEON, RR_UNIQUE, NA, NULL); @@ -6922,6 +7197,12 @@ int isrotting(object_t *o) { return B_FALSE; } +int isthrownmissile(object_t *o) { + if (hasflag(o->flags, F_THROWMISSILE)) { + return B_TRUE; + } + return B_FALSE; +} int isweapon(object_t *o) { //if ((o->type->obclass->id == OC_WEAPON) && hasflag(o->flags, F_DAM)) { @@ -7106,7 +7387,7 @@ lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level) { flag_t *f; lifeform_t *newlf; - where = getrandomadjcell(lf->cell, WE_EMPTY); + where = getrandomadjcell(lf->cell, WE_EMPTY, B_NOEXPAND); if (!where) return NULL; newlf = addlf(where, R_DANCINGWEAPON, level); @@ -7368,6 +7649,10 @@ object_t *moveob(object_t *src, obpile_t *dst, int howmany) { drawscreen(); } + // in case you picked up money, something which changes your AR, etc + if (dst->owner && isplayer(dst->owner)) { + statdirty = B_TRUE; + } //o = newobeffects(o); @@ -7769,7 +8054,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { msg("You can't see there!"); return B_TRUE; } - if ((f->val[1] & TR_NEEDLOF) && !haslof(lf, where, B_TRUE, &newwhere)) { + if ((f->val[1] & TR_NEEDLOF) && !haslof(lf->cell, where, B_TRUE, &newwhere)) { if (newwhere) { // update destination where = newwhere; @@ -7891,7 +8176,7 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { break; case 2: // butterflies around user willid = B_TRUE; - where = getrandomadjcell(lf->cell, WE_NOTSOLID); + where = getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND); addmonster(where, R_BUTTERFLY, B_FALSE, rnd(10,20)); if (haslos(player, where)) { msg("A swarm of butterflies appears!"); @@ -8566,13 +8851,21 @@ void quaff(lifeform_t *lf, object_t *o) { willid = B_FALSE; if (playercansee) { switch (o->type->id) { + enum ATTRIB a; case OT_POT_HEALING: case OT_POT_HEALINGMIN: - case OT_POT_RESTORATION: if (lf->hp < lf->maxhp) { willid = B_TRUE; } break; + case OT_POT_RESTORATION: + for (a = 0; a < (MAXATTS-1); a++) { + if (getattr(lf,a) < lf->baseatt[a]) { + willid = B_TRUE; + break; + } + } + break; default: willid = B_TRUE; break; @@ -8773,7 +9066,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i } break; case OT_POT_ETHEREALNESS: - dospelleffects(lf, OT_S_PASSWALL, (potblessed) ? 5 : 1, lf, NULL, NULL, potblessed, seen); + dospelleffects(lf, OT_S_PASSWALL, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); break; case OT_POT_EXPERIENCE: // gain xp! @@ -8789,16 +9082,16 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i gainxp(lf, getxpforlev(lf->level+1) - lf->xp); break; case OT_POT_GASEOUSFORM: - dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, NULL, potblessed, seen); + dospelleffects(lf, OT_S_GASEOUSFORM, (potblessed) ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); break; case OT_POT_HEALING: - dospelleffects(lf, OT_S_HEALING,potblessed ? 5 : 1, lf, NULL, NULL, potblessed, seen); + dospelleffects(lf, OT_S_HEALING,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); break; case OT_POT_HEALINGMIN: - dospelleffects(lf, OT_S_HEALINGMIN,potblessed ? 5 : 1, lf, NULL, NULL, potblessed, seen); + dospelleffects(lf, OT_S_HEALINGMIN,potblessed ? 5 : 1, lf, NULL, lf->cell, potblessed, seen); break; case OT_POT_INVIS: - dospelleffects(lf, OT_S_INVISIBILITY,potblessed ? 6 : 3, lf, NULL, NULL, potblessed, seen); + dospelleffects(lf, OT_S_INVISIBILITY,potblessed ? 6 : 3, lf, NULL, lf->cell, potblessed, seen); break; case OT_POT_INVULN: if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) { @@ -8843,13 +9136,16 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i msg("Mmm, %s oil.", buf); } break; + case OT_POT_POISON: + poison(lf, rnd(10,20), "a potion of poison"); + break; case OT_POT_POLYMORPH: if (potblessed == B_BLESSED) { // controlled polymorph - dospelleffects(lf, OT_S_POLYMORPH, 5, lf, NULL, NULL, potblessed, NULL); + dospelleffects(lf, OT_S_POLYMORPH, 5, lf, NULL, lf->cell, potblessed, NULL); } else { // random polymorph - dospelleffects(lf, OT_S_POLYMORPH, 1, lf, NULL, NULL, potblessed, NULL); + dospelleffects(lf, OT_S_POLYMORPH, 1, lf, NULL, lf->cell, potblessed, NULL); } break; case OT_POT_RESTORATION: @@ -9162,20 +9458,12 @@ int readsomething(lifeform_t *lf, object_t *o) { object_t *oo; // remove curses! for (oo = lf->pack->first ; oo ; oo = oo->next) { + // if this object is cursed if (iscursed(oo)) { + // blessed scrolls remove curse from everything you're holding. + // otherwise only equipped objects will be uncursed. if (o->blessed || isequipped(oo)) { - // announce - if (cansee(player, lf)) { - char lfname[BUFLEN]; - char obname[BUFLEN]; - getlfname(lf, lfname); - getobname(oo, obname,oo->amt); - msg("A black aura breaks away from %s%s %s.",lfname,getpossessive(lfname),noprefix(obname)); - seen = B_TRUE; - } - // uncurse it - oo->blessed = B_UNCURSED; - oo->blessknown = B_TRUE; + uncurseob(oo, &seen); } } } @@ -9206,7 +9494,7 @@ int readsomething(lifeform_t *lf, object_t *o) { addflag(lf->flags, F_CANCAST, linkspell->id, NA, NA, NULL); } } else { - if (isplayer(lf)) msg("This book is a bit too advanced for you."); + if (isplayer(lf)) msg("You cannot comprehend this book."); } } else { // manuals @@ -9635,6 +9923,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, cell_t *newloc; int db = B_TRUE; int willcatch = B_FALSE; + int announcedmiss = B_FALSE; reason = E_OK; @@ -9726,7 +10015,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (target && isdead(target)) { target = NULL; } - if (target) { + if (thrower && target) { getlfname(target, targetname); if (areallies(thrower, target) && !firearm) { willcatch = B_TRUE; @@ -9783,7 +10072,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // adjust destination location in case something is in the way. - haslof(thrower, where, LOF_NEED, &newloc); + haslof(thrower->cell, where, LOF_NEED, &newloc); if (newloc) { where = newloc; target = where->lf; @@ -9847,20 +10136,43 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, // announce if (seen) { msg("%s is repelled from %s!", obname, targetname); + announcedmiss = B_TRUE; } youhit = B_FALSE; } else if (rnd(1,100) <= acc) { youhit = B_TRUE; } - // saving throw + // cyclone shield? + if (youhit && target) { + flag_t *f; + f = lfhasflag(target, F_WINDSHIELD); + if (f) { + if (speed <= f->val[0]) { + if (seen) { + msg("%s is repelled by air currents around %s!", obname, targetname); + announcedmiss = B_TRUE; + } + youhit = B_FALSE; + } + } + } + + // saving throws if (youhit && !willcatch) { - if (skillcheck(target, SC_DODGE, 20, 0)) { + // first check to see if you can catch it + if (!lfhasflag(target, F_NOPACK) && hasbp(target, BP_HANDS) && + lfhasflag(target, F_HUMANOID) && + !isimmobile(target) && + skillcheck(target, SC_DEX, 10*speed, isblind(target) ? -15 : 0)) { + willcatch = B_TRUE; + } else if (skillcheck(target, SC_DODGE, 20, 0)) { + // then check if we dodge it... youhit = B_FALSE; } } - // doesn't matter wheter you hit or ot... + // doesn't matter wheter you hit or not... if (lfhasflag(target, F_UNDEAD) && isblessed(o)) { if (seen) { msg("%s recoils in fear!", targetname); @@ -9948,10 +10260,13 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } } else { - if (isplayer(thrower)) { - msg("Your %s misses %s.", noprefix(obname), targetname); - } else if (haslos(player, where)) { - msg("%s misses %s.", obname, targetname); + if (!announcedmiss) { + if (isplayer(thrower)) { + msg("Your %s misses %s.", noprefix(obname), targetname); + } else if (haslos(player, where)) { + msg("%s misses %s.", obname, targetname); + } + announcedmiss = B_TRUE; } } } else { // no target @@ -10016,6 +10331,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, case OT_POT_ELEMENTIMMUNE: case OT_POT_ETHEREALNESS: case OT_POT_GASEOUSFORM: + case OT_POT_POISON: case OT_POT_POLYMORPH: case OT_POT_INVIS: case OT_POT_SANCTUARY: // always make them known @@ -10556,6 +10872,43 @@ void turnon(lifeform_t *lf, object_t *o) { } +int uncurseob(object_t *o, int *seen) { + lifeform_t *lf = NULL; + + // default + if (seen) *seen = B_FALSE; + + if (o->blessed != B_CURSED) { + return B_TRUE; + } + lf = o->pile->owner; + + // announce + if (lf) { + if (cansee(player, lf)) { + char lfname[BUFLEN]; + char obname[BUFLEN]; + getlfname(lf, lfname); + getobname(o, obname,o->amt); + msg("A black aura breaks away from %s%s %s.",lfname,getpossessive(lfname),noprefix(obname)); + if (seen) *seen = B_TRUE; + } + } else { // not held + cell_t *loc = NULL; + loc = getoblocation(o); + if (haslos(player, loc)) { + char obname[BUFLEN]; + getobname(o, obname,o->amt); + msg("A black aura breaks away from %s.",obname); + if (seen) *seen = B_TRUE; + } + } + // uncurse it + o->blessed = B_UNCURSED; + o->blessknown = B_TRUE; + return B_FALSE; +} + // returns charges remaining, -1 if object doesn't have the flag int usecharge(object_t *o) { flag_t *f; diff --git a/objects.h b/objects.h index 5cb98c1..d33c2d3 100644 --- a/objects.h +++ b/objects.h @@ -16,6 +16,7 @@ obpile_t *addobpile(lifeform_t *owner, cell_t *where); objecttype_t *addot(int id, char *name, char *description, int material, float weight, int obclassid); void adjustdammaterial(unsigned int *dam, enum DAMTYPE damtype, enum MATERIAL mat); void adjustdamob(object_t *o, unsigned int *dam, enum DAMTYPE damtype); +int adjustshieldpenalty(lifeform_t *lf, float amt); //void adjustprice(objecttype_t *ot, float *price ); void appendinscription(object_t *o, char *text); void applyobmod(object_t *o, obmod_t *om); @@ -77,6 +78,7 @@ int getnumshards(object_t *o); int getnutritionbase(object_t *o); int getnutrition(object_t *o); char *getobdesc(object_t *o, char *buf); +char *getobequipinfo(object_t *o, char *buf); char *getobextrainfo(object_t *o, char *buf); cell_t *getoblocation(object_t *o); char *getobname(object_t *o, char *buf, int count); @@ -137,6 +139,7 @@ int ispourable(object_t *o); int ispushable(object_t *o); int isreadable(object_t *o); int isrotting(object_t *o); +int isthrownmissile(object_t *o); int isweapon(object_t *o); int iswearable(object_t *o); void killmaterial(material_t *m); @@ -181,6 +184,7 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, void timeeffectsob(object_t *o); void turnoff(lifeform_t *lf, object_t *o); void turnon(lifeform_t *lf, object_t *o); +int uncurseob(object_t *o, int *seen); int usecharge(object_t *o); int validateobs(void); int willshatter(enum MATERIAL mat); diff --git a/save.c b/save.c index 121448b..e64747b 100644 --- a/save.c +++ b/save.c @@ -93,8 +93,10 @@ int loadflagpile(FILE *f, flagpile_t *fp) { int loadknowledge(FILE *f) { int db = B_FALSE; char buf[BUFLEN]; + char line[BUFLEN]; int otid,known; char hiddenname[BUFLEN]; + char *p,*dummy; if (db) dblog("--> Loading knowledge...\n"); fscanf(f, "startknowledge\n"); @@ -102,7 +104,14 @@ int loadknowledge(FILE *f) { buf[strlen(buf)-1] = '\0'; // strip newline while (strcmp(buf, "endknowledge")) { - sscanf(buf, "%d^%s^%d",&otid, hiddenname, &known); + //sscanf(buf, "%d^%s^%d",&otid, hiddenname, &known); + strcpy(line, buf); + p = strtok_r(line, "^", &dummy); + otid = atoi(p); + p = strtok_r(NULL, "^", &dummy); + strcpy(hiddenname, p); + p = strtok_r(NULL, "^", &dummy); + known = atoi(p); addknowledge(otid, hiddenname, known); // get next line fgets(buf, BUFLEN, f); diff --git a/spell.c b/spell.c index 670d840..22b53c3 100644 --- a/spell.c +++ b/spell.c @@ -120,7 +120,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (!target) { if (isplayer(user)) msg("There is nobody there!"); return TRUE; - } else if (!haslof(user, targcell, LOF_NEED, NULL)) { + } else if (!haslof(user->cell, targcell, LOF_NEED, NULL)) { if (isplayer(user)) msg("Your path there is blocked!"); return TRUE; } @@ -319,7 +319,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // TODO: if jumper is smaller, move them out of the way instead // move them out of the way - c = getrandomadjcell(victim->cell, WE_EMPTY); + c = getrandomadjcell(victim->cell, WE_EMPTY, B_NOEXPAND); // nowhere to move? move to player's cell! if (!c) { c = user->cell; @@ -405,7 +405,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_TRUE; } - howlong = 5; + howlong = 2; // +2 for each athletics skill level slev = getskill(user, SK_ATHLETICS); if (slev > PR_INEPT) { @@ -436,6 +436,22 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // cause ongoing pain for 2 turns addtempflag(target->flags, F_PAIN, DT_ACID, NA, NA, damstr, 2); taketime(user, getactspeed(user)); + } else if (abilid == OT_A_POLYREVERT) { + flag_t *f; + if (!target) target = user; + + // take time + taketime(user, getactspeed(user)); + + f = lfhasflag(target, F_ORIGRACE); + if (!f) { + if (isplayer(user)) nothinghappens(); + return B_FALSE; + } + + // this call will also remove this ability... + setrace(user, f->val[0]); + } else if (abilid == OT_A_LEARN) { skill_t *sk; char ch = 'a'; @@ -456,6 +472,10 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef sprintf(buf, "%s",getskilllevelname(i)); addchoice(&prompt, ch++, buf, buf, NULL); } + if (prompt.nchoices <= 0) { + msg("You have already mastered this skill!"); + return B_TRUE; + } getchoice(&prompt); while (strcmp(getskilllevelname(getskill(user, sk->id)), prompt.choice[prompt.selection].text)) { @@ -1067,7 +1087,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { targcell = getcellat(caster->cell->map, x,y); if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell, B_FALSE, NULL)) { + if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); @@ -1130,7 +1150,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else { // get random adjacent cell - targcell = getrandomadjcell(caster->cell, WE_EMPTY); + targcell = getrandomadjcell(caster->cell, WE_EMPTY, B_ALLOWEXPAND); } } @@ -1278,7 +1298,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int howlong,radius; howlong = getspellduration(10,20,blessed) + (power*2); radius = power * 10; - addtempflag(target->flags, F_DETECTLIFE, 10, NA, NA, NULL, howlong); + addtempflag(target->flags, F_DETECTLIFE, 10, (power >= 5) ? B_TRUE : NA, NA, NULL, howlong); } else { // monsters can't use this } @@ -1492,7 +1512,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { targcell = getcellat(caster->cell->map, x,y); if (targcell && (getcelldist(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell, B_FALSE, NULL)) { + if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); @@ -1578,6 +1598,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (o) { setobcreatedby(o, caster); } + if (c->lf) { + losehp(c->lf, rolldie(power,4), DT_FIRE, caster, "a fireball"); + } } } for (dir = DC_NE; dir <= DC_NW; dir += 2) { @@ -1588,6 +1611,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (o) { setobcreatedby(o, caster); } + if (c->lf) { + int ndice; + ndice = power / 2; if (ndice < 1) ndice = 1; + losehp(c->lf, rolldie(ndice,4), DT_FIRE, caster, "a fireball"); + } } } for (dir = D_N; dir <= D_W; dir++) { @@ -1600,6 +1628,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (o) { setobcreatedby(o, caster); } + if (c->lf) { + int ndice; + ndice = power / 2; if (ndice < 1) ndice = 1; + losehp(c->lf, rolldie(ndice,2), DT_FIRE, caster, "a fireball"); + } } } } @@ -1657,7 +1690,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // announce if (isplayer(caster) || cansee(player, caster)) { - msg("%s emit%s a blast of fire!",castername,isplayer(caster) ? "" : "s"); + msg("%s emit%s a %sblast of fire!",castername,isplayer(caster) ? "" : "s", + (power >= 5) ? "huge " : ""); if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -1667,7 +1701,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ for (x = caster->cell->x - range ; x <= caster->cell->x + range; x++) { targcell = getcellat(caster->cell->map, x,y); if (targcell && (getcelldistorth(caster->cell, targcell) <= range)) { - if (targcell->lf && (targcell->lf != caster) && haslof(caster, targcell, B_FALSE, NULL)) { + if (targcell->lf && (targcell->lf != caster) && haslof(caster->cell, targcell, B_FALSE, NULL)) { char lfname[BUFLEN]; // automatic hit getlfname(targcell->lf, lfname); @@ -1862,9 +1896,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (isplayer(caster) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } - // if this is the player, remember the original race and job... + // remember the original race addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL); - // polymorph will be temporary... + // polymorph is always will be temporary addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, 10); setrace(target, R_GASCLOUD); } @@ -2244,7 +2278,20 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ sprintf(buf, "Whose mind will you scan?"); where = askcoords(buf, TT_MONSTER); if (where && haslos(caster, where) && haslf(where)) { - showlfstats(where->lf, B_TRUE); + char targname[BUFLEN]; + lifeform_t *oldplayer; + // temporarily change player pointer... + oldplayer = player; + player = where->lf; + + // + getlfname(where->lf, targname); + sprintf(buf, "Mindscanning %s, ESC to quit.", targname); + doexplain(buf); + + // restore player pointer + player = oldplayer; + //showlfstats(where->lf, B_TRUE); } else { failed = B_TRUE; } @@ -2419,6 +2466,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } getlfname(target, targname); + // warn if it can't do magic + if (lfhasflag(target, F_NOSPELLS)) { + int cancel = B_FALSE; + if (isplayer(caster)) { + char buf[BUFLEN]; + char ch; + sprintf(buf, "You may be stuck in %s%s body - proceed?", targname, + getpossessive(targname)); + ch = askchar(buf, "yn", "n", B_TRUE); + if (ch != 'y') { + cancel = B_TRUE; + } + } else { + cancel = B_TRUE; + } + if (cancel) { + if (isplayer(caster)) msg("Cancelled."); + return B_TRUE; + } + } + // saving throw.... if (skillcheck(target, SC_RESISTMAG, 20 + power*2, 0)) { if (isplayer(caster) && cansee(player, target)) { @@ -2473,7 +2541,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ targcell = caster->cell; target = caster; - f = addtempflag(caster->flags, F_ARBOOST, power*3, NA, NA, NULL, FROMSPELL); + f = addtempflag(caster->flags, F_MAGICARMOUR, power*4, NA, NA, "psychic barrier", FROMSPELL); f->obfrom = spellid; } else if (spellid == OT_S_PULL) { if (!validatespellcell(caster, &targcell,TT_MONSTER, B_TRUE, LOF_WALLSTOP, spellid, power)) return B_TRUE; @@ -2628,7 +2696,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *srcportal,*dstportal; // find adjacent cell for portal - srccell = getrandomadjcell(caster->cell, WE_NOTSOLID); + srccell = getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND); if (!srccell) { fizzle(caster); return B_FALSE; @@ -2752,22 +2820,32 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_KNOCK) { object_t *o; if (!validatespellcell(caster, &targcell,TT_DOOR, B_TRUE, LOF_DONTNEED, spellid, power)) return B_TRUE; - o = hasobwithflag(targcell->obpile, F_DOOR); - if (o) { - int dooropen; - isdoor(o, &dooropen); // just check whether it's open, we know it's a door - if (dooropen) { - fizzle(caster); - } else { - if (haslos(player, targcell)) { - getobname(o, buf, o->amt); - msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf); - } - takedamage(o, 999, DT_DIRECT); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } + + target = targcell->lf; + + // high powered knock can knock back monsters + if (target && (power >= 7)) { + int dir; + dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); + knockback(target, dir, 2, caster); } else { - fizzle(caster); + o = hasobwithflag(targcell->obpile, F_DOOR); + if (o) { + int dooropen; + isdoor(o, &dooropen); // just check whether it's open, we know it's a door + if (dooropen) { + fizzle(caster); + } else { + if (haslos(player, targcell)) { + getobname(o, buf, o->amt); + msg("%s %s!",isplayer(caster) ? "You blast" : "Something blasts", buf); + } + takedamage(o, 999, DT_DIRECT); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + } else { + fizzle(caster); + } } } else if (spellid == OT_S_LEVITATION) { flag_t *f; @@ -2965,6 +3043,12 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } + if (lfhasflag(caster, F_CONTROL)) { + if (power < 5) { + power = 5; + } + } + if (isplayer(caster) && (power >= 5)) { if (isplayer(target)) { askstring("What will you become", '?', buf, BUFLEN, NULL); @@ -2987,7 +3071,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // random race, but not the same! r = target->race; while (r == target->race) { - r = getrandomrace(NULL); + r = getrandomrace(NULL, 0); } } @@ -2997,20 +3081,34 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (r) { + //int rememberorig = B_FALSE; getlfname(target, buf); // if this is the player, remember the original race and job... - if (isplayer(target) && !hasflag(target->flags, F_ORIGRACE)) { - int howlong; + if (!hasflag(target->flags, F_ORIGRACE)) { + // remember the original race addflag(target->flags, F_ORIGRACE, target->race->id, NA, NA, NULL); + } + + if (isplayer(target)) { + int howlong; // polymorph will be temporary... howlong = rnd(20,50); addtempflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL, howlong); + } else { + // permenant + addflag(target->flags, F_POLYMORPHED, B_TRUE, NA, NA, NULL); } + // become the new race! setrace(target, r->id); + // if someone cast the spell at themself, they can change back at will. + if (target == caster) { + addflag(target->flags, F_CANWILL, OT_A_POLYREVERT, NA, NA, NULL); + } + if (haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -3092,7 +3190,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = caster; - if (skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { + if (getmr(target) && skillcheck(target, SC_RESISTMAG, 20 + power, 0)) { if (isplayer(target)) { msg("You flicker."); if (seenbyplayer) *seenbyplayer = B_TRUE; @@ -3105,6 +3203,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } + if (lfhasflag(caster, F_CONTROL)) { + if (power < 5) { + power = 5; + } else if (power < 8) { + power = 8; + } + } + if ((power < 5) || !isplayer(caster)) { // random while (!c || c->type->solid || haslf(c)) { @@ -3386,6 +3492,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else { fizzle(caster); } + } else if (spellid == OT_S_WINDSHIELD) { + flag_t *f; + // always targetted at caster + targcell = caster->cell; + target = caster; + + f = addtempflag(caster->flags, F_WINDSHIELD, power, NA, NA, NULL, FROMSPELL); + f->obfrom = spellid; } else if ((spellid == OT_S_WISH) || (spellid == OT_S_GIFT)) { object_t *o; if (isplayer(caster)) { @@ -3424,7 +3538,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (hasflag(o->flags, F_IMPASSABLE)) { cell_t *newloc; // if so, don't put it where the player is! - newloc = getrandomadjcell(target->cell, WE_NOTSOLID); + newloc = getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND); o = relinkob(o, newloc->obpile); } if (o) { @@ -3561,15 +3675,9 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf) { strcat(buf, roman(power)); } - if (spellid == OT_S_TELEPORT) { - if (power >= 8) { - strcat(buf, "(fullctrl)"); - } else if (power >= 5) { - strcat(buf, "(semictrl)"); - } - } else if (spellid == OT_S_POLYMORPH) { + if (spellid == OT_S_DETECTLIFE) { if (power >= 5) { - strcat(buf, "(ctrl)"); + strcat(buf, "(enhanced)"); } } else if (spellid == OT_S_CREATEMONSTER) { if (power >= 7) { @@ -3577,12 +3685,26 @@ char *getspellname(enum OBTYPE spellid, lifeform_t *lf, char *buf) { } else if (power >= 5) { strcat(buf, "(semictrl)"); } + } else if (spellid == OT_S_KNOCK) { + if (power >= 7) { + strcat(buf, "(enhanced)"); + } } else if (spellid == OT_S_LIGHT) { if (power >= 8) { strcat(buf, "(perm,ctrl)"); } else if (power >= 3) { strcat(buf, "(ctrl)"); } + } else if (spellid == OT_S_POLYMORPH) { + if (power >= 5) { + strcat(buf, "(ctrl)"); + } + } else if (spellid == OT_S_TELEPORT) { + if (power >= 8) { + strcat(buf, "(fullctrl)"); + } else if (power >= 5) { + strcat(buf, "(semictrl)"); + } } return buf; } @@ -3661,7 +3783,7 @@ int getspellpower(lifeform_t *lf, enum OBTYPE spellid) { // specialised school skill - apply this AFTER dividing by spell level schoolskill = getskill(lf, getschoolskill(getspellschool(spellid))); if (schoolskill != PR_INEPT) { - power += schoolskill; + power += ((float)schoolskill * 1.5); } // enforce maximum @@ -3850,7 +3972,7 @@ cell_t *validatespellcell(lifeform_t *caster, cell_t **targcell, int targtype, i } // line of fire interrupted? - if (where && needlof && !haslof(caster, where, needlof, &newwhere)) { + if (where && needlof && !haslof(caster->cell, where, needlof, &newwhere)) { if (newwhere) { if (isplayer(caster)) { // warn! diff --git a/text.c b/text.c index a5bbd6d..8298521 100644 --- a/text.c +++ b/text.c @@ -9,6 +9,14 @@ extern long curtime; + +int needan(char *text) { + if (isvowel(tolower(text[0]))) { + return B_TRUE; + } + return B_FALSE; +} + char *capitalise(char *text) { if (strlen(text) > 0) { text[0] = toupper(text[0]); @@ -72,6 +80,21 @@ char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dic return dicebuf; } +char *getattrabbrev(enum ATTRIB att) { + switch (att) { + case A_NONE: + return "??"; + case A_STR: + return "St"; + case A_IQ: + return "Iq"; + case A_DEX: + return "Dx"; + case A_CON: + return "Cn"; + } + return "??"; +} char *getattrname(enum ATTRIB att) { switch (att) { diff --git a/text.h b/text.h index 10593f7..dd72a23 100644 --- a/text.h +++ b/text.h @@ -1,8 +1,10 @@ #include "defs.h" +int needan(char *text); char *capitalise(char *text); char *capitaliseall(char *text); char *dicetotext(int ndice, int nsides, int bonus, int *min, int *max, char *dicebuf, char *minmaxbuf); +char *getattrabbrev(enum ATTRIB att); char *getattrname(enum ATTRIB att); char *getpossessive(char *text); char *getsizetext(enum LFSIZE sz);