diff --git a/ai.c b/ai.c index 5364e09..bd5f578 100644 --- a/ai.c +++ b/ai.c @@ -429,7 +429,53 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi } if (spelllf) *spelllf = NULL; if (spellob) *spellob = NULL; - + } else if (spelltype->id == OT_A_JUMP) { + cell_t *cell[MAXCANDIDATES],*c; + cell_t *poss[MAXCANDIDATES]; + int ncells,i,bestdist,nposs; + + if (purpose == F_AICASTTOATTACK) { + bestdist = 99; + } else { + bestdist = -99; + } + getradiuscells(lf->cell, 2, DT_COMPASS, B_TRUE, LOF_WALLSTOP, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + int disttovictim; + c = cell[i]; + if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { + continue; + } + disttovictim = getcelldist(victim->cell, c); + if (purpose == F_AICASTTOATTACK) { + // get closest cell to victim + if (disttovictim < bestdist) { + bestdist = disttovictim; + } + } else { + // get furthest cell from victim + if (disttovictim > bestdist) { + bestdist = disttovictim; + } + } + } + // now get all possible cells... + nposs = 0; + for (i = 0; i < ncells; i++) { + int disttovictim; + c = cell[i]; + if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { + continue; + } + disttovictim = getcelldist(victim->cell, c); + if (disttovictim == bestdist) { + poss[nposs++] = c; + } + } + // cast spell at one of the cells we found. + // we should ALWAYS have at least one cell, because aispellok() + // will check this. + if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; } else if (spelltype->id == OT_S_TELEKINESIS) { float maxweight; object_t *poss[MAXPILEOBS]; @@ -592,6 +638,7 @@ int ai_bored(lifeform_t *lf, lifeform_t *master, int icanattack) { flag_t *retflag[MAXCANDIDATES]; int nretflags = 0; flag_t *f; + if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; // not attacking anyone in particular if (db) dblog(".oO { i do not have a target or can't move towards it. }"); @@ -1281,7 +1328,7 @@ int aimovetolf(lifeform_t *lf, lifeform_t *target, int wantattack) { else spellchance = 30; // some attacks can always happen - if (cancast(lf, OT_A_THRUST, NULL) && (dist == 2)) { + if (cancast(lf, OT_A_THRUST, NULL) && (dist == 2) && haslof(lf->cell, target->cell, LOF_NEED, NULL)) { spellchance = 100; } @@ -1962,6 +2009,29 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } } } + } else if (ot->id == OT_A_JUMP) { + cell_t *cell[MAXCANDIDATES],*c; + int ncells,i; + getradiuscells(lf->cell, 2, DT_COMPASS, B_TRUE, LOF_WALLSTOP, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + c = cell[i]; + if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { + continue; + } + if (purpose == F_AICASTTOATTACK) { + // is this cell closer to the victim? + if (getcelldist(victim->cell, c) < getcelldist(victim->cell, lf->cell)) { + ok = B_TRUE; + break; + } + } else { + // is this cell further away from the victim? + if (getcelldist(victim->cell, c) > getcelldist(victim->cell, lf->cell)) { + ok = B_TRUE; + break; + } + } + } } else if (ot->id == OT_S_PYROMANIA) { int i; for (i = 0; i < lf->nlos; i++) { @@ -2084,7 +2154,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } if (ot->id == OT_A_SHIELDBASH) { - if (!getshield(lf)) { + if (!getshield(lf, DT_ALL)) { specificcheckok = B_FALSE; } } diff --git a/attack.c b/attack.c index e10ab1e..11255f6 100644 --- a/attack.c +++ b/attack.c @@ -817,7 +817,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } if (ndam > 0) { - object_t *shield = NULL; flag_t *f; for (i = 0; i < ndam; i++) { int reduceamt = 0; @@ -853,31 +852,17 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } if (i == 0) { + int difficulty; + char attackname[BUFLEN]; if (lfhasflag(lf, F_HOLYAURA) && isvulnto(victim->flags, DT_HOLY, B_FALSE)) { damtype[i] = DT_HOLY; } // blocked by defender's shield? - shield = getshield(victim); - if (shield && cansee(victim, lf)) { - int difficulty; - difficulty = 25 + ((gethitdice(lf) - gethitdice(victim))*3 ); - if (skillcheck(victim, SC_SHIELDBLOCK, difficulty, 0)) { - char shname[BUFLEN]; - // announce - real_getobname(shield, shname, 1, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); - if (isplayer(lf)) { // player is atatcking - msg("%s blocks your attack with %s.", victimname, shname); - } else if (cansee(player, lf) || cansee(player, victim)) { // monster is attacking - msg("%s block%s %s%s attack with %s.", victimname, isplayer(victim) ? "" : "s", - attackername, getpossessive(attackername), - shname); - } - // apply all damage to shield - takedamage(shield, dam[i], damtype[i]); - practice(victim, SK_SHIELDS, 1); - blocked = B_TRUE; - break; // stop processing damage now. - } + sprintf(attackname, "%s%s attack", attackername, getpossessive(attackername)); + difficulty = 25 + ((gethitdice(lf) - gethitdice(victim))*3 ); + if (check_for_block(lf, victim, dam[i], damtype[i], difficulty, attackname)) { + blocked = B_TRUE; + break; // stop processing damage now. } } @@ -1416,6 +1401,43 @@ enum DAMTYPE basedamagetype(enum DAMTYPE dt) { return dt; } +// returns B_TRUE if victim blocked lf's attack +int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname) { + object_t *shield[MAXPILEOBS]; + int checkmod[MAXPILEOBS]; + int nshields,i; + + if (lf && !cansee(victim, lf)) return B_FALSE; + + // get all usable shields for this damtype + getallshields(victim, damtype, shield, checkmod, &nshields); + for (i = 0; i < nshields; i++) { + // did we block with this object? + if (skillcheck(victim, SC_SHIELDBLOCK, difficulty, checkmod[i])) { + char shname[BUFLEN]; + char victimname[BUFLEN]; + getlfname(victim, victimname); + // announce + real_getobname(shield[i], shname, 1, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); + if (isplayer(lf)) { // player is atatcking + msg("%s blocks %s with %s.", victimname, attackname, shname); + } else if (cansee(player, lf) || cansee(player, victim)) { // monster is attacking + msg("%s block%s %s with %s.", victimname, isplayer(victim) ? "" : "s", + attackname, shname); + } + if (isshield(shield[i])) { + // apply all damage to shield. + // (blocking with weapons won't damage them) + takedamage(shield[i], dam, damtype); + practice(victim, SK_SHIELDS, 1); + } + // stop checking. + return B_TRUE; + } + } + return B_FALSE; +} + void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int dam, enum DAMTYPE damtype) { object_t *o,*armour; int protected = B_FALSE; diff --git a/attack.h b/attack.h index 2b76133..f151ec2 100644 --- a/attack.h +++ b/attack.h @@ -6,7 +6,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force); int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag); int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag); enum DAMTYPE basedamagetype(enum DAMTYPE dt); -void confereffects(flagpile_t *fp, lifeform_t *victim); +int check_for_block(lifeform_t *lf, lifeform_t *victim, int dam, enum DAMTYPE damtype, int difficulty, char *attackname); +//void confereffects(flagpile_t *fp, lifeform_t *victim); void criticalhit(lifeform_t *lf, lifeform_t *victim, enum BODYPART hitpos, int dam, enum DAMTYPE damtype); int damtypecausesbleed(enum DAMTYPE dt); int damtypecausescriteffects(enum DAMTYPE dt); diff --git a/data.c b/data.c index 79d67a3..219cd30 100644 --- a/data.c +++ b/data.c @@ -86,7 +86,6 @@ void initcommands(void) { addcommand(CMD_MEMMAGIC, 'M', "Memorise a hotkey for magic or abilities."); addcommand(CMD_OFFER, 'O', "Offer a sacrifice to the gods."); addcommand(CMD_OPERATE, 'o', "Operate a tool/wand/device, or fill a flask."); - addcommand(CMD_PICKLOCK, 'p', "Pick a lock."); addcommand(CMD_POUR, 'P', "Pour a potion onto something."); addcommand(CMD_QUAFF, 'q', "Quaff (drink) a potion."); addcommand(CMD_READ, 'r', "Read a scroll/book."); @@ -3644,6 +3643,8 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_JUMP, "jump", "You can leap large distances.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_STAMCOST, 3, NA, NA, NULL); addot(OT_A_POLYREVERT, "revertform", "Revert to your original form.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); @@ -5415,6 +5416,7 @@ void initobjects(void) { addot(OT_BUCKLER, "buckler", "A small, unobtrusive wooden shield.", MT_WOOD, 3.00, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); @@ -5422,12 +5424,14 @@ void initobjects(void) { addot(OT_SHIELDHIDE, "hide shield", "A small shield constructed out of animal skin.", MT_LEATHER, 2.00, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); @@ -5440,6 +5444,7 @@ void initobjects(void) { addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL); addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); @@ -5670,6 +5675,13 @@ void initobjects(void) { addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addot(OT_TONGUE, "tongue", "tongue object", MT_FLESH, 0, OC_WEAPON, SZ_TINY); + addflag(lastot->flags, F_DAM, DT_PIERCE, 10, NA, NULL); + addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 110, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); + addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); + addot(OT_ZAPPER, "zapper", "zapper object", MT_NOTHING, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_ELECTRIC, 2, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); @@ -5827,14 +5839,14 @@ void initobjects(void) { addot(OT_AXE, "axe", "A short pole with a heavy, wedge-shaped blade for chopping.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, 6, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + 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, 9, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addot(OT_BATTLEAXE, "battleaxe", "An large axe specifically designed for combat.", MT_METAL, 8, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, 11, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + 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, 13, 10, NULL); addot(OT_GREATAXE, "greataxe", "An enormous axe made designed for combat.", MT_METAL, 10, OC_WEAPON, SZ_MEDIUM); @@ -5849,7 +5861,7 @@ void initobjects(void) { addot(OT_HANDAXE, "hand axe", "A fast one-handed axe, ideal for throwing.", MT_METAL, 2.5, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, 7, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_MISSILEDAM, 5, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_AXES, NA, NA, NULL); @@ -5858,7 +5870,7 @@ void initobjects(void) { addot(OT_HATCHET, "hatchet", "Similar to a handaxe but weighted at the head. A fast one-handed axe, ideal for throwing.", MT_METAL, 4, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, 8, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 70, 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, 8, 5, NULL); @@ -5866,13 +5878,14 @@ void initobjects(void) { addot(OT_WARAXE, "war axe", "An axe made for combat.", MT_METAL, 7, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_CHOP, 12, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 85, NA, NA, NULL); + 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, 11, 10, NULL); // short blades addot(OT_COMBATKNIFE, "combat knife", "A sharp knife designed for military use.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 65, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 5, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -5883,13 +5896,16 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL); addot(OT_CUTLASS, "cutlass", "An accurate, light-weight pirate blade.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 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_AGI, 8, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_DAGGER, "dagger", "A short stabbing weapon with a pointed blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 4, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -5902,12 +5918,14 @@ void initobjects(void) { addflag(lastot->flags, F_CANBEDIFFMAT, MT_BONE, 10, NA, NULL); addot(OT_FORK, "fork", "A common kitchen fork.", MT_METAL, 0.2, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 2, NA, NULL); addflag(lastot->flags, F_ACCURACY, 65, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 2, 2, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addot(OT_KNIFE, "knife", "A moderately sharp stabbing tool.", MT_METAL, 0.5, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 3, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -5923,33 +5941,30 @@ void initobjects(void) { addflag(lastot->flags, F_CRITCHANCE, 15, NA, NA, NULL); addot(OT_ORNDAGGER, "ornamental dagger", "This dagger is pretty, but not particularly effective.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 3, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, 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, 3.0, OC_WEAPON, SZ_MEDIUM); + addot(OT_QUICKBLADE, "quickblade", "A short blade of exceptional quality and balance, it allows its bearar to attack faster than would seem possible.", MT_METAL, 3.0, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 73, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 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_CRITCHANCE, 2, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_RAPIER, "rapier", "A long, narrow French sword lacking a cutting edge. Made for stabbing.", MT_METAL, 3.5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 7, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 75, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 6, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL); - addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1.5, OC_WEAPON, SZ_SMALL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 81, NA, NULL); - addflag(lastot->flags, F_DAM, DT_PIERCE, 4, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DISARMLF, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_AGI, 10, 15, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_PIERCE, NA, NA, NULL); addot(OT_SHORTSWORD, "gladius", "A short gladiator blade. Designed for stabbing rather than slashing.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, 6, NA, NULL); @@ -5958,14 +5973,17 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 6, 5, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_SICKLE, "sickle", "A hand-held agricultural tool with a curved blade.", MT_METAL, 1, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 6, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 2, NA, NA, NULL); addot(OT_STEAKKNIFE, "steak knife", "A common kitchen knife.", MT_METAL, 0.2, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 50, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 2, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_THROWMISSILE, B_TRUE, NA, NA, NULL); @@ -6002,14 +6020,6 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 15, 15, NULL); addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL); - addot(OT_KATANA, "katana", "A long, finely balanced blade. Less raw power then a standard longsword, but its weight gives it a higher critical chance.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); - addflag(lastot->flags, F_DAM, DT_SLASH, 6, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_AGI, 12, 15, NULL); - addflag(lastot->flags, F_CRITCHANCE, 10, NA, NA, NULL); - addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); addot(OT_LONGSWORD, "longsword", "Standard issue long slashing weapon.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 9, NA, NULL); @@ -6018,13 +6028,16 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 10, 3, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_ORNSWORD, "ornamental sword", "A gleaming (but quite blunt) blade.", MT_METAL, 6, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastot->flags, F_SHINY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 5, NA, NULL); addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); - addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 5, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); + addot(OT_SCIMITAR, "scimitar", "A fast, sharp, curved blade.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 90, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 8, NA, NULL); @@ -6032,6 +6045,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_LONGBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 8, 3, NULL); addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); // polearms addot(OT_GLAIVE, "glaive", "A single-edged blade attached to a long pole.", MT_METAL, 10, OC_WEAPON, SZ_HUMAN); @@ -6116,12 +6130,12 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_POLEARMS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 11, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); // staves addot(OT_QUARTERSTAFF, "quarterstaff", "A long, stout pole.", MT_WOOD, 4, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 8, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_NEEDSSPACE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -6129,6 +6143,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_AGI, 10, 15, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_BAMBOOSTAFF, "bamboo staff", "A long hard pole made from bamboo.", MT_WOOD, 3, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); @@ -6140,10 +6155,10 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_AGI, 12, 15, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_BLADEDSTAFF, "bladed staff", "A long wooden pole with blades on either end.", MT_WOOD, 5, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_SLASH, 12, NA, NULL); addflag(lastot->flags, F_NEEDSSPACE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); @@ -6152,6 +6167,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_AGI, 15, 15, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_IRONSTAFF, "iron staff", "A long, stout metal pole.", MT_METAL, 8, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); @@ -6165,6 +6181,8 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_AGI, 12, 10, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_BASH, NA, NA, NULL); addot(OT_WIZARDSTAFF, "neophyte staff", "A twisted branch of wood.", MT_DRAGONWOOD, 4, OC_WEAPON, SZ_HUMAN); addflag(lastot->flags, F_GLYPH, C_BROWN, ')', NA, NULL); @@ -6250,6 +6268,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 10, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 110, NA, NA, NULL); addot(OT_FLAIL, "flail", "A flexible chain attached to a heavy weight.", MT_METAL, 9, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 8, NA, NULL); @@ -6258,6 +6277,7 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 10, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 10, 5, NULL); addflag(lastot->flags, F_CRITCHANCE, 5, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 125, NA, NA, NULL); addot(OT_FLAILHEAVY, "heavy flail", "A flexible chain attached to a very heavy weight.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 115, NA, NA, NULL); @@ -6267,9 +6287,10 @@ void initobjects(void) { addflag(lastot->flags, F_ATTREQ, A_STR, 14, 10, NULL); addflag(lastot->flags, F_ATTREQ, A_AGI, 10, 5, NULL); addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 125, NA, NA, NULL); addot(OT_GREATCLUB, "great club", "An enormous, very heavy, blunt instrument to hit things with.", MT_STONE, 15, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); - addflag(lastot->flags, F_OBATTACKDELAY, 220, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 200, NA, NA, NULL); addflag(lastot->flags, F_DAM, DT_BASH, 15, NA, NULL); addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); addflag(lastot->flags, F_TWOHANDED, B_TRUE, NA, NA, NULL); @@ -6282,6 +6303,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 12, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 7, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 125, NA, NA, NULL); addot(OT_MORNINGSTAR, "morningstar", "A heavy, spiked mace.", MT_METAL, 12, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); @@ -6291,14 +6313,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 13, 10, NULL); addflag(lastot->flags, F_CRITCHANCE, 8, NA, NA, NULL); - addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short or rope. Good for disarming.", MT_WOOD, 4.5, OC_WEAPON, SZ_MEDIUM); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); - addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DISARMLF, NA, NULL); - addflag(lastot->flags, F_DAM, DT_BASH, 7, NA, NULL); - addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); - addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); - addflag(lastot->flags, F_ATTREQ, A_AGI, 13, 15, NULL); - addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL); + addflag(lastot->flags, F_OBATTACKDELAY, 150, NA, NA, NULL); addot(OT_SPANNER, "spanner", "A long, heavy metal wrench.", MT_METAL, 1, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "It makes metalwork easier."); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -6313,6 +6328,7 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_BASH, 5, NA, NULL); addflag(lastot->flags, F_ACCURACY, 90, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_CLUBS, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); addot(OT_STICK, "stick", "A sturdy wooden stick. It's brown and sticky.", MT_WOOD, 0.5, OC_WEAPON, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); @@ -6323,6 +6339,35 @@ void initobjects(void) { addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RODSHAPED, B_TRUE, NA, NA, NULL); + // exotic weapons + addot(OT_KATANA, "katana", "A long, finely balanced blade. Less raw power then a standard longsword, but its weight gives it a higher critical chance.", MT_METAL, 4, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_DAM, DT_SLASH, 6, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 80, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_AGI, 12, 15, NULL); + addflag(lastot->flags, F_CRITCHANCE, 10, NA, NA, NULL); + addflag(lastot->flags, F_CANBEDIFFMAT, MT_SILVER, 5, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_PIERCE, NA, NA, NULL); + addot(OT_NUNCHAKU, "nunchaku", "Two stout sticks connected with a short chain. Good for disarming.", MT_WOOD, 4.5, OC_WEAPON, SZ_MEDIUM); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DISARMLF, NA, NULL); + addflag(lastot->flags, F_DAM, DT_BASH, 7, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 75, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_AGI, 13, 15, NULL); + addflag(lastot->flags, F_CRITCHANCE, 3, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); + addot(OT_SAI, "sai", "A dagger with two long prongs on either side, made to trap opponents' weapons.", MT_METAL, 1.5, OC_WEAPON, SZ_SMALL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 81, NA, NULL); + addflag(lastot->flags, F_DAM, DT_PIERCE, 4, NA, NULL); + addflag(lastot->flags, F_EQUIPCONFER, F_CANWILL, OT_A_DISARMLF, NA, NULL); + addflag(lastot->flags, F_ACCURACY, 70, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_EXOTICWEPS, NA, NA, NULL); + addflag(lastot->flags, F_ATTREQ, A_AGI, 10, 15, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_SLASH, NA, NA, NULL); + // projectile weapons addot(OT_BOW, "short bow", "A weapon which projects arrows via its elasticity.", MT_WOOD, 5, OC_WEAPON, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, NULL); @@ -6426,6 +6471,7 @@ void initobjects(void) { addot(OT_ICESHIELD, "ice crystal shield", "A summoned shield made of ice crystals.", MT_ICE, 0, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 5, 5, NA, NULL); // will be replaced when summoned @@ -8217,7 +8263,7 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addrace(R_OOZEGREY, "grey ooze", 10, 'j', C_GREY, MT_SLIME, RC_SLIME, "Exactly what it sounds like - a small lump of grey ooze. Grey, acidic ooze."); + addrace(R_OOZEGREY, "green ooze", 10, 'j', C_GREEN, MT_SLIME, RC_SLIME, "Exactly what it sounds like - a small lump of green ooze. Green, acidic ooze."); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "puddle of slime"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); @@ -8915,6 +8961,32 @@ void initrace(void) { addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addrace(R_FROG, "impaler frog", 10, ';', C_BOLDGREEN, MT_FLESH, RC_ANIMAL, "As their name implies, impaler frogs are dangerous frogs whose tongues end in a very sharp point. They use this to spear their enemies from afar, often while hiding underwater."); + setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+4"); + addflag(lastrace->flags, F_HASATTACK, OT_TONGUE, 6, 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_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_THRUST, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_JUMP, NA, NA, "stamcost:0;"); + addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); + addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "hop"); + + addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL, "A young baby hawk."); // 'A' for Avian setbodytype(lastrace, BT_BIRD); lastrace->baseid = R_HAWK; @@ -10025,6 +10097,7 @@ void initrace(void) { addrace(R_STINKBUG, "stinkbeetle", 1, 'x', C_MAGENTA, MT_FLESH, RC_INSECT, "A dog-sized beetle with tough scales. Emits a foul odour upon death."); setbodytype(lastrace, BT_QUADRAPED); addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); @@ -10034,7 +10107,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+0"); addflag(lastrace->flags, F_ARMOURRATING, 10, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, 1, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 1, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_STINGACID, NA, NA, "dam:1d1;"); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); @@ -10792,6 +10865,7 @@ void initskills(void) { addskilldesc(sk->id, PR_BEGINNER, "^g-1 accuracy penalty^n", B_FALSE); addskilldesc(sk->id, PR_ADEPT, "^g+10% damage bonus.^n", B_FALSE); addskilldesc(sk->id, PR_SKILLED, "^g+2 accuracy, +20% damage bonus.^n", B_FALSE); + addskilldesc(sk->id, PR_SKILLED, "^gYou can now block certain attacks with this kind of weapon.^n", B_FALSE); addskilldesc(sk->id, PR_EXPERT, "^g+4 accuracy, +30% damage bonus.^n", B_FALSE); addskilldesc(sk->id, PR_MASTER, "^g+6 accuracy, +40%% damage bonus, combination strike ability.^n", B_FALSE); } diff --git a/data/hiscores.db b/data/hiscores.db index f0fb037..ee56582 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 1e477b1..f556bcd 100644 --- a/defs.h +++ b/defs.h @@ -221,8 +221,8 @@ #define SPEED_DEAD 50 #define SPEED_ACTION SP_NORMAL #define SPEED_MOVE SP_NORMAL -#define SPEED_DROP SP_FAST -#define SPEED_PICKUP SP_FAST +#define SPEED_DROP SP_ULTRAFAST +#define SPEED_PICKUP SP_ULTRAFAST #define SPEED_THROW SP_FAST #define SPEED_WAIT SP_NORMAL #define SPEED_READ SP_NORMAL @@ -928,6 +928,7 @@ enum RACE { R_HAWKYOUNG, R_HAWKBLOOD, R_HAWKFROST, + R_FROG, R_LEECH, R_NEWT, R_PORCUPINE, @@ -1699,6 +1700,7 @@ enum OBTYPE { OT_TEETH, OT_TEETHSM, OT_TENTACLE, + OT_TONGUE, OT_ZAPPER, // monster weapons OT_ACIDATTACK, @@ -2257,6 +2259,7 @@ enum FLAG { F_ARMOURSIZE, // v0 = sz_xxx, can be "medium", "human" or "large". F_ARMOURRATING, // val0 * 2 = pct of damage reduced F_SHIELD, // this is a shield - use special bodyhitchance code + F_CANBLOCK, // this objcet can block damtype xxx F_OBHP, // val0 = object health, val1 = object maxhealth F_OBHPDRAIN, // val0 = amt hp to lose each second. val1 = NA or damtype // if no damtype specified, it will be DT_DIRECT @@ -3084,7 +3087,6 @@ enum COMMAND { CMD_MSGHIST, CMD_OFFER, CMD_OPERATE, - CMD_PICKLOCK, CMD_PICKUP, CMD_POUR, CMD_QUAFF, diff --git a/doc/glyphs.txt b/doc/glyphs.txt index ccf3e4f..8a93615 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -41,6 +41,7 @@ X = unknown thing! y/Y = air related creatures like clouds of gas, air elemental z = lizard-like creature Z = undead +; = fish & = demon diff --git a/flag.c b/flag.c index ec0dbd2..c97bd91 100644 --- a/flag.c +++ b/flag.c @@ -913,6 +913,9 @@ void killflag(flag_t *f) { } } + ///////////////////////////////////////////// + // now we are actually removing the flag. + ///////////////////////////////////////////// // remember the pile so that we can re-index pile = f->pile; @@ -997,6 +1000,9 @@ void killflag(flag_t *f) { } void killflagpile(flagpile_t *fp) { + if (fp->ob && !fp->ob->dying) { + assert(0 == "calling killflagpile on non-dying object"); + } while (fp->first) { killflag(fp->first); } diff --git a/io.c b/io.c index f34f5b1..a660c28 100644 --- a/io.c +++ b/io.c @@ -2055,9 +2055,6 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { break; case F_FLEEFROM: msg("%s stop%s fleeing.", lfname, isplayer(lf) ? "" : "s"); - if (!isplayer(lf)) { - dblog("xx"); - } donesomething = B_TRUE; break; case F_FRIENDLY: @@ -4312,7 +4309,7 @@ void dolook(cell_t *where, int onpurpose) { char buf[BUFLEN]; char seeverb[BUFLEN]; int seensomething = B_FALSE; - object_t *o,*firstob = NULL; + object_t *o,*firstob = NULL,*secondob = NULL; flag_t *f; int includetrails = B_TRUE; @@ -4345,7 +4342,11 @@ void dolook(cell_t *where, int onpurpose) { interrupt(player); seensomething = B_TRUE; } else { - if (!firstob) { + if (firstob) { + if (!secondob) { + secondob = o; + } + } else { firstob = o; } numobs++; @@ -4376,45 +4377,24 @@ void dolook(cell_t *where, int onpurpose) { } } else if (numobs == 2) { char buf2[BUFLEN]; - object_t *secondob; - secondob = firstob->next; - if (hasflag(firstob->flags, F_THEREISHERE)) { - strcpy(buf, ""); // don't show it - } else { - if (streq(seeverb, "feel")) { - f = hasflag(firstob->flags, F_FEELTEXT); - if (f) { - strcpy(buf, f->text); - } else { - getobname(firstob, buf, firstob->amt); - } + if (streq(seeverb, "feel")) { + f = hasflag(firstob->flags, F_FEELTEXT); + if (f) { + strcpy(buf, f->text); } else { getobname(firstob, buf, firstob->amt); } - } - if (hasflag(secondob->flags, F_THEREISHERE)) { - strcpy(buf2, ""); // don't show it - } else { - if (streq(seeverb, "feel")) { - f = hasflag(secondob->flags, F_FEELTEXT); - if (f) { - strcpy(buf2, f->text); - } else { - getobname(secondob, buf2, secondob->amt); - } + f = hasflag(secondob->flags, F_FEELTEXT); + if (f) { + strcpy(buf2, f->text); } else { getobname(secondob, buf2, secondob->amt); } - } - if (!strlen(buf) && !strlen(buf2)) { - // both obs shown later! - } else if (!strlen(buf)) { - msg("You %s %s here.", seeverb, buf2); - } else if (!strlen(buf2)) { - msg("You %s %s here.", seeverb, buf); } else { - msg("You %s %s and %s here.", seeverb, buf, buf2); + getobname(firstob, buf, firstob->amt); + getobname(secondob, buf2, secondob->amt); } + msg("You %s %s and %s here.", seeverb, buf, buf2); } else if ((numobs >= 3) && (numobs <= 4)) { msg("You %s a few things here.", seeverb); } else if ((numobs >= 5) && (numobs <= 6)) { @@ -4655,6 +4635,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { strncat(retbuf, buf, HUGEBUFLEN); strncat(retbuf, "\n", HUGEBUFLEN); } + if ((f = hasflag(o->flags, F_IMPASSABLE)) != NULL) { if ((f->val[0] == SZ_MIN) && (f->val[1] == SZ_MAX)) { snprintf(buf, BUFLEN, "It is %simpassable.\n", hasflag(o->flags, F_DOOR) ? "currently " : ""); @@ -5287,6 +5268,32 @@ char *makedesc_ob(object_t *o, char *retbuf) { } // other weapon properties... + getflags(o->flags, retflag, &nretflags, F_CANBLOCK, F_NONE); + for (i = 0; i < nretflags; i++) { + char thisdt[BUFLEN]; + f = retflag[i]; + if (f->val[0] == DT_ALL) { + strcpy(thisdt, "melee"); + } else { + sprintf(thisdt, "%s", getdamname(f->val[0])); + } + + if (i == 0) { + snprintf(buf, BUFLEN, "Skilled weilders can use it to block %s", thisdt); + } else if (i == (nretflags - 1)) { + snprintf(buf, BUFLEN, " and %s", thisdt); + } else { + snprintf(buf, BUFLEN, ", %s", thisdt); + } + strncat(retbuf, buf, HUGEBUFLEN); + } + if (nretflags) { + snprintf(buf, BUFLEN, " damage.\n"); + strncat(retbuf, buf, HUGEBUFLEN); + } + + + f = hasflag(o->flags, F_NEEDSSPACE); if (f && f->known) { sprintf(buf, "It is ineffective in confined spaces due to its length.\n"); @@ -5698,12 +5705,21 @@ char *makedesc_ob(object_t *o, char *retbuf) { sprintf(buf, "^%dIt requires at least %d %s to use%s.^n\n", col, f->val[1], getattrname(f->val[0]), (f->val[2] == 0) ? "" : " effectively"); strncat(retbuf, buf, HUGEBUFLEN); + + msg("^wYou low %s will lower your %s with this weapon.", + getattrname(retflag[i]->val[0]), + (retflag[i]->val[0] == A_AGI) ? "accuracy" : "damage"); + if (usable && isweapon(o)) { if (pctmod > 0) { - sprintf(buf, "^%dYour high %s will increase your effectiveness with this weapon.^n\n", C_GREEN, getattrname(f->val[0])); + sprintf(buf, "^%dYour high %s will increase your %s with this weapon.^n\n", C_GREEN, + getattrname(f->val[0]), + (f->val[0] == A_AGI) ? "accuracy" : "damage"); strncat(retbuf, buf, HUGEBUFLEN); } else if (pctmod < 0) { - sprintf(buf, "^%dYour low %s will decrease your effectiveness with this weapon.^n\n", C_BROWN, getattrname(f->val[0])); + sprintf(buf, "^%dYour low %s will decrease your %s with this weapon.^n\n", C_BROWN, + getattrname(f->val[0]), + (f->val[0] == A_AGI) ? "accuracy" : "damage"); strncat(retbuf, buf, HUGEBUFLEN); } } @@ -6142,7 +6158,7 @@ char *makedesc_skill(enum SKILL skid, char *retbuf, enum SKILLLEVEL levhilite) { char *makedesc_spell(objecttype_t *ot, char *retbuf) { char buf[BUFLEN]; flag_t *retflag[MAXCANDIDATES], *f; - int nretflags,i,power,range; + int nretflags,i,power,range,stamcost; strcpy(retbuf, ""); @@ -6213,10 +6229,9 @@ char *makedesc_spell(objecttype_t *ot, char *retbuf) { } } - - f = hasflag(ot->flags, F_STAMCOST); - if (f) { - sprintf(buf, "It costs %d stamina to use.\n",f->val[0]); + stamcost = getstamcost(player, ot->id); + if (stamcost) { + sprintf(buf, "It costs %d stamina to use.\n",stamcost); strncat(retbuf, buf, HUGEBUFLEN); } @@ -8636,10 +8651,6 @@ void handleinput(void) { case 't': // throw dothrow(player->pack); break; - case 'p': // pick lock - addflag(player->flags, F_LASTCMD, NA, NA, NA, temp); - lockpick(player, NULL, NULL, NULL); - break; case 'P': // Pour dopour(player->pack); break; diff --git a/lf.c b/lf.c index 5e3b648..5f95aed 100644 --- a/lf.c +++ b/lf.c @@ -531,6 +531,7 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { int castable = B_FALSE; flag_t *f; objecttype_t *ot; + int stamcost = 0; // TODO: check for mute? if (lfhasflag(lf, F_STUNNED)) { @@ -588,7 +589,6 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { return B_FALSE; } } - } else if (lfhasflagval(lf, F_CANCAST, oid, NA, NA, NULL)) { int cost,power; @@ -622,8 +622,9 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { } - f = hasflag(ot->flags, F_STAMCOST); - if (f && (getstamina(lf) < f->val[0])) { + // do we have enough stamina to do this? + stamcost = getstamcost(lf, oid); + if (stamcost && (getstamina(lf) < stamcost)) { reason = E_NOSTAM; return B_FALSE; } @@ -1195,19 +1196,11 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { return B_FALSE; } - // other flags to check - getflags(o->flags, retflag, &nretflags, F_ATTREQ, F_NONE); - for (i = 0; i < nretflags; i++) { - f = retflag[i]; - if (f->id == F_ATTREQ) { - // meetsattreq will set 'reason' for us. - if (!meetsattreq(lf, f, o, NULL)) { - return B_FALSE; - } - } + if (!meetsallattreqs(lf, o)) { + // meetsattreq will set 'reason' for us. + return B_FALSE; } - // can we wear it ANYWHERE? getflags(o->flags, retflag, &nretflags, F_GOESON, F_NONE); for (i = 0; i < nretflags; i++) { @@ -1992,7 +1985,7 @@ int continuedigging(lifeform_t *lf) { int digpower; int stopnow = B_FALSE; - if (!hasfreeaction(lf)) { + if (!real_hasfreeaction(lf, F_DIGGING)) { stopnow = B_TRUE; } @@ -6988,18 +6981,91 @@ object_t *getsecmeleeweapon(lifeform_t *lf) { return NULL; } -object_t *getshield(lifeform_t *lf) { +// returns the best shield for the given damtype +object_t *getshield(lifeform_t *lf, enum DAMTYPE dt) { + object_t *shield[MAXPILEOBS]; + int checkmod[MAXPILEOBS]; + int nshields,i; + object_t *bestshield = NULL; + int bestcheckmod = -99; + getallshields(lf, dt, shield, checkmod, &nshields); + for (i = 0; i < nshields; i++) { + if (checkmod[i] > bestcheckmod) { + bestcheckmod = checkmod[i]; + bestshield = shield[i]; + } + } + return bestshield; +} + +int getallshields(lifeform_t *lf, enum DAMTYPE damtype, object_t **retob, int *checkmod, int *nretobs) { object_t *o; - o = getequippedob(lf->pack, BP_SECWEAPON); - if (o) { - if (isshield(o)) return o; - // master two-weaponers can use their second weapon as a shield. - if ((getskill(lf, SK_TWOWEAPON) >= PR_MASTER) && isweapon(o) && getweaponskill(lf, o)) { - return o; + + *nretobs = 0; + + if (!hasfreeaction(lf)) { + return 0; + } + + for (o = lf->pack->first ; o ; o = o->next) { + flag_t *f; + f = isequipped(o); + if (f && meetsallattreqs(lf, o)) { + int isblockob = B_FALSE; + if (isshield(o) && (f->val[0] == BP_SECWEAPON)) { + // shield? + isblockob = B_TRUE; + } else if (isweapon(o) && (getweaponskill(lf, o) >= PR_SKILLED) && (damtype != DT_PROJECTILE)) { + if (f->val[0] == BP_WEAPON) { + // primary weapon which we are skilled in? + isblockob = B_TRUE; + } else if ((f->val[0] == BP_SECWEAPON) && (getskill(lf, SK_TWOWEAPON) >= PR_MASTER)) { + // secondary weapon which we are skilled in, + // and we are a master two-weaponer ? + isblockob = B_TRUE; + } + } + if (isblockob) { + // can it block this damage type? + if ((damtype == DT_ALL) || + hasflagval(o->flags, F_CANBLOCK, damtype, NA, NA, NULL) || + hasflagval(o->flags, F_CANBLOCK, DT_ALL, NA, NA, NULL)) { + retob[*nretobs] = o; + checkmod[*nretobs] = getshieldblockmod(lf, o); + (*nretobs)++; + } + } } } - return NULL; + return *nretobs; +} + +int getshieldblockmod(lifeform_t *lf, object_t *o) { + enum SKILLLEVEL slev = PR_INEPT; + int othermod = 0; + if (isshield(o)) { + slev = getskill(lf, SK_SHIELDS); + } else { + // using a weapon + // skilled weapon == beginner block + // expert weapon == adept block + // master weapon == skilled block + slev = getweaponskill(lf, o) - 2; + } + switch (slev) { + case PR_NOVICE: othermod = 0; break; + case PR_BEGINNER: othermod = 4; break; + case PR_ADEPT: othermod = 7; break; + case PR_SKILLED: othermod = 10; break; + case PR_EXPERT: othermod = 13; break; + case PR_MASTER: othermod = 16; break; + default: + // should never happen + othermod = -4; + break; + } + return othermod; } @@ -7033,7 +7099,10 @@ float getstamregen(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags,i; - if (lfhasflagval(lf, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) { + if (lfhasflag(lf, F_TRAINING)) { + // don't regain stamina while training! + return 0; + } else if (lfhasflagval(lf, F_INJURY, IJ_WINDPIPECRUSHED, NA, NA, NULL)) { regenrate = 0.2; // override everything else } else { if (lfhasflag(lf, F_ASLEEP)) { @@ -7433,14 +7502,27 @@ race_t *getreallyrandomrace(enum RACECLASS wantrc) { } enum SKILL getrandomskill(void) { - int sel,count = 0; + int sel,count; + int nskills; skill_t *sk; - sel = rnd(1,MAXSKILLS-1); // 0 is SK_NONE + enum SKILL retskill = SK_NONE; + // count skills + nskills = 0; for (sk = firstskill ; sk ; sk = sk->next) { - if (count == sel) return sk->id; + nskills++; + } + + sel = rnd(0,nskills-1); + count = 0; + for (sk = firstskill ; sk ; sk = sk->next) { + if (count == sel) { + retskill = sk->id; + break; + } count++; } - return SK_NONE; + assert(findskill(retskill)); + return retskill; } object_t *getrestob(lifeform_t *lf) { @@ -8915,11 +8997,18 @@ flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp) { int hasfreeaction(lifeform_t *lf) { + return real_hasfreeaction(lf, F_NONE); +} +int real_hasfreeaction(lifeform_t *lf, enum FLAG exception) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags,i; if (isimmobile(lf)) return B_FALSE; - if (lfhasflag(lf, F_CASTINGSPELL)) return B_FALSE; - if (lfhasflag(lf, F_DIGGING)) return B_FALSE; - if (lfhasflag(lf, F_EATING)) return B_FALSE; - if (lfhasflag(lf, F_ASLEEP)) return B_FALSE; + getflags(lf->flags, retflag, &nretflags, F_ASLEEP, F_CASTINGSPELL, F_DIGGING, F_EATING, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->id != exception) { + return B_FALSE; + } + } return B_TRUE; } @@ -10085,9 +10174,11 @@ void killlf(lifeform_t *lf) { } // kill object pile free(lf->pack); + lf->pack = NULL; // kill flags killflagpile(lf->flags); + lf->flags = NULL; // remove from list nextone = lf->next; @@ -12176,6 +12267,19 @@ void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how) { } } +int meetsallattreqs(lifeform_t *lf, object_t *o) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags,i; + + // other flags to check + getflags(o->flags, retflag, &nretflags, F_ATTREQ, F_NONE); + for (i = 0; i < nretflags; i++) { + if (!meetsattreq(lf, retflag[i], o, NULL)) { + return B_FALSE; + } + } + return B_TRUE; +} // if you don't meet it, return why not in 'reason' int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *pctmod) { @@ -12494,10 +12598,10 @@ void modmorale(lifeform_t *lf, int howmuch) { void modstamina(lifeform_t *lf, float howmuch) { float orig; + if (howmuch == 0) return; + // you don't lose stamina while enraged - if (lfhasflag(lf, F_RAGE) && (howmuch < 0)) { - return; - } + if (lfhasflag(lf, F_RAGE) && (howmuch < 0)) return; if (isplayer(lf)) { if (howmuch < 0) { @@ -12656,9 +12760,6 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, } else { msg("%s %s.", lfname, realseetext); } - if ((realseetext[0] == '\0') || !strlen(realseetext)) { - dblog("xxx"); - } rv = B_TRUE; } } else if (!noisemaker && haslos(player, c)) { @@ -14734,32 +14835,6 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) { othermod += 10; } - } else if (ct == SC_SHIELDBLOCK) { - object_t *shield; - enum SKILLLEVEL slev; - shield = getshield(lf); - if (shield) { - if (isshield(shield)) { - slev = getskill(lf, SK_SHIELDS); - } else { - // twoweaponer using their weapon - slev = PR_NOVICE; - } - } else { - // should never happen!!! - slev = PR_INEPT; - } - switch (slev) { - case PR_NOVICE: othermod = 0; break; - case PR_BEGINNER: othermod = 4; break; - case PR_ADEPT: othermod = 7; break; - case PR_SKILLED: othermod = 10; break; - case PR_EXPERT: othermod = 13; break; - case PR_MASTER: othermod = 16; break; - default: - othermod = -4; - break; - } } else if (ct == SC_MORALE) { othermod += (getstatmod(lf, A_WIS) / 30); // ie. -1 to 1 } else if (ct == SC_OPENLOCKS) { @@ -16784,12 +16859,10 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where) if (!rv) { objecttype_t *ot; - flag_t *f; int stamcost = 0; // success - charge stamina ot = findot(aid); - f = hasflag(ot->flags, F_STAMCOST); - if (f) stamcost = f->val[0]; + stamcost = getstamcost(lf, aid); if (stamcost) { modstamina(lf, -stamcost); } @@ -17548,11 +17621,6 @@ int wear(lifeform_t *lf, object_t *o) { int nretflags; int showpos = B_FALSE; - // this might impact your AR - if (isplayer(lf)) { - statdirty = B_TRUE; - } - if (lfhasflag(lf, F_RAGE)) { if (isplayer(lf)) msg("You are too enraged!"); return B_TRUE; @@ -17785,10 +17853,7 @@ int wear(lifeform_t *lf, object_t *o) { return B_TRUE; } - // wear it - //f = hasflag(o->flags, F_GOESON); - //bp = f->val[0]; - + // actually wear it for (i = 0; i < ncheckparts; i++) { addflag(o->flags, F_EQUIPPED, possbp[i], -1, -1, NULL); } @@ -17807,7 +17872,9 @@ int wear(lifeform_t *lf, object_t *o) { } if ((gamemode == GM_GAMESTARTED) && lf->created) { + if (isplayer(lf)) { + // announce if (showpos) { char posbuf[BUFLEN]; makewearstring(lf, o, B_TRUE, posbuf ); @@ -17862,6 +17929,10 @@ int wear(lifeform_t *lf, object_t *o) { // give flags giveobflags(lf, o, F_EQUIPCONFER); + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + // set statdirty since this might have impacted your AR / EV + statdirty = B_TRUE; + } return rv; } @@ -18144,7 +18215,9 @@ int weild(lifeform_t *lf, object_t *o) { int pctmod; meetsattreq(lf, retflag[i], o, &pctmod); if (pctmod < 0) { - msg("^wYou lack of %s will hinder your usage of this weapon.", getattrname(retflag[i]->val[0])); + msg("^wYou low %s will lower your %s with this weapon.", + getattrname(retflag[i]->val[0]), + (retflag[i]->val[0] == A_AGI) ? "accuracy" : "damage"); } } } diff --git a/lf.h b/lf.h index 12177eb..9c34e36 100644 --- a/lf.h +++ b/lf.h @@ -200,7 +200,9 @@ char *real_getlfnamea(lifeform_t *lf, char *buf, int usevis); enum LFSIZE getlfsize(lifeform_t *lf); float getlfweight(lifeform_t *lf, int withobs); object_t *getsecmeleeweapon(lifeform_t *lf); -object_t *getshield(lifeform_t *lf); +object_t *getshield(lifeform_t *lf, enum DAMTYPE dt); +int getallshields(lifeform_t *lf, enum DAMTYPE damtype, object_t **retob, int *checkmod, int *nretobs); +int getshieldblockmod(lifeform_t *lf, object_t *o); int getspellspeed(lifeform_t *lf); int getstamina(lifeform_t *lf); float getstamregen(lifeform_t *lf); @@ -250,6 +252,7 @@ map_t *gotolev(lifeform_t *lf, int depth, object_t *fromstairs); int gotosleep(lifeform_t *lf, int onpurpose); flag_t *hasbleedinginjury(lifeform_t *lf, enum BODYPART bp); int hasfreeaction(lifeform_t *lf); +int real_hasfreeaction(lifeform_t *lf, enum FLAG exception); int hashealableinjuries(lifeform_t *lf); job_t *hasjob(lifeform_t *lf, enum JOB job); void inc_quad_range(enum QUADRANT *start, enum QUADRANT *end, int howmuch); @@ -332,6 +335,7 @@ void makenoise(lifeform_t *lf, enum NOISETYPE nid); void makepeaceful(lifeform_t *lf); lifeform_t *makezombie(object_t *o); void mayusespellschool(flagpile_t *fp, enum SPELLSCHOOL ss, enum FLAG how); +int meetsallattreqs(lifeform_t *lf, object_t *o); int meetsattreq(lifeform_t *lf, flag_t *f, object_t *o, int *modpct); int mightflee(lifeform_t *lf); int modattr(lifeform_t *lf, enum ATTRIB attr, int amt); diff --git a/map.c b/map.c index 50f281f..1d84d25 100644 --- a/map.c +++ b/map.c @@ -3375,6 +3375,7 @@ void killmap(map_t *m) { while (m->lf) killlf(m->lf); killflagpile(m->flags); + m->flags = NULL; for (i = 0; i < (m->w*m->h); i++){ killcell(m->cell[i]); diff --git a/objects.c b/objects.c index 642ae1e..2125cf5 100644 --- a/objects.c +++ b/objects.c @@ -1290,6 +1290,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes // } } else { // ie. manual bookcontents = getrandomskill(); + assert(findskill(bookcontents)); } } @@ -1323,6 +1324,7 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int wantlinkholes } } } else { + assert(findskill(bookcontents)); addflag(o->flags, F_MANUALOF, bookcontents, NA, NA, NULL); } @@ -3542,7 +3544,7 @@ int getobvalue(object_t *o) { price += f->val[0]; } - getflags(o->flags, retflag, &nretflags, F_ARMOURRATING, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE); + getflags(o->flags, retflag, &nretflags, F_ARMOURRATING, F_ARMOURSIZE, F_BONUS, F_DAM, F_EDIBLE, F_LINKSPELL, F_MANUALOF, F_NONE); for (i = 0; i < nretflags; i++) { f = retflag[i]; // damage @@ -3557,6 +3559,12 @@ int getobvalue(object_t *o) { rating = (float)f->val[0]; price += (rating * 20.0); } + // armour size (nonstandard costs more) + if (f->id == F_ARMOURSIZE) { + if (f->val[0] != SZ_HUMAN) { + price += 75; + } + } // bonus/penalties if (f->id == F_BONUS) { price += (f->val[0] * 100); @@ -6368,9 +6376,8 @@ int isedible(object_t *o) { return B_FALSE; } -int isequipped(object_t *o) { - if (hasflag(o->flags, F_EQUIPPED)) return B_TRUE; - return B_FALSE; +flag_t *isequipped(object_t *o) { + return hasflag(o->flags, F_EQUIPPED); } int isequippedon(object_t *o, enum BODYPART bp) { @@ -6889,9 +6896,18 @@ void killob(object_t *o) { } // free mem - if (o->inscription) free(o->inscription); - if (o->contents) killobpile(o->contents); - if (o->flags) killflagpile(o->flags); + if (o->inscription) { + free(o->inscription); + o->inscription = NULL; + } + if (o->contents) { + killobpile(o->contents); + o->contents = NULL; + } + if (o->flags) { + killflagpile(o->flags); + o->flags = NULL; + } // remove from list nextone = o->next; @@ -11517,7 +11533,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, if (youhit && target) { flag_t *f; - object_t *shield; + char attackname[BUFLEN]; + int difficulty; // cyclone shield? f = lfhasflag(target, F_WINDSHIELD); if (f) { @@ -11529,31 +11546,14 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, youhit = B_FALSE; } } - // an actual physical shield? - shield = getshield(target); - if (shield && hasfreeaction(target)) { - // block chance based on shield skill - if (skillcheck(target, SC_SHIELDBLOCK, 14 + (speed*2), 0)) { - int throwdam,dam; - if (seen) { - char shname[BUFLEN]; - real_getobname(shield, shname, 1, B_TRUE, B_FALSE, B_TRUE, B_FALSE, B_FALSE); - if (isplayer(target)) { - msg("You block %s with your %s.", obname, noprefix(shname)); - } else { - msg("%s blocks %s with %s.", targetname, obname, shname); - } - announcedmiss = B_TRUE; - } - // damage shield - throwdam = getthrowdam(o); - dam = throwdam + speed; - takedamage(shield, dam, DT_PROJECTILE); - youhit = B_FALSE; - practice(target, SK_SHIELDS, 1); - missiledam += ((speed*2)+1); - } + // an actual physical shield? + sprintf(attackname, "%s", obname); + difficulty = 14 + (speed*2); + if (check_for_block(thrower, target, getthrowdam(o) + speed, DT_PROJECTILE, difficulty, attackname)) { + announcedmiss = B_TRUE; + youhit = B_FALSE; + missiledam += ((speed*2)+1); } } @@ -12403,7 +12403,7 @@ void trapeffects(object_t *trapob, enum OBTYPE oid, cell_t *c) { } } } else if (oid == OT_TRAPALARM) { - noise(c, NULL, NC_OTHER, 10, "a blaring siren!", NULL); + noise(c, NULL, NC_OTHER, 10, "a blaring siren!", "A blaring siren goes off!"); } else if ((oid == OT_TRAPARROW) || (oid == OT_TRAPARROWP)) { int dir,bestdir = D_NONE; cell_t *src = NULL; diff --git a/objects.h b/objects.h index 08f1970..3a10c30 100644 --- a/objects.h +++ b/objects.h @@ -175,7 +175,7 @@ int isdangerousob(object_t *o, lifeform_t *lf, int onlyifknown); int isdeadob(object_t *o); int isdrinkable(object_t *o); int isedible(object_t *o); -int isequipped(object_t *o); +flag_t *isequipped(object_t *o); int isequippedon(object_t *o, enum BODYPART bp); int isfirearm(object_t *o); int isflammable(object_t *o); diff --git a/shops.c b/shops.c index f58a0b4..8c31dcc 100644 --- a/shops.c +++ b/shops.c @@ -553,19 +553,31 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top int y; char buf[BUFLEN], buf2[BUFLEN], choices[BUFLENSMALL]; char ch; + static enum { + BUY, + EXAMINE + } shopmode = BUY; y = starty; // list objects for sale for (o = vm->contents->first ; o ; o = o->next) { char obname[BUFLEN]; int thisprice; + enum COLOUR col; getshopobname(o, obname, o->amt); thisprice = (int)getshopprice(o, player); snprintf(buf, BUFLEN, "%c - %s", o->letter, obname); - snprintf(buf2, BUFLEN, "^%d%-60s$%d", - (countmoney(player->pack) >= thisprice) ? C_GREY : C_RED, - buf, thisprice); + if (shopmode == BUY) { + if (countmoney(player->pack) >= thisprice) { + col = C_GREY; + } else { + col = C_RED; + } + } else { + col = C_GREY; + } + snprintf(buf2, BUFLEN, "^%d%-60s$%d", col, buf, thisprice); wmove(mainwin, y, 0); textwithcol(mainwin, buf2); y++; @@ -581,140 +593,150 @@ enum SHOPRETURN shoppurchase(lifeform_t *lf, object_t *vm, int starty, char *top y++; // ask what to do - mvwprintw(mainwin, y, 0, "What will you buy (ESC when done)? "); + mvwprintw(mainwin, y, 0, "What will you %s (ESC when done)? ", (shopmode == BUY) ? "buy" : "examine"); ch = getch(); if (ch == 27) { strcpy(toptext, ""); return SR_BACK; + } else if (ch == '?') { + if (shopmode == BUY) { + shopmode = EXAMINE; + } else { + shopmode = BUY; + } } else { // try to find that object... o = hasobletter(vm->contents, ch); if (o) { - enum SKILLLEVEL slev; - char obname[BUFLEN],validchars[BUFLENSMALL]; - char answer; - int value; + if (shopmode == EXAMINE) { + describeob(o); + } else { + enum SKILLLEVEL slev; + char obname[BUFLEN],validchars[BUFLENSMALL]; + char answer; + int value; - value = (int)getshopprice(o, player); - slev = getskill(player, SK_THIEVERY); + value = (int)getshopprice(o, player); + slev = getskill(player, SK_THIEVERY); - // confirm - getshopobname(o, obname, o->amt); - snprintf(buf, BUFLEN, "Buy%s %s for $%d?", slev ? "/steal" : "", obname, value); - strcpy(validchars, "yn"); - if (slev) { - strcat(validchars, "s"); - } - answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE); - if (answer == 'y') { - // prompt to use a card - if (hasob(player->pack, OT_CREDITCARD)) { - char ch2; - ch2 = askchar("Charge this purchase to your credit card?","yn","n", B_TRUE, B_FALSE); - if (ch2 == 'y') { - object_t *cc; - // ask which one - initprompt(&prompt, "Which credit card will you use?"); - for (cc = player->pack->first ; cc ; cc = cc->next) { - if (cc->type->id == OT_CREDITCARD) { - char cardname[BUFLEN]; - getobname(cc, cardname, 1); - addchoice(&prompt, cc->letter, cardname, cardname, cc, NULL); + // confirm + getshopobname(o, obname, o->amt); + snprintf(buf, BUFLEN, "Buy%s %s for $%d?", slev ? "/steal" : "", obname, value); + strcpy(validchars, "yn"); + if (slev) { + strcat(validchars, "s"); + } + answer = askchar(buf, validchars,"n", B_TRUE, B_FALSE); + if (answer == 'y') { + // prompt to use a card + if (hasob(player->pack, OT_CREDITCARD)) { + char ch2; + ch2 = askchar("Charge this purchase to your credit card?","yn","n", B_TRUE, B_FALSE); + if (ch2 == 'y') { + object_t *cc; + // ask which one + initprompt(&prompt, "Which credit card will you use?"); + for (cc = player->pack->first ; cc ; cc = cc->next) { + if (cc->type->id == OT_CREDITCARD) { + char cardname[BUFLEN]; + getobname(cc, cardname, 1); + addchoice(&prompt, cc->letter, cardname, cardname, cc, NULL); + } } - } - if (prompt.nchoices == 1) { - // only one card? - cc = (object_t *)prompt.choice[0].data; - } else { - addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL); - prompt.maycancel = B_TRUE; - getchoice(&prompt); - cc = (object_t *)prompt.result; - } - if (cc) { - if (getcharges(cc) >= getobvalue(o)) { - int shopamt; - // you got it! - usecharges(cc, getobvalue(o)); - o->letter = '\0'; - shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 - o = moveob(o, player->pack, ALL); - identify(o); - getobname(o, obname, shopamt); - snprintf(toptext, BUFLEN, "Charged to card: %c - %s", o->letter, obname); - if (npurchased) (*npurchased)++; - // god of thieves likes credit cards... - pleasegodmaybe(R_GODTHIEVES, (value/75)); - return SR_CONTINUE; + if (prompt.nchoices == 1) { + // only one card? + cc = (object_t *)prompt.choice[0].data; } else { - // maxed! - usecharges(cc, getcharges(o)); // use up all remaining charges - // get kicked out - msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more(); - // shop closes - addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); - return SR_QUIT; + addchoice(&prompt, '-', "(cancel)", "(cancel)", NULL, NULL); + prompt.maycancel = B_TRUE; + getchoice(&prompt); + cc = (object_t *)prompt.result; + } + if (cc) { + if (getcharges(cc) >= getobvalue(o)) { + int shopamt; + // you got it! + usecharges(cc, getobvalue(o)); + o->letter = '\0'; + shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 + o = moveob(o, player->pack, ALL); + identify(o); + getobname(o, obname, shopamt); + snprintf(toptext, BUFLEN, "Charged to card: %c - %s", o->letter, obname); + if (npurchased) (*npurchased)++; + // god of thieves likes credit cards... + pleasegodmaybe(R_GODTHIEVES, (value/75)); + return SR_CONTINUE; + } else { + // maxed! + usecharges(cc, getcharges(o)); // use up all remaining charges + // get kicked out + msg("^B\"Trying to use a maxed out card, eh? Get out of here, thief!\""); more(); + // shop closes + addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); + return SR_QUIT; + } } } } - } - // do you have enough money? - if (countmoney(player->pack) >= getobvalue(o) ) { - int shopamt; - object_t *gold; - gold = hasob(player->pack, OT_GOLD); - if (gold) { - // if so, buy it - // lose money (do this first to avoid potential weight issues) - givemoney(player, NULL, value); - // clear o->letter + // do you have enough money? + if (countmoney(player->pack) >= getobvalue(o) ) { + int shopamt; + object_t *gold; + gold = hasob(player->pack, OT_GOLD); + if (gold) { + // if so, buy it + // lose money (do this first to avoid potential weight issues) + givemoney(player, NULL, value); + // clear o->letter + o->letter = '\0'; + // give object + shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 + o = moveob(o, player->pack, ALL); + identify(o); + getobname(o, obname, shopamt); + snprintf(toptext, BUFLEN, "Purchased: %c - %s", o->letter, obname); + if (npurchased) (*npurchased)++; + } else { + msg("You don't seem to have any money..."); more(); + o = NULL; + } + } else { + msg("You can't afford that!"); more(); + o = NULL; + } + } else if (answer == 's') { // steal + // skillcheck - difficulty based on total value of objects here + // 15 + value/50 means: + // $50 is diff 16 + // $100 is diff 17 + // $200 is diff 19 + // $500 is diff 25 + // $1000 is diff 35 + if (skillcheck(player, SC_STEAL, 15+(value/50), 0)) { + int shopamt; + // success o->letter = '\0'; - // give object - shopamt = o->amt; // avoid "purchased: 2 apples" when you only bought 1 but were holding 1 + shopamt = o->amt; // avoid "stolen: 2 apples" when you only bought 1 but were holding 1 o = moveob(o, player->pack, ALL); identify(o); getobname(o, obname, shopamt); - snprintf(toptext, BUFLEN, "Purchased: %c - %s", o->letter, obname); - if (npurchased) (*npurchased)++; - } else { - msg("You don't seem to have any money..."); more(); + snprintf(toptext, BUFLEN, "Stolen: %c - %s", o->letter, obname); + + pleasegodmaybe(R_GODTHIEVES, (value/50)); o = NULL; + } else { + msg("^B\"HEY! Get out of my shop, thief!\""); more(); + // shop closes + addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); + return SR_QUIT; } } else { - msg("You can't afford that!"); more(); - o = NULL; + // cancelled + strcpy(toptext, ""); } - } else if (answer == 's') { // steal - // skillcheck - difficulty based on total value of objects here - // 15 + value/50 means: - // $50 is diff 16 - // $100 is diff 17 - // $200 is diff 19 - // $500 is diff 25 - // $1000 is diff 35 - if (skillcheck(player, SC_STEAL, 15+(value/50), 0)) { - int shopamt; - // success - o->letter = '\0'; - shopamt = o->amt; // avoid "stolen: 2 apples" when you only bought 1 but were holding 1 - o = moveob(o, player->pack, ALL); - identify(o); - getobname(o, obname, shopamt); - snprintf(toptext, BUFLEN, "Stolen: %c - %s", o->letter, obname); - - pleasegodmaybe(R_GODTHIEVES, (value/50)); - o = NULL; - } else { - msg("^B\"HEY! Get out of my shop, thief!\""); more(); - // shop closes - addflag(vm->flags, F_BANNEDLF, player->id, NA, NA, NULL); - return SR_QUIT; - } - } else { - // cancelled - strcpy(toptext, ""); - } + } // end if shopmode == ... } else { snprintf(toptext, BUFLEN, "No such item."); } // end if o diff --git a/spell.c b/spell.c index a2fbf51..0b3209b 100644 --- a/spell.c +++ b/spell.c @@ -102,8 +102,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } - f = hasflag(ot->flags, F_STAMCOST); - if (f) stamcost = f->val[0]; + stamcost = getstamcost(user, abilid); if (stamcost) { if (getstamina(user) < stamcost) { @@ -1618,11 +1617,13 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // TODO: make this like eating/resting/etc ? taketime(user, getactspeed(user)); } else if (abilid == OT_A_SHIELDBASH) { - object_t *shield; + object_t *shield = NULL; char dirch; flag_t *f; int badshield = B_FALSE; int shpenalty,mod; + object_t *shieldlist[MAXPILEOBS]; + int nshields,i; char shname[BUFLEN], tname[BUFLEN]; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { @@ -1630,8 +1631,14 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef return B_TRUE; } - shield = getshield(user); - if (!shield || !isshield(shield)) { + getallshields(user, DT_ALL, shieldlist, NULL, &nshields); + for (i = 0; i < nshields; i++) { + if (isshield(shieldlist[i])) { + shield = shieldlist[i]; + break; + } + } + if (!shield) { badshield = B_TRUE; } @@ -2036,6 +2043,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef char targetname[BUFLEN]; int badweapon = B_FALSE; flag_t *damflag; + obpile_t *op = NULL; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You lack the stability for a thrust while swimming."); @@ -2044,17 +2052,29 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef wep = getweapon(user); if (!wep) { - badweapon = B_TRUE; - } else if (getdamtype(wep) != DT_PIERCE) { - badweapon = B_TRUE; + object_t *weplist[MAXPILEOBS]; + int nweps; + // look for innate attack + getweapons(user, weplist, NULL, NULL, &op, &nweps); + if (nweps) { + wep = weplist[0]; + } else { + badweapon = B_TRUE; + } } - damflag = hasflag(wep->flags, F_DAM); - if (!damflag) { - badweapon = B_TRUE; + if (wep) { + if (getdamtype(wep) != DT_PIERCE) { + badweapon = B_TRUE; + } + damflag = hasflag(wep->flags, F_DAM); + if (!damflag) { + badweapon = B_TRUE; + } } if (badweapon) { if (isplayer(user)) msg("You need a long piercing weapon to perform a thrust!" ); + if (op) killobpile(op); return B_TRUE; } @@ -2064,6 +2084,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef targcell = askcoords(buf, "Thrust->", TT_MONSTER, user, 2, LOF_NEED, B_TRUE); if (!targcell) { msg("Cancelled."); + if (op) killobpile(op); return TRUE; } } @@ -2071,6 +2092,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef target = targcell->lf; if (!target) { if (isplayer(user)) msg("There is nobody there to attack!"); + if (op) killobpile(op); return B_TRUE; } getlfname(target, targetname); @@ -2079,6 +2101,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef attacklf(user, target, wep, damflag); killflag(f); taketime(user, getattackspeed(user)); + if (op) killobpile(op); } else if (abilid == OT_A_TRAIN) { // can we train? if (!user->skillpoints && !lfhasflag(user, F_HASNEWLEVEL)) { @@ -10448,6 +10471,25 @@ int getspellrange(lifeform_t *lf, enum OBTYPE spellid, int power) { return range; } +int getstamcost(lifeform_t *lf, enum OBTYPE oid) { + int stamcost = -1; + flag_t *f; + f = lfhasflagval(lf, F_CANWILL, oid, NA, NA, NULL); + if (f) { + // override stamina cost? + texttospellopts(f->text, "stamcost:", &stamcost, NULL); + } + if (stamcost == -1) { + objecttype_t *ot; + ot = findot(oid); + if (ot) { + f = hasflag(ot->flags, F_STAMCOST); + if (f) stamcost = f->val[0]; + } + } + return stamcost; +} + char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf) { // default strcpy(buf, ""); diff --git a/spell.h b/spell.h index b7ad2d0..34e39ec 100644 --- a/spell.h +++ b/spell.h @@ -27,6 +27,7 @@ enum SPELLSCHOOL getspellschool(enum OBTYPE spellid); enum SPELLSCHOOL getspellschoolknown(lifeform_t *lf, enum OBTYPE spellid); enum SKILLLEVEL getspellskill(lifeform_t *lf, enum OBTYPE spellid); int getspellrange(lifeform_t *lf, enum OBTYPE spellid, int power); +int getstamcost(lifeform_t *lf, enum OBTYPE oid); char *getvarpowerspelldesc(enum OBTYPE spellid, int power, char *buf); int getworkablematerials(lifeform_t *lf, enum SKILL skid , enum MATERIAL *repairablemats, int *cutoffpct, int *nmats); object_t *getworkhelpob(obpile_t *op, enum MATERIAL mat); diff --git a/text.c b/text.c index 3d73552..cc84417 100644 --- a/text.c +++ b/text.c @@ -1674,6 +1674,7 @@ void texttospellopts(char *text, ... ) { "needgrab:", "range:", "race:", + "stamcost:", NULL, }; char argtype[] = { @@ -1682,6 +1683,7 @@ void texttospellopts(char *text, ... ) { 'b', 'i', 's', + 'i', '\0', }; char *wantname = NULL; diff --git a/vault.c b/vault.c index df381bc..bcdc8f1 100644 --- a/vault.c +++ b/vault.c @@ -1403,6 +1403,7 @@ void killvault(vault_t *v) { killlegend(v->legend); } killflagpile(v->flags); + v->flags = NULL; // deallocate nextone = v->next;