diff --git a/ai.c b/ai.c index bfa26e0..9bc3c2d 100644 --- a/ai.c +++ b/ai.c @@ -392,11 +392,12 @@ void aiturn(lifeform_t *lf) { flag_t *mf; //flag_t *nextf; // lifeform_t *fleefrom = NULL; - lifeform_t *target; + lifeform_t *target,*newtarget; enum BODYPART bp; - cell_t *c; + //cell_t *c; lifeform_t *master = NULL; enum IQBRACKET iqb; + int n; /* @@ -601,9 +602,6 @@ void aiturn(lifeform_t *lf) { return; } - if (goingtomove && (getcelldist(lf->cell, target->cell) == 1)) { - } - if (!lfhasflag(lf, F_HIDING)) { objecttype_t *st; // can we attack with spells (ie. ones which target the victim)? @@ -711,7 +709,7 @@ void aiturn(lifeform_t *lf) { // try to throw it! if (!throwat(lf, o, target->cell)) { // succesful - goingtomove = B_FALSE; + return; } else { if (db) dblog(".oO { throw failed! }"); } @@ -748,7 +746,7 @@ void aiturn(lifeform_t *lf) { if (!operate(lf, o, zapcell)) { // succesful - goingtomove = B_FALSE; + return; } else { if (db) dblog(".oO { zap failed! }"); } @@ -861,8 +859,51 @@ void aiturn(lifeform_t *lf) { // not attacking anyone in particular - if (db) dblog(".oO { i do not have a target or can't move towards it. }"); - // are we hostile? if so, look for a target + if (db) dblog(".oO { i do not have a target or can't move towards it. looking for one. }"); + + // look for any race which we hate + newtarget = NULL; + for (n = 0; n < lf->nlos; n++) { + lifeform_t *who; + who = lf->los[n]->lf; + if (who && cansee(lf, who)) { + if (lfhasflagval(lf, F_HATESRACE, who->race->id, NA, NA, NULL) || + lfhasflagval(lf, F_HATESRACE, who->race->baseid, NA, NA, NULL) ) { + if (db) dblog(".oO { found a hated target - lfid %d (%s) ! }",who->id, who->race->name); + newtarget = who; + break; + } + } + } + if (!newtarget) { + // now look for enemies + for (n = 0; n < lf->nlos; n++) { + lifeform_t *who; + who = lf->los[n]->lf; + if (who && cansee(lf, who)) { + if (areenemies(lf, who)) { + if (db) dblog(".oO { found an enemy target - lfid %d (%s) ! }",who->id, who->race->name); + newtarget = who; + break; + } + } + } + } + + if (newtarget) { + aiattack(lf, newtarget, AI_FOLLOWTIME); + // then move towards them... + if (db) dblog(".oO { moving towards my new target }"); + + if (icanattack) { + if (!movetowards(lf, newtarget->cell, DT_ORTH)) return; + } else { + if (db) dblog(".oO { won't move towards target - i have no weapon. }"); + } + } + + /* + // look for a target to attack based on our allegiance switch (getallegiance(lf)) { int i; int x,y; @@ -918,6 +959,8 @@ void aiturn(lifeform_t *lf) { default: break; } + */ + /////////////////////////////////////////////// // training @@ -941,7 +984,7 @@ void aiturn(lifeform_t *lf) { master = findlf(lf->cell->map, mf->val[0]); if (master && cansee(lf, master)) { // can see my master - if (lfhasflag(master, F_RESTING)) { + if (isresting(master)) { // rest as well. rest(lf, B_TRUE); return; @@ -1143,11 +1186,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG case ST_VICTIM: case ST_ADJVICTIM: if (needlos && (!victim || !cansee(lf, victim)) ) { - dblog(".oO { cant cast %s - no LOS to victim }", ot ? ot->name : "?unkownspell?"); + if (db) dblog(".oO { cant cast %s - no LOS to victim }", ot ? ot->name : "?unkownspell?"); return B_FALSE; } if (needlof && !haslof(lf->cell, victim->cell, needlof, NULL) ) { - dblog(".oO { cant cast %s - no LOF to victim }", ot ? ot->name : "?unkownspell?"); + if (db) dblog(".oO { cant cast %s - no LOF to victim }", ot ? ot->name : "?unkownspell?"); return B_FALSE; } break; @@ -1157,7 +1200,7 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } else { // invalid spell for this purpose - dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?"); + if (db) dblog(".oO { cant cast %s - not valid for given purpose }", ot ? ot->name : "?unkownspell?"); return B_FALSE; } @@ -1197,6 +1240,15 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG // now check whether it meets specific spell conditions specificcheckok = B_TRUE; + if (ot->id == OT_S_AIRBLAST) { + // target must be in a straight compass dir from us + if ((victim->x != lf->x) || + (victim->y != lf->y) || + (abs(victim->x - lf->x) != abs(victim->y - lf->y)) ) { + } else { + specificcheckok = B_FALSE; + } + } if (ot->id == OT_S_ANIMATEMETAL) { object_t *wep; wep = getweapon(lf); @@ -1210,37 +1262,19 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_S_DRAINLIFE) && isimmuneto(victim->flags, DT_NECROTIC)) { specificcheckok = B_FALSE; } - if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) { - flag_t *willflag; - flag_t *srflag; - int srange = 5; - srflag = lfhasflag(lf, F_SWOOPRANGE); - if (srflag) { - srange = srflag->val[0]; - } - - willflag = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); - if (willflag) { - texttospellopts(f->text, NULL, NULL, NULL, &srange); - if (!srange) srange = 5; - } - - - if (!haslof(lf->cell, victim->cell, LOF_NEED,NULL)) { - specificcheckok = B_FALSE; - } else if (isimmobile(lf)) { - specificcheckok = B_FALSE; - } else if ((ot->id == OT_A_SWOOP) && !lfhasflag(lf, F_FLYING)) { - specificcheckok = B_FALSE; - } else if (getcelldist(lf->cell, victim->cell) > srange) { - specificcheckok = B_FALSE; - } else if (getcelldist(lf->cell, victim->cell) == 1) { // ie already adjacent + if (ot->id == OT_A_FLURRY) { + if (!isdualweilding(lf)) { specificcheckok = B_FALSE; } } if ((ot->id == OT_S_HASTE) && (lfhasflag(victim, F_FASTACT) || lfhasflag(victim, F_FASTACTMOVE)) ) { specificcheckok = B_FALSE; } + if (ot->id == OT_A_HEAVYBLOW) { + if (!getweapon(lf)) { + specificcheckok = B_FALSE; + } + } if (ot->id == OT_A_HIDE) { if (lfhasflag(victim, F_HIDING)) { specificcheckok = B_FALSE; @@ -1272,6 +1306,34 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG if ((ot->id == OT_A_SPRINT) && lfhasflag(lf, F_SPRINTING)) { specificcheckok = B_FALSE; } + if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) { + flag_t *willflag; + flag_t *srflag; + int srange = 5; + srflag = lfhasflag(lf, F_SWOOPRANGE); + if (srflag) { + srange = srflag->val[0]; + } + + willflag = lfhasflagval(lf, F_CANWILL, ot->id, NA, NA, NULL); + if (willflag) { + texttospellopts(f->text, NULL, NULL, NULL, &srange); + if (!srange) srange = 5; + } + + + if (!haslof(lf->cell, victim->cell, LOF_NEED,NULL)) { + specificcheckok = B_FALSE; + } else if (isimmobile(lf)) { + specificcheckok = B_FALSE; + } else if ((ot->id == OT_A_SWOOP) && !lfhasflag(lf, F_FLYING)) { + specificcheckok = B_FALSE; + } else if (getcelldist(lf->cell, victim->cell) > srange) { + specificcheckok = B_FALSE; + } else if (getcelldist(lf->cell, victim->cell) == 1) { // ie already adjacent + specificcheckok = B_FALSE; + } + } if ((ot->id == OT_S_WARPWOOD)) { specificcheckok = B_FALSE; if (victim) { diff --git a/attack.c b/attack.c index fbd09b7..7cb87a7 100644 --- a/attack.c +++ b/attack.c @@ -113,6 +113,7 @@ int attackcell(lifeform_t *lf, cell_t *c) { int attacktime; int gotweapon = B_FALSE; int maxattacks = ALL; + int lastweaponidx = -1; // anyone there? if so just attack. if (c->lf) { @@ -155,14 +156,29 @@ int attackcell(lifeform_t *lf, cell_t *c) { } // first use our weapon... - wep[0] = getweapon(lf); - if (wep[0]) { - damflag[0] = hasflag(wep[0]->flags, F_DAM); - validwep[0] = B_TRUE; + nweps = 0; + wep[nweps] = getweapon(lf); + if (wep[nweps]) { + damflag[nweps] = hasflag(wep[nweps]->flags, F_DAM); + validwep[nweps] = B_TRUE; + lastweaponidx = 0; nweps++; gotweapon = B_TRUE; } + // if we are skilled at twoweaponing, we can attack with our second weapon + // as well, with a possible accuracy penalty depending on our skill level. + if (getskill(lf, SK_TWOWEAPON)) { + wep[nweps] = getsecmeleeweapon(lf); + if (wep[nweps]) { + damflag[nweps] = hasflag(wep[nweps]->flags, F_DAM); + validwep[nweps] = B_TRUE; + lastweaponidx = nweps; + nweps++; + gotweapon = B_TRUE; + } + } + // then use all our innate attacks.. for (f = lf->flags->first ; f; f = f->next) { if (f->id == F_HASATTACK) { @@ -178,11 +194,12 @@ int attackcell(lifeform_t *lf, cell_t *c) { validwep[nweps] = B_TRUE; damflag[nweps] = f; nweps++; - innateattacks++; } } } + innateattacks = countinnateattacks(lf); + // stop sprinting f = lfhasflag(lf, F_SPRINTING); if (f && f->val[0]) { @@ -200,36 +217,26 @@ int attackcell(lifeform_t *lf, cell_t *c) { return B_TRUE; } - maxattacks = nweps; // ie. all - f = lfhasflag(lf, F_MAXATTACKS); - if (f) { - maxattacks = f->val[0]; - } else { - maxattacks = innateattacks; - } + //maxattacks = nweps; // ie. all + + maxattacks = getmaxattacks(lf); /* // if we have a weapon, this takes the place of one of our // attacks. - // for monsters, pick which one to replace randomly. - // for players, never pick the weapon to replace randomly. - if (gotweapon && (nweps >= 2)) { - if (isplayer(lf)) { - validwep[rnd(1,nweps-1)] = B_FALSE; - } else { - validwep[rnd(0,nweps-1)] = B_FALSE; - } - } + // - for monsters, pick which one to replace randomly. + // - for players, never pick the weapon to replace randomly. */ + // # valid attacks higher than our allowed attacks? if (nweps > maxattacks) { int nvalid; int first; - // player never invalidates their weapon + // player never invalidates their equipped weapons if (isplayer(lf) && gotweapon) { - first = 1; + first = lastweaponidx+1; } else { first = 0; } @@ -256,6 +263,7 @@ int attackcell(lifeform_t *lf, cell_t *c) { } } + // remember initial cells for (i = 0; i < nweps; i++) { if (validwep[i]) { if (attacktype == AT_LF) { @@ -266,6 +274,14 @@ int attackcell(lifeform_t *lf, cell_t *c) { if (attackob(lf, (object_t *)attacktarget, wep[i], damflag[i])) break; } } + + // stop attacking if they somehow got out of range + // (eg. dodging) + if (attacktype == AT_LF) { + if (getcelldist(lf->cell, ((lifeform_t *)attacktarget)->cell) > 1) { + break; + } + } } // now kill all temp obs @@ -286,6 +302,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char attackername[BUFLEN]; char victimname[BUFLEN]; int fatal = B_FALSE; + int deflected = B_FALSE; int firstisbackstab = B_FALSE; int hit = B_FALSE; int critical = 0; @@ -347,8 +364,21 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // did you hit? ndam = 0; - if (rolltohit(lf, victim, wep, &critical)) { - hit = B_TRUE; + hit = rolltohit(lf, victim, wep, &critical); + + // deflection? + if (hit) { + object_t *dwep; + dwep = isdualweilding(victim); + if (dwep && (getskill(victim, SK_TWOWEAPON) >= PR_MASTER)) { + if (onein(4)) { + deflected = B_TRUE; + hit = B_FALSE; + } + } + } + + if (hit) { if (aidb) dblog(".oO { i hit! }"); // special case @@ -454,8 +484,6 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) ndam = 0; } - - if (ndam > 0) { flag_t *f; for (i = 0; i < ndam; i++) { @@ -464,11 +492,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) flag_t *rust; if (firstisbackstab && (i == 0)) backstab = B_TRUE; - dblog("initial dam[%d] = %d",i,dam[i]); + //dblog("initial dam[%d] = %d",i,dam[i]); if (lfhasflag(lf, F_HEAVYBLOW) || hasflag(wep->flags, F_HEAVYBLOW)) { dam[i] = (int)pctof(110,dam[i]); - dblog("heavy blow makes dam[%d] = %d",i,dam[i]); + //dblog("heavy blow makes dam[%d] = %d",i,dam[i]); } // modify for rust @@ -492,7 +520,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // modify based on resistances adjustdamlf(victim, &dam[i], damtype[i]); - dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); + //dblog("adjusted for lf to dam[%d] = %d",i,dam[i]); if (!backstab) { // modify for defender's armour @@ -500,7 +528,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) applyarmourdamreduction(victim, wep, reduceamt, &dam[i], damtype[i]); - dblog("reduced by armour to dam[%d] = %d",i,dam[i]); + //dblog("reduced by armour to dam[%d] = %d",i,dam[i]); } // will this hit be fatal? @@ -703,12 +731,33 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) addflag(lf->flags, F_ATTACHEDTO, victim->id, NA, NA, NULL); } } - } + + // retaliation happens even if victim died + for (f = victim->flags->first ; f ; f = f->next) { + if (f->id == F_RETALIATE) { + int rdam; + char damstring[BUFLEN]; + rdam = rolldie(f->val[0], f->val[1]); + if (cansee(player, victim)) { + msg("%s%s %s %s %s!", victimname, getpossessive(victimname), + noprefix(f->text), + getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp), + attackername); + } + sprintf(damstring, "%s%s %s", victimname, getpossessive(victimname), noprefix(f->text)); + losehp(lf, rdam, f->val[2], victim, damstring); + } + } + } else { // miss! if (aidb) dblog(".oO { i missed! }"); // announce it - if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { + if (deflected) { + if (cansee(player, lf)) { + msg("%s deflect%s %s%s attack.", victimname, isplayer(victim) ? "" : "s",attackername, getpossessive(attackername)); + } + } else if (lfhasflag(victim, F_MAGSHIELD) && ismetal(wep->material->id)) { if (isplayer(lf) || cansee(player, lf)) { sprintf(buf, "%s",attackername); @@ -763,6 +812,32 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) } } + // twoweapon? + if (hit) { + enum SKILLLEVEL slev; + slev = getskill(lf, SK_TWOWEAPON); + if (slev >= PR_SKILLED) { + object_t *secwep; + secwep = getsecmeleeweapon(lf); + // ie. if we are using two weapons, and the current one + // is the first... + if (secwep && (secwep != wep)) { + int bonus = 0; + // next hit will have enhanced accuracy + if (slev == PR_SKILLED) { + bonus = 10; + } else if (slev == PR_EXPERT) { + bonus = 25; + } else if (slev == PR_MASTER) { + bonus = 40; + } + if (bonus) { + addtempflag(lf->flags, F_ACCURACYMOD, bonus, NA, NA, NULL, 1); + } + } + } + } + if (aidb) dblog(".oO { doattack about to return B_FALSE }"); return B_FALSE; } @@ -1473,6 +1548,7 @@ int isphysicaldam(enum DAMTYPE damtype) { return B_FALSE; } +// returns true if we hit int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) { int acc,ev; int gothit; @@ -1540,7 +1616,6 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) acc += 50; } - // base 5% critical chance if (critical) { int critroll; @@ -1555,10 +1630,7 @@ int rolltohit(lifeform_t *lf, lifeform_t *victim, object_t *wep, int *critical) if (critroll >= 95) *critical = 1; } - if (acc < 0) acc = 0; - if (acc > 100) acc = 100; - - + limit(&acc, 0, 100); //if (aidb) dblog(".oO { my modified chance to hit is %d %% }", acc); myroll = rnd(1,100); diff --git a/defs.h b/defs.h index 2776e63..5a16b7f 100644 --- a/defs.h +++ b/defs.h @@ -4,7 +4,7 @@ // MACROS #define MAXOF(a,b) (a > b ? a : b) -#define PRACTICETIME 50 // #attempts it takes to learn new skill +#define PRACTICETIME 15 // #attempts it takes to learn new weapon skill #define WETTIME 10 // how long it takes for things to dry #define DRUNKTIME 10 // how long it takes for alcohol to wear off @@ -48,6 +48,7 @@ enum SKILL { SK_SPOTHIDDEN, SK_STEALTH, SK_TECHUSAGE, + SK_TWOWEAPON, // knowledge SK_LORE_ARCANA, SK_LORE_DEMONS, @@ -68,7 +69,7 @@ enum SKILL { SK_SS_DEATH, SK_SS_DIVINATION, SK_SS_FIRE, - SK_SS_ICE, + SK_SS_COLD, SK_SS_GRAVITY, SK_SS_LIFE, SK_SS_MODIFICATION, @@ -78,7 +79,7 @@ enum SKILL { SK_SS_TRANSLOCATION, SK_SS_WILD, }; -#define MAXSKILLS 39 +#define MAXSKILLS 40 // proficiency levels enum SKILLLEVEL { @@ -166,6 +167,8 @@ enum LFCONDITION { // if target lf is out of view for this many turns, abandon chase #define AI_FOLLOWTIME (10) +#define DEFAULTRESTHEALTIME (3) + // object confitions for random objects #define RO_NONE 0 @@ -209,8 +212,9 @@ enum LFCONDITION { #define MORESTRING "--More--" #define SOLDOUTSTRING "--SOLD OUT--" -// hunger constant -#define HUNGERCONST 10000 +// hunger constant - this is how many turns +// it will take to go from 'normal' to 'hungry' etc +#define HUNGERCONST 200 // LIMITS @@ -392,7 +396,7 @@ enum SPELLSCHOOL { SS_DEATH, SS_DIVINATION, SS_FIRE, - SS_ICE, + SS_COLD, SS_GRAVITY, SS_LIFE, SS_MODIFICATION, @@ -609,6 +613,7 @@ enum RACE { R_HAWKFROST, R_LEECH, R_NEWT, + R_PORCUPINE, R_RAT, R_SNAKE, R_SNAKECARPET, @@ -696,7 +701,8 @@ enum OBTYPE { // dungeon features OT_BOULDER, OT_STATUE, - OT_WOODENDOOR, + OT_DOORWOOD, + OT_DOORIRON, OT_WOODENTABLE, OT_WOODENBARREL, OT_WOODENSTOOL, @@ -727,20 +733,6 @@ enum OBTYPE { // corpses OT_CORPSE, OT_HEAD, - /* - OT_CORPSEEYEBAT, - OT_CORPSEBAT, - OT_CORPSEFLY, - OT_CORPSEGLOWBUG, - OT_CORPSEGOBLIN, - OT_CORPSEHUMAN, - OT_CORPSELIZARD, - OT_CORPSEOGRE, - OT_CORPSEORK, - OT_CORPSERODENT, - OT_CORPSETROLL, - OT_CORPSEWOLF, - */ // potions OT_POT_ACID, OT_POT_ACROBATICS, @@ -754,6 +746,7 @@ enum OBTYPE { OT_POT_GASEOUSFORM, OT_POT_HEALING, OT_POT_HEALINGMIN, + OT_POT_HEALINGMAJ, OT_POT_INVIS, OT_POT_INVULN, OT_POT_MAGIC, @@ -802,6 +795,7 @@ enum OBTYPE { OT_MAN_SPOTHIDDEN, OT_MAN_STEALTH, OT_MAN_TECHUSAGE, + OT_MAN_TWOWEAPON, // manuals of knowledge OT_MAN_LORE_ARCANA, OT_MAN_LORE_DEMONS, @@ -823,7 +817,7 @@ enum OBTYPE { OT_MAN_SS_DIVINATION, OT_MAN_SS_NATURE, OT_MAN_SS_FIRE, - OT_MAN_SS_ICE, + OT_MAN_SS_COLD, OT_MAN_SS_GRAVITY, OT_MAN_SS_LIFE, OT_MAN_SS_MODIFICATION, @@ -881,6 +875,7 @@ enum OBTYPE { // -- life OT_SB_HEALING, OT_SB_HEALINGMIN, + OT_SB_HEALINGMAJ, OT_SB_TURNUNDEAD, // -- mental / psionic OT_SB_MINDSCAN, @@ -964,6 +959,7 @@ enum OBTYPE { // -- life OT_S_HEALING, OT_S_HEALINGMIN, + OT_S_HEALINGMAJ, OT_S_TURNUNDEAD, // -- mental / psionic OT_S_MINDSCAN, @@ -1009,6 +1005,7 @@ enum OBTYPE { OT_S_SUMMONANIMALSSM, OT_S_SUMMONANIMALSMD, OT_S_SUMMONANIMALSLG, + OT_S_THORNS, OT_S_WARPWOOD, OT_S_WATERJET, // -- summoning @@ -1033,7 +1030,7 @@ enum OBTYPE { OT_A_LEARN, OT_A_LEVELUP, // abilities - OT_A_SUCKBLOOD, + OT_A_FLURRY, OT_A_GRAB, OT_A_CHARGE, OT_A_CRUSH, @@ -1041,6 +1038,7 @@ enum OBTYPE { OT_A_RAGE, OT_A_SPRINT, OT_A_STINGACID, // need to define dam in f_canwill + OT_A_SUCKBLOOD, OT_A_SWOOP, OT_A_EMPLOY, OT_A_HEAVYBLOW, @@ -1067,6 +1065,7 @@ enum OBTYPE { OT_WAND_WEAKNESS, OT_WAND_WONDER, // tools + OT_BLANKET, OT_BLINDFOLD, OT_BUGLAMP, OT_CANDLE, @@ -1092,7 +1091,9 @@ enum OBTYPE { OT_MOTIONSCANNER, OT_NVGOGGLES, OT_PAPERCLIP, + OT_SLEEPINGBAG, OT_TELEPAD, + OT_TENT, OT_XRAYGOGGLES, // misc objects OT_BONE, @@ -1507,7 +1508,7 @@ enum FLAG { //F_DAM, // val0 = ndice, val1 = nsidesondie, val2 = mod F_DAM, // v0 = damtype, text = 1d1+1 F_MISSILEDAM, // val0 = dam if it hits (without speed multiplier) - F_ACCURACY, // 100 - val0 = penalty to tohit% (ie. higher is better) + F_ACCURACY, // 100 - val0 = modify to tohit% (ie. higher is better) F_UNARMEDWEP, // this is not a real weapon, ie. claws, teeth etc F_ARMOURPIERCE, // goes through armour F_TWOHANDED, // weapon uses two hands to weild @@ -1520,6 +1521,11 @@ enum FLAG { F_FLAMESTRIKE, // causes fires where you hit F_BALANCE, // heals target if their maxhp < your maxhp F_REVENGE, // causes damage based on your hp + F_HELPSREST, // makes you heal mp/hp faster when using 'R' + // reduces skillcheck difficulty by v0. + // optional v1 = how many less turns between + // skillchecks. should not go more than + // DEFAULTRESTHEALTIME. // tech flags F_RNDCHARGES, // ob starts with between val0 and val1 charges // this will cause F_CHARGES to be filled in @@ -1588,6 +1594,7 @@ enum FLAG { F_DEBUG, // debugging enabled F_ACCURACYMOD, // modify your accuracy by val0 F_VEGETARIAN, // this lf will not eat meat. + F_PARTVEGETARIAN,// this lf will only eat if hunger >= 'hungry' F_SHIELDPENALTY, // lower your accuracy by val0 due to a cumbersome // shield F_LEVRACE, // at level v0, this race is promoted to race v1 @@ -1599,6 +1606,12 @@ enum FLAG { F_RESTHEALTIME, // val0 = how long to rest before healing hp F_RESTHEALAMT, // val0 = how many hp to gain after resting x turns F_RESTHEALMPAMT, // val0 = how many MP to gain after resting x turns + F_HOMEOB, // when this monster is auto generated on a level, place + // this object underneath them. + // text = object name + F_HOMELEVOB, // when this monster is auto generated on a level, place + // between v0 and v1 objects of type 'text' somewhere on + // the level. 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 @@ -1612,6 +1625,8 @@ enum FLAG { F_STARTHIDDENPCT, // val0 = pct chance auto-generated monster will // start off hidden F_CORPSETYPE, // text field specifies what corpse obtype to leave + F_CORPSEFLAG, // add flag v0 to our corpse. + // v1->v0, v2->v1, text->text F_MYCORPSE, // text field contains obid of my corpse. // (for ghosts) F_NOCORPSE, // monster's body crumbles to dust after death @@ -1644,6 +1659,8 @@ enum FLAG { // vanish. // v1 is lifetime left. this decrements each turn. // when at zero, lf vanishes. + F_HATESRACE, // lf will attack lfs with race=v0 or baseid=v0 on + // sight F_HOSTILE, // lf will attack the player if in sight F_FRIENDLY, // lf will attack all non-players if in sight F_WANTS, // lf will try to pick up object type val0. if @@ -1722,7 +1739,8 @@ enum FLAG { F_MAGICARMOUR,// armour is magically boosted. f->text is the description // ie 'magic armour', 'force field' // v0 is power left. - F_ASLEEP, // is asleep + F_ASLEEP, // is asleep. if v2 is set, means we are sleeping on + // purpose and will wake up when at full hp/mp/etc. F_ATTACHEDTO, // you are attached to lf id v0, and will move with it F_BEINGSTONED,// turn to stone when v0 drops to zero. (drops 1/turn) F_BLIND, // cannot see anything @@ -1795,6 +1813,9 @@ enum FLAG { F_RESISTMAG, // immunity to magic effects. v0=amt (1-20) F_MPREGEN, // regenerate MP at val0 per turn F_RAGE, // you are enraged. v0/v1 will be set to player's old hp/maxhp + F_RETALIATE, // deal damage to anyone who hits you + // v0=ndice, v1=dsides, v2=damtype, text=obname + // text must have at least TWO words F_RISEASGHOST, // become a ghost when you die. F_SEEINDARK, // nightvis range is val0 F_TREMORSENSE, // doesn't need eyes to see, can see in dark with v0 @@ -1831,8 +1852,8 @@ enum FLAG { F_STATGAINREADY, // ready to increase str/int etc. v2 is how many times // we can do it. F_INTERRUPTED, // somethign interrupted our rest. stop! - F_RESTING, // are we resting? cleared on any action other than rest. - // v2 = if not, NA it is the training counter. + F_TRAINING, // are we training? cleared on any action other than rest. + // v2 = if not NA, it is the training counter. // when it hits 0, you finish trainign. F_RESTUNTILHP, // resting until we have full hp F_RESTUNTILMP, // resting until we have full mp @@ -2018,7 +2039,8 @@ enum ERROR { // E_NOBP = 48, E_VEGETARIAN = 49, - E_NOOB = 50, + E_PARTVEGETARIAN= 50, + E_NOOB = 51, }; diff --git a/doc/glyphs.txt b/doc/glyphs.txt new file mode 100644 index 0000000..714e004 --- /dev/null +++ b/doc/glyphs.txt @@ -0,0 +1,37 @@ +@ = human +: = timid animal +} = gas cloud +) = dancing weapon +A = avian / bird +a = ant +B = bat + C = celestial / divine ? +d = canine/dog +e = eye +f = feline/cat +g = goblin +i = insect +j = jelly/ooze/leech +k = kobold +G = large goblin +n = small humanoid / nymph / sprite +o = orc +O = ogre +p = sPirit +c = cockatricoe +x = small creature/monster +q = quadraped +Q = large quadraped +r = rodent +s = snake +S = spider +h = humanoid +H = large humanoid +U = unearthly/demonic/horrific creature +w = worm +z = lizard-like creature +Z = undead + +--- +C +hybrid human animal? diff --git a/flag.c b/flag.c index f54206e..81fb373 100644 --- a/flag.c +++ b/flag.c @@ -105,7 +105,22 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, if ((gamemode == GM_GAMESTARTED)) { if (f->pile->owner) { if (announceflaggain(f->pile->owner, f)) { - addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL); // note: recursive call! + // don't include flags which interrupt will kill! + switch (f->id) { + case F_RUNNING: + case F_TRAINING: + case F_AUTOCMD: + break; + case F_ASLEEP: + if (f->val[2] == NA) { // ie. sleeping, not resting + addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL); + } + break; + default: + addflag(f->pile, F_INTERRUPTED, B_TRUE, NA, NA, NULL); + break; + } + f->known = B_TRUE; if (f->obfrom) { object_t *ob; @@ -198,6 +213,15 @@ void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime) { } } +int countflags(flagpile_t *fp) { + flag_t *f; + int count = 0; + for (f = fp->first ; f ; f = f->next) { + count++; + } + return count; +} + int flagcausesredraw(lifeform_t *lf, enum FLAG fid) { if (!lf) return B_FALSE; @@ -334,6 +358,7 @@ void killflag(flag_t *f) { lifeform_t *lf; int doredraw = B_FALSE; + lf = f->pile->owner; // flags which cause a redraw @@ -364,10 +389,15 @@ void killflag(flag_t *f) { if (announceflagloss(lf, f)) { // don't include flags which interrupt will kill! switch (f->id) { - case F_RESTING: case F_RUNNING: + case F_TRAINING: case F_AUTOCMD: break; + case F_ASLEEP: + if (f->val[2] != NA) { // ie. resting + addflag(lf->flags, F_INTERRUPTED, B_TRUE, NA, NA, NULL); + } + break; default: addflag(lf->flags, F_INTERRUPTED, B_TRUE, NA, NA, NULL); break; diff --git a/flag.h b/flag.h index 1af65aa..386529f 100644 --- a/flag.h +++ b/flag.h @@ -8,6 +8,7 @@ flag_t *addflag_real(flagpile_t *fp, enum FLAG id, int val1, int val2, int val3, flagpile_t *addflagpile(lifeform_t *owner, object_t *o); void copyflag(flagpile_t *dst, flagpile_t *src, enum FLAG id); void copyflags(flagpile_t *dst, flagpile_t *src, int lifetime); +int countflags(flagpile_t *fp); int flagcausesredraw(lifeform_t *lf, enum FLAG fid); int flagstacks(enum FLAG fid); int modcounter(flagpile_t *fp, int amt); diff --git a/io.c b/io.c index 9e0415e..7121d4c 100644 --- a/io.c +++ b/io.c @@ -62,6 +62,8 @@ extern lifeform_t *player; extern map_t *firstmap; +int gettinginput = B_FALSE; + int viewx = -9999,viewy = -9999; int vieww,viewh; @@ -516,18 +518,20 @@ cell_t *askcoords(char *prompt, int targettype) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "fleeing"); } - if (lfhasflag(c->lf, F_PRONE)) { + f = lfhasflag(c->lf, F_ASLEEP); + if (f) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + if (f->val[2] == NA) { + strcat(extrainfo, "sleeping"); + } else { + strcat(extrainfo, "resting"); + } + } else if (lfhasflag(c->lf, F_PRONE)) { + // prevent showing 'prone' AND 'asleep' if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "prone"); } - if (lfhasflag(c->lf, F_RESTING)) { - if (strlen(extrainfo)) strcat(extrainfo, ", "); - strcat(extrainfo, "resting"); - } - if (lfhasflag(c->lf, F_ASLEEP)) { - if (strlen(extrainfo)) strcat(extrainfo, ", "); - strcat(extrainfo, "asleep"); - } + f = lfhasflag(c->lf, F_ATTACHEDTO); if (lfhasflag(c->lf, F_ATTACHEDTO)) { lifeform_t *alf; @@ -602,6 +606,13 @@ cell_t *askcoords(char *prompt, int targettype) { if (strlen(extrainfo)) strcat(extrainfo, ", "); strcat(extrainfo, "enraged"); } + + for (f = c->lf->flags->first ; f ; f = f->next) { + if (f->id == F_RETALIATE) { + if (strlen(extrainfo)) strcat(extrainfo, ", "); + strcat(extrainfo, f->text); + } + } wep = getweapon(c->lf); if (wep && (c->lf->race->id != R_DANCINGWEAPON)) { @@ -859,7 +870,19 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { donesomething = B_TRUE; break; case F_ASLEEP: - msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s"); + if (isplayer(lf) && (f->val[2] != NA)) { // ie. resting + object_t *restob; + restob = getrestob(lf); + if (restob) { + char restobname[BUFLEN]; + getobname(restob, restobname, 1); + msg("You start resting (in your %s)...",noprefix(restobname)); + } else { + msg("You start resting (on the ground)..."); + } + } else { + msg("%s fall%s asleep.",lfname, isplayer(lf) ? "" : "s"); + } donesomething = B_TRUE; break; case F_ATTACHEDTO: @@ -1146,6 +1169,12 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { msg("%s enter%s a berzerker rage!", lfname, isplayer(lf) ? "" : "s"); donesomething = B_TRUE; break; + case F_RETALIATE: + msg("%s appear%s from %s%s skin.", noprefix(f->text), + (f->text[strlen(f->text)-1] == 's') ? "" : "s", + lfname, getpossessive(lfname)); + donesomething = B_TRUE; + break; case F_REGENERATES: if (isplayer(lf)) { // don't know if monsters get it msg("Your body's healing rate is enhanced!"); @@ -1584,6 +1613,12 @@ int announceflagloss(lifeform_t *lf, flag_t *f) { msg("%s %s less angry now.", lfname, isplayer(lf) ? "feel" : "seems"); donesomething = B_TRUE; break; + case F_RETALIATE: + msg("%s disappear%s from %s%s skin.", noprefix(f->text), + (f->text[strlen(f->text)-1] == 's') ? "" : "s", + lfname, getpossessive(lfname)); + donesomething = B_TRUE; + break; case F_REGENERATES: if (isplayer(lf)) { // don't know if monsters lose it msg("Your healing rate is no longer enhanced."); @@ -1931,7 +1966,7 @@ object_t *doaskobject(obpile_t *op, char *prompt, int *count, long opts, ...) { wantflag[nwantflags] = va_arg(flags, enum FLAG); } va_end(flags); - dblog("nwantflags is %d",nwantflags); + //dblog("nwantflags is %d",nwantflags); // remember player's current ammo if (op->owner) { @@ -2883,6 +2918,9 @@ void describeob(object_t *o) { case F_PRODUCESLIGHT: mvwprintw(mainwin, y, 0, "%s produces light.", buf); y++; break; + case F_RETALIATE: + mvwprintw(mainwin, y, 0, "%s protects you with %s.", buf, f->text); y++; + break; case F_RAGE: mvwprintw(mainwin, y, 0, "%s makes you enraged.", buf); y++; break; @@ -3171,6 +3209,7 @@ void docomms(void) { char buf[BUFLEN]; char lfname[BUFLEN]; char ch; + flag_t *f; where = askcoords("Talk to who?", TT_MONSTER); if (where && where->lf && cansee(player, where->lf)) { @@ -3194,7 +3233,9 @@ void docomms(void) { if (isadjacent(lf->cell, player->cell) && !lfhasflag(lf, F_NOPACK)) { addchoice(&prompt, 't', "Trade items with me", NULL, NULL); } - if (lfhasflag(lf, F_RESTING)) { + + f = isresting(lf); + if (f) { addchoice(&prompt, 'r', "Stop resting.", NULL, NULL); } else { addchoice(&prompt, 'r', "Rest until you are healed.", NULL, NULL); @@ -3240,7 +3281,8 @@ void docomms(void) { msg("Cancelled."); return; case 'r': - if (lfhasflag(lf, F_RESTING)) { + f = isresting(lf); + if (f) { stopresting(lf); } else { if (needstorest(lf, NULL)) { @@ -4465,7 +4507,7 @@ void dorest(void) { } } } else { - if (countnearbyallies(player)) { + if (countnearbyhurtallies(player)) { strcpy(ques, "Rest until nearby allies are healed?"); ch = askchar(ques, "yn", "y", B_TRUE); if (ch == 'y') { @@ -5252,11 +5294,13 @@ int getkey(void) { key_code = getch(); // XXX NEW CODE: - if (strcmp(msgbuf, "")) { - clearmsg(); - //strcpy(msgbuf, ""); - //drawmsg(); - //drawcursor(); + if (gettinginput) { + if (strcmp(msgbuf, "")) { + clearmsg(); + //strcpy(msgbuf, ""); + //drawmsg(); + //drawcursor(); + } } return keycodetokey(key_code); @@ -5347,7 +5391,9 @@ void handleinput(void) { f->val[0]--; } } else { + gettinginput = B_TRUE; ch = getkey(); + gettinginput = B_FALSE; } gotcmd = B_TRUE; @@ -5823,7 +5869,7 @@ void drawstatus(void) { wprintw(statwin, " Next:%ld",xpleft); } // blinded? - if (isblind(player)) { + if (isblind(player) && !lfhasflag(player, F_ASLEEP)) { setcol(statwin, C_RED); wprintw(statwin, " Blind"); unsetcol(statwin, C_RED); @@ -5836,7 +5882,15 @@ void drawstatus(void) { } // paralysed somehow? - if (isimmobile(player)) { + if (isresting(player)) { + setcol(statwin, C_CYAN); + wprintw(statwin, " Resting"); + unsetcol(statwin, C_CYAN); + } else if (lfhasflag(player, F_ASLEEP)) { + setcol(statwin, C_BLUE); + wprintw(statwin, " Asleep"); + unsetcol(statwin, C_BLUE); + } else if (isimmobile(player)) { setcol(statwin, C_RED); wprintw(statwin, " Immobile"); unsetcol(statwin, C_RED); @@ -6283,14 +6337,17 @@ void showlfstats(lifeform_t *lf, int showall) { int y = 0, y2 = 0, x2 = 40; int x; int arating, evasion; - int speed,acc; + int acc; + char actbuf[BUFLEN],movebuf[BUFLEN]; int h; char buf[BUFLEN],buf2[BUFLEN]; job_t *j; flag_t *f; char *ftext= "%12s: "; long xpneeded; - object_t *w; + object_t *o; + object_t *w[2]; + int nweps = 0; objecttype_t *ot; int first; int i; @@ -6552,73 +6609,91 @@ void showlfstats(lifeform_t *lf, int showall) { // now go to second column + mvwprintw(mainwin, y2, x2, ftext, "# Attacks"); + wprintw(mainwin, "%d", getmaxattacks(lf)); y2++; + y2++; // current weapon + dam - w = getweapon(lf); - if (w) { - int mindam,maxdam; - int bonus; - // weapon - sprintf(buf, "%s", w->type->name); - mvwprintw(mainwin, y2, x2, ftext, "Weapon"); - wprintw(mainwin, "%-20s", buf); y2++; + nweps = 0; - if (showall) { - // damage - f = hasflag(w->flags, F_BONUS); - if (f && f->known) { - // only tell player about bonuses if they are known.! - bonus = f->val[0]; - } else { - bonus = 0; - } - - f = hasflag(w->flags, F_DAM); - if (f) { - getdamrange(f, &mindam, &maxdam); - } else { - mindam = 0; - maxdam = 0; - } - - mindam += bonus; - maxdam += bonus; - - // apply damage mod for strength - if (!hasflag(w->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { - mindam = (int)((float)mindam * dammod); - maxdam = (int)((float)maxdam * dammod); - } - - if (mindam < 0) mindam = 0; - if (maxdam < 0) maxdam = 0; - - sprintf(buf, "%d-%d",(int)mindam,(int)maxdam); - - mvwprintw(mainwin, y2, x2, ftext, "Weapon Dmg"); - wprintw(mainwin, "%-20s", buf); y2++; - - // chance to hit - acc = getlfaccuracy(lf, w); - mvwprintw(mainwin, y2, x2, ftext, "Wep.Accuracy"); - wprintw(mainwin, "%d%%", acc); y2++; - - // attack speed - speed = getattackspeed(lf); - getspeedname(speed, buf); - capitalise(buf); - mvwprintw(mainwin, y2, x2, ftext, "Attack Speed"); - wprintw(mainwin, "%-20s", buf); y2++; + o = getweapon(lf); + if (o) w[nweps++] = o; + o = getsecmeleeweapon(lf); + if (o) { + // can't be the same as the first one! + if ((nweps == 1) && (o == w[0])) { + } else { + w[nweps++] = o; } - } else { - // no damage - sprintf(buf, "N/A"); - mvwprintw(mainwin, y2, x2, ftext, "Current Weapon"); - wprintw(mainwin, "%-20s", buf); y2++; } + for (i = 0; i < nweps; i++) { + if (w[i]) { + int mindam,maxdam; + int bonus,speed; + + // weapon + if (showall) { + char buf2[BUFLEN]; + // calculate damage + f = hasflag(w[i]->flags, F_BONUS); + if (f && f->known) { + // only tell player about bonuses if they are known.! + bonus = f->val[0]; + } else { + bonus = 0; + } + + f = hasflag(w[i]->flags, F_DAM); + if (f) { + getdamrange(f, &mindam, &maxdam); + } else { + mindam = 0; + maxdam = 0; + } + + mindam += bonus; + maxdam += bonus; + + // apply damage mod for strength + if (!hasflag(w[i]->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { + mindam = (int)((float)mindam * dammod); + maxdam = (int)((float)maxdam * dammod); + } + + if (mindam < 0) mindam = 0; + if (maxdam < 0) maxdam = 0; + + + sprintf(buf, "%s (%d-%d dmg)", w[i]->type->name,(int)mindam,(int)maxdam); + mvwprintw(mainwin, y2, x2, ftext, "Weapon"); + wprintw(mainwin, "%-20s", buf); y2++; + + // attack speed + acc = getlfaccuracy(lf, w[i]); + speed = getattackspeed(lf); + getspeedname(speed, buf2); + capitalise(buf2); + sprintf(buf, "%s, %d%%",buf2,acc); + mvwprintw(mainwin, y2, x2, ftext, "Speed/Acc"); + wprintw(mainwin, "%-20s", buf); y2++; + + } else { + // just show weapon name + sprintf(buf, "%s", w[i]->type->name); + mvwprintw(mainwin, y2, x2, ftext, "Weapon"); + wprintw(mainwin, "%-20s", buf); y2++; + } + } else { + // no weapon + sprintf(buf, "N/A"); + mvwprintw(mainwin, y2, x2, ftext, "Current Weapon"); + wprintw(mainwin, "%-20s", buf); y2++; + } + } // end for each weapon + // skip a line y2++; @@ -6675,7 +6750,7 @@ void showlfstats(lifeform_t *lf, int showall) { // no attacks at all? - if (!w && !op->first) { + if ((nweps == 0) && !op->first) { sprintf(buf, "N/A"); mvwprintw(mainwin, y2, x2, ftext, "Attack"); wprintw(mainwin, "%-20s", buf); y2++; @@ -6709,18 +6784,17 @@ void showlfstats(lifeform_t *lf, int showall) { y2++; // skip line } - speed = getactspeed(lf); - getspeedname(speed, buf); - capitalise(buf); - mvwprintw(mainwin, y2, x2, ftext, "Action Speed"); + getspeednameshort(getactspeed(player), actbuf); + getspeednameshort(getmovespeed(player), movebuf); + if (!strcmp(actbuf, movebuf)) { + sprintf(buf, "%s", actbuf); + capitalise(buf); + } else { + sprintf(buf, "Mv:%s Act:%s", movebuf,actbuf); + } + + mvwprintw(mainwin, y2, x2, ftext, "Speed"); wprintw(mainwin, "%-20s", buf); y2++; - - speed = getmovespeed(lf); - getspeedname(speed, buf); - capitalise(buf); - mvwprintw(mainwin, y2, x2, ftext, "Move Speed"); - wprintw(mainwin, "%-20s", buf); y2++; - y2++; // skip line @@ -6993,6 +7067,17 @@ void showlfstats(lifeform_t *lf, int showall) { y++; } + f = lfhasflag(lf, F_RETALIATE); + if (f && (f->known)) { + if (showall || (lorelev >= PR_BEGINNER)) { + mvwprintw(mainwin, y, 0, "%s %s covered by %s (%dd%d %s dmg to attackers).", you(lf), is(lf), f->text, + f->val[0], f->val[1], getdamname(f->val[2])); + } else { + mvwprintw(mainwin, y, 0, "%s %s covered by %s", you(lf), is(lf), f->text); + } + y++; + } + // fleeing? if (showall) { for (f = lf->flags->first ; f ; f = f->next) { diff --git a/lf.c b/lf.c index 6678463..7b08e89 100644 --- a/lf.c +++ b/lf.c @@ -489,6 +489,12 @@ int caneat(lifeform_t *lf, object_t *o) { reason = E_VEGETARIAN; return B_FALSE; } + if (lfhasflag(lf, F_PARTVEGETARIAN) && (o->material->id == MT_FLESH)) { + if (gethungerlevel(gethungerval(player)) < H_HUNGRY) { + reason = E_PARTVEGETARIAN; + return B_FALSE; + } + } // ai lifeforms won't eat tainted food if (!isplayer(lf)) { @@ -817,12 +823,17 @@ int canwear(lifeform_t *lf, object_t *o, enum BODYPART where) { } int canweild(lifeform_t *lf, object_t *o) { - object_t *oo; flag_t *f; enum BODYPART weildloc,otherloc; weildloc = getweildloc(o, &otherloc, NULL); + // already weilding it? + if (isequipped(o)) { + reason = E_ALREADYUSING; + return B_FALSE; + } + // special case... if (lf->race->id == R_DANCINGWEAPON) { return B_TRUE; @@ -866,17 +877,6 @@ int canweild(lifeform_t *lf, object_t *o) { reason = E_OK; - // already weilding it? - for (oo = lf->pack->first ; oo ; oo = oo->next) { - f = hasflagval(oo->flags, F_EQUIPPED, BP_WEAPON, -1, -1, NULL); - if (f) { - if (oo == o) { // already weilding it - reason = E_ALREADYUSING; - return B_FALSE; - } - } - } - // trying to fight unarmed, but no unarmed attack? if (o == NULL) { @@ -1110,6 +1110,16 @@ float comparelfs(lifeform_t *lf1, lifeform_t *lf2) { return ratio; } +int countinnateattacks(lifeform_t *lf) { + int count = 0; + flag_t *f; + for (f = lf->flags->first ; f; f = f->next) { + if (f->id == F_HASATTACK) count++; + } + return count; +} + + int countmoney(lifeform_t *lf) { object_t *o; int amt = 0; @@ -1133,6 +1143,20 @@ int countnearbyallies(lifeform_t *lf) { return count; } +int countnearbyhurtallies(lifeform_t *lf) { + lifeform_t *l; + int count = 0; + + for (l = lf->cell->map->lf ; l ; l = l->next) { + if ((l != lf) && areallies(l, lf)) { + if (l->hp != l->maxhp) { + count++; + } + } + } + return count; +} + // toggle debugging void debug(lifeform_t *lf) { char lfname[BUFLEN]; @@ -1359,6 +1383,13 @@ void die(lifeform_t *lf) { if (corpse->type->id == OT_CORPSE) { colourmatchob(corpse, lf); } + + // add extra flags ? + for (f = lf->flags->first ; f ; f = f->next) { + if (f->id == F_CORPSEFLAG) { + addflag(corpse->flags, f->val[0], f->val[1], f->val[2], NA, f->text); + } + } } @@ -1624,6 +1655,9 @@ int eat(lifeform_t *lf, object_t *o) { case E_VEGETARIAN: msg("The thought of eating flesh disgusts you."); break; + case E_PARTVEGETARIAN: + msg("You aren't hungry enough to eat meat yet."); + break; case E_WRONGOBTYPE: default: msg("You can't eat that!"); @@ -2027,11 +2061,14 @@ object_t *eyesshaded(lifeform_t *lf) { int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { char lfname[BUFLEN]; - getlfname(lf,lfname); + if (isdead(lf)) return B_TRUE; if (lfhasflag(lf, F_STABILITY) || !hasbp(lf, BP_FEET)) { return B_TRUE; } + + getlfname(lf,lfname); + if (announce) { if (isplayer(lf) || cansee(player, lf)) { if (fromlf) { @@ -2043,15 +2080,27 @@ int fall(lifeform_t *lf, lifeform_t *fromlf, int announce) { } } } - taketime(lf, getactspeed(lf)); + taketime(lf, SP_NORMAL*2); addflag(lf->flags, F_PRONE, B_TRUE, NA, NA, NULL); loseconcentration(lf); return B_FALSE; } +int fallasleep(lifeform_t *lf, int howlong) { + if (lfhasflag(lf, F_ASLEEP)) { + return B_TRUE; + } + + killflagsofid(lf->flags, F_TRAINING); + + addtempflag(lf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong); + return B_FALSE; +} + // make 'lf' respond to damage void fightback(lifeform_t *lf, lifeform_t *attacker) { + interrupt(lf); // special cases if ((lf->race->id == R_STIRGE) || (lf->race->id == R_LEECH)) { @@ -3110,7 +3159,7 @@ object_t *getequippedob(obpile_t *op, enum BODYPART bp) { object_t *getfirearm(lifeform_t *lf) { object_t *o; o = getequippedob(lf->pack, BP_SECWEAPON); - if (o && hasflag(o->flags, F_FIREARM)) { + if (o && isfirearm(o)) { return o; } o = getequippedob(lf->pack, BP_WEAPON); @@ -3279,13 +3328,23 @@ int getlastdir(lifeform_t *lf) { int getlfaccuracy(lifeform_t *lf, object_t *wep) { flag_t *f; - int acc = 0; + // get weapon if (wep) { acc = getobaccuracy(wep, lf); } + // dual weilding? + if (isdualweilding(lf)) { + switch (getskill(lf, SK_TWOWEAPON)) { + case PR_INEPT: acc -= 100; break; + case PR_NOVICE: acc -= 20; break; + case PR_BEGINNER: acc -= 10; break; + default: break; + } + } + for (f = lf->flags->first ;f ; f = f->next) { if (f->id == F_ACCURACYMOD) { acc += f->val[0]; @@ -3301,8 +3360,14 @@ int getlfaccuracy(lifeform_t *lf, object_t *wep) { // assume maximum dex acc += 50; } else { + int dexmod; // modify with dexterity - acc += getstatmod(lf, A_DEX); + dexmod = getstatmod(lf, A_DEX); + // double dex penalties when dual weilding + if (isdualweilding(lf) && (dexmod < 0)) { + dexmod *= 2; + } + acc += dexmod; } // modify for blindness @@ -3507,6 +3572,30 @@ enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid) { return slev; } +int getmaxattacks(lifeform_t *lf) { + flag_t *f; + int maxattacks; + f = lfhasflag(lf, F_MAXATTACKS); + if (f) { + maxattacks = f->val[0]; + } else { + maxattacks = countinnateattacks(lf); + } + + // if we have high unarmed skill and our second hand is free, + // we get one more attack + if (getskill(lf, SK_UNARMED) >= PR_ADEPT) { + if (!getequippedob(lf->pack, BP_SECWEAPON)) { + maxattacks++; + } + } + + if (getskill(lf, SK_TWOWEAPON) && isdualweilding(lf)) { + maxattacks++; + } + return maxattacks; +} + float getmaxcarryweight(lifeform_t *lf) { float max; float mod; @@ -3853,6 +3942,27 @@ float getlfweight(lifeform_t *lf, int withobs) { return weight; } +object_t *getsecmeleeweapon(lifeform_t *lf) { + object_t *o; + o = getequippedob(lf->pack, BP_SECWEAPON); + if (o && ismeleeweapon(o)) { + return o; + } + + return NULL; +} + +object_t *getshield(lifeform_t *lf) { + object_t *o; + o = getequippedob(lf->pack, BP_SECWEAPON); + if (o && isshield(o)) { + return o; + } + + return NULL; +} + + int getspellspeed(lifeform_t *lf) { int speed = 0; flag_t *f; @@ -4050,7 +4160,7 @@ race_t *getrandomrace(map_t *map, int forcedepth) { race_t *poss[MAXRANDOMLFCANDIDATES]; int nposs = 0; int selidx; - int db = B_TRUE; + int db = B_FALSE; int depth; int raritymin,raritymax; @@ -4155,6 +4265,23 @@ race_t *getreallyrandomrace(void) { return r; } +object_t *getrestob(lifeform_t *lf) { + object_t *o,*bestob = NULL; + int bestval = -1; + flag_t *f; + for (o = lf->pack->first; o ; o = o->next) { + f = hasflag(o->flags, F_HELPSREST); + if (f) { + if (!bestob && (f->val[0] > bestval)) { + bestval = f->val[0]; + bestob = o; + } + } + } + + return bestob; +} + // returns proficiency level in a given skill enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id) { flag_t *f; @@ -4443,7 +4570,10 @@ object_t *getweapon(lifeform_t *lf) { return o; } } - return NULL; + + + // no primary weapon. do we have a secondary one? + return getsecmeleeweapon(lf); } long getxpforlev(int level) { @@ -4559,7 +4689,7 @@ void givejob(lifeform_t *lf, enum JOB jobid) { } // } else { - if (db) dblog("processing normal flag: %d",f->id); + //if (db) dblog("processing normal flag: %d",f->id); /* switch (f->id) { @@ -4730,6 +4860,7 @@ int giveskill(lifeform_t *lf, enum SKILL id) { f = addflag(lf->flags, F_HASSKILL, id, PR_NOVICE, NA, NULL); if (isplayer(lf) && (gamemode == GM_GAMESTARTED)) { msg("You have learned the %s %s skill!", getskilllevelname(PR_NOVICE), getskillname(sk->id)); + more(); } // special effects for gaining a skill. @@ -4753,7 +4884,7 @@ int giveskill(lifeform_t *lf, enum SKILL id) { // special effects based on skill level if (id == SK_ATHLETICS) { if (f->val[1] == PR_ADEPT) { - newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, NA, NA, NULL); + newf = addflag(lf->flags, F_CANWILL, OT_A_JUMP, 3, 3, NULL); newf->lifetime = FROMJOB; } } else if (id == SK_FIRSTAID) { @@ -4797,9 +4928,32 @@ int giveskill(lifeform_t *lf, enum SKILL id) { if (tf && !isknownot(ot) && (tf->val[0] <= f->val[1])) { // then make it known! makeknown(ot->id); + if (isplayer(lf)) { + object_t *o; + o = hasob(lf->pack, ot->id); + if (o) { + char buf[BUFLEN]; + getobname(o, buf, o->amt); + msgnocap("%c - %s", o->letter, buf); + } + } } } } + } else if (id == SK_TWOWEAPON) { + if ((gamemode == GM_GAMESTARTED) && isplayer(lf)) { + if (f->val[1] == PR_NOVICE) { + msg("You can now weild two weapons at once."); + } else if (f->val[1] == PR_ADEPT) { + msg("You no longer suffer an accuracy penalty when weilding two weapons."); + } else if (f->val[1] == PR_SKILLED) { + msg("Follow-up attacks with your second weapon are now more accurate."); + } else if (f->val[1] == PR_EXPERT) { + addflag(lf->flags, F_CANWILL, OT_A_FLURRY, 3, 3, "pw:1;"); + } else if (f->val[1] == PR_MASTER) { + msg("You can now deflect attacks with your second weapon."); + } + } } else if (id == SK_SS_ALLOMANCY) { // give all allomantic spells mayusespellschool(lf->flags, SS_ALLOMANCY, F_CANCAST); @@ -5220,7 +5374,11 @@ int lockpick(lifeform_t *lf, object_t *target, object_t *device) { } removeob(device, 1); } else if (faileffect == B_BLUNTONFAIL) { - makeduller(device, 1); + if (!makeduller(device, 1)) { + if (isplayer(lf) || cansee(player, lf)) { + msg("%s fail%s to unlock %s.",lfname, isplayer(lf) ? "" : "s", obname); + } + } } else { if (isplayer(lf) || cansee(player, lf)) { msg("%s fail%s to unlock %s.",lfname, isplayer(lf) ? "" : "s", obname); @@ -5408,7 +5566,6 @@ int haslos(lifeform_t *viewer, cell_t *dest) { map = dest->map; - x1 = viewer->cell->x; y1 = viewer->cell->y; x2 = dest->x; @@ -5423,7 +5580,7 @@ int haslos(lifeform_t *viewer, cell_t *dest) { } // can't see if you're blind - if (lfhasflag(viewer, F_BLIND)) { + if (isblind(viewer)) { return B_FALSE; } @@ -5638,6 +5795,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_POLEARMS, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); addflag(lastjob->flags, F_LEVABIL, 3, OT_A_HEAVYBLOW, 3, NULL); addflag(lastjob->flags, F_LEVABIL, 4, OT_A_WARCRY, 4, NULL); addflag(lastjob->flags, F_LEVABIL, 5, OT_A_CHARGE, 5, NULL); @@ -5663,11 +5821,11 @@ void initjobs(void) { 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_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_TECHUSAGE, PR_BEGINNER, 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_DRUID, "Druid"); @@ -5693,7 +5851,7 @@ void initjobs(void) { // abilities mayusespellschool(lastjob->flags, SS_NATURE, F_CANCAST); addflag(lastjob->flags, F_HASPET, NA, NA, NA, "young wolf"); - addflag(lastjob->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); + addflag(lastjob->flags, F_PARTVEGETARIAN, B_TRUE, NA, NA, NULL); addjob(J_PLUMBER, "Plumber"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "spanner"); @@ -5709,7 +5867,7 @@ void initjobs(void) { 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); + addflag(lastjob->flags, F_CANLEARN, SK_SS_COLD, 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"); @@ -5782,6 +5940,7 @@ void initjobs(void) { addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_STAVES, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_UNARMED, NA, NA, NULL); + addflag(lastjob->flags, F_CANLEARN, SK_TWOWEAPON, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_SS_DIVINATION, 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); @@ -5829,7 +5988,7 @@ void initjobs(void) { 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_COLD, 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); @@ -5929,7 +6088,6 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, 5, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "2d4+1"); @@ -5990,7 +6148,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:1d6;"); addflag(lastrace->flags, F_CANWILL, OT_A_CHARGE, NA, NA, "range:5;"); - addrace(R_DARKMANTLE, "darkmantle", 70, 'Q', C_BLUE, MT_FLESH, RC_MAGIC); + addrace(R_DARKMANTLE, "darkmantle", 70, 'U', C_BLUE, MT_FLESH, RC_MAGIC); addflag(lastrace->flags, F_STARTHIDDENPCT, 80, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_MIGHTY, NA, NULL); @@ -6016,7 +6174,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); - addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "0d6+5"); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); @@ -6046,7 +6203,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); - addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SPELLCASTING, PR_EXPERT, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); @@ -6424,7 +6580,7 @@ void initrace(void) { addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 15, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, 5, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d3"); @@ -6495,7 +6651,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 50, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, 0, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); @@ -6549,7 +6704,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); addflag(lastrace->flags, F_HITDICE, 13, 8, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -6578,7 +6732,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 45, NA, NULL); addflag(lastrace->flags, F_HITDICE, 35, 0, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); @@ -6666,7 +6819,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 81, NA, NULL); addflag(lastrace->flags, F_HITDICE, 3, 3, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); @@ -6732,7 +6884,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); - addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASSKILL, SK_SS_MENTAL, PR_EXPERT, NA, NULL); @@ -6790,7 +6941,6 @@ void initrace(void) { addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, NULL); addflag(lastrace->flags, F_HITDICE, 5, 0, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); @@ -6804,7 +6954,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_FEET, NA, NA, NULL); - addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_ACIDATTACK, NA, NA, "1d6+5"); addflag(lastrace->flags, F_TREMORSENSE, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_WALK, NA, NA, "^slurping"); @@ -6859,7 +7008,7 @@ void initrace(void) { addrace(R_XAT, "xat", 2, 'x', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_SIZE, SZ_TINY, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 95, NA, NULL); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -6891,32 +7040,10 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, 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_TREMORSENSE, 10, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^flapping wings"); - addrace(R_ANT, "giant worker ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); - 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_ARMOURRATING, 4, NA, NA, NULL); - addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); - addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); - addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); - addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); - addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); - addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); - 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_HANDS, 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_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4"); - addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); - addrace(R_BEAR, "black bear", 150, 'b', C_BLUE, MT_FLESH, RC_ANIMAL); + addrace(R_BEAR, "black bear", 150, 'q', C_BLUE, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); @@ -6934,7 +7061,7 @@ void initrace(void) { addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d4;"); - addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'b', C_BROWN, MT_FLESH, RC_ANIMAL); + addrace(R_BEARGRIZZLY, "grizzly bear", 200, 'q', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 52, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); @@ -6954,6 +7081,25 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); addflag(lastrace->flags, F_CRITKNOCKDOWN, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_BLEEDABIL, OT_A_RAGE, NA, NA, NULL); + addrace(R_ANT, "giant ant", 20, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); + lastrace->baseid = R_ANT; + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 85, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 1, 0, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); + 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_HANDS, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, NA, NA, "0d1+4"); + addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addrace(R_ANTS, "giant soldier ant", 25, 'a', C_BROWN, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -6962,14 +7108,12 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, 4, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); 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_HANDS, 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_HASATTACK, OT_TEETH, NA, NA, "0d1+4"); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:1d8+3;"); @@ -6986,14 +7130,12 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_DEX, DX_AVERAGE, NA, NULL); addflag(lastrace->flags, F_HITDICE, 6, 0, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); - addflag(lastrace->flags, F_EVASION, 0, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); 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_HANDS, 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_HASATTACK, OT_TEETH, NA, NA, "5d4"); addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, "dam:2d4;"); @@ -7013,7 +7155,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_VEGETARIAN, B_TRUE, NA, NA, NULL); @@ -7038,7 +7179,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); @@ -7061,13 +7201,11 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_WANTSOBFLAG, F_EDIBLE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); - addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL); // 'A' for Avian lastrace->baseid = R_HAWK; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 75, NA, ""); @@ -7202,10 +7340,27 @@ void initrace(void) { 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_HANDS, 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_DTRESIST, DT_FIRE, B_TRUE, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addrace(R_PORCUPINE, "giant porcupine", 10, 'r', C_GREY, MT_FLESH, RC_ANIMAL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HATESRACE, R_ANT, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 90, NA, ""); + addflag(lastrace->flags, F_HITDICE, 2, 1, NA, ""); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, NA, NA, "1d4"); + addflag(lastrace->flags, F_MAXATTACKS, 1, NA, NA, NULL); + addflag(lastrace->flags, F_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); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 2, NA, NA, NULL); + addflag(lastrace->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp spines"); + addflag(lastrace->flags, F_CORPSEFLAG, F_SHARP, 1, 4, NULL); addrace(R_RAT, "giant rat", 3, 'r', C_BROWN, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, ST_VWEAK, NA, NULL); @@ -7221,8 +7376,6 @@ void initrace(void) { 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); - addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); @@ -7342,7 +7495,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANWILL, OT_A_GRAB, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_CRUSH, NA, NA, "dam:2d6;"); addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); - addrace(R_SPIDER, "giant spider", 5, 'S', C_GREEN, MT_FLESH, RC_ANIMAL); + addrace(R_SPIDER, "giant spider", 5, 'S', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_DEX, DX_DEXTROUS, NA, NULL); @@ -7357,12 +7510,13 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:1;"); - 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_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); + addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "1-10 webs"); addrace(R_SPIDERFUNNELWEB, "giant funnelweb", 5, 'S', C_MAGENTA, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 63, NA, ""); @@ -7381,12 +7535,13 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:2;"); - 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_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); + addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "20-30 webs"); addrace(R_SPIDERREDBACK, "giant redback", 5, 'S', C_RED, MT_FLESH, RC_ANIMAL); lastrace->baseid = R_SPIDER; addflag(lastrace->flags, F_RARITY, H_DUNGEON, 78, NA, ""); @@ -7405,12 +7560,13 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); // don't announce spellcasting addflag(lastrace->flags, F_CANWILL, OT_S_WEB, 3, 3, "pw:3;"); - 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_LIGHT, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_POISONOUS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_HOMEOB, NA, NA, NA, "web"); + addflag(lastrace->flags, F_HOMELEVOB, NA, NA, NA, "10-20 webs"); addrace(R_WOLFYOUNG, "young wolf", 5, 'd', C_GREY, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -7425,7 +7581,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 4, NA, NA, NULL); @@ -7447,7 +7602,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 5, NA, NA, NULL); @@ -7455,7 +7609,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, NA, NA, "whines in pain^whining"); // insects - addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_GREEN, MT_FLESH, RC_ANIMAL); + addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL); addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); @@ -7491,7 +7645,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SECWEAPON, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, 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_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); @@ -7515,7 +7668,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, 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_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); @@ -7537,7 +7689,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_HANDS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, 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_NOISETEXT, N_GETANGRY, NA, NA, "buzzes angrily^an angry buzzing"); addflag(lastrace->flags, F_NOISETEXT, N_FLY, NA, NA, "^buzzing"); @@ -7546,7 +7697,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_SUCKBLOOD, NA, NA, "dam:1d4;"); - addrace(R_CENTIPEDE, "giant centipede", 3, 'c', C_GREEN, MT_FLESH, RC_INSECT); + addrace(R_CENTIPEDE, "giant centipede", 3, 'w', C_GREEN, MT_FLESH, RC_INSECT); addflag(lastrace->flags, F_RARITY, H_DUNGEON, 80, NA, ""); addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -7578,7 +7729,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, NA, ""); addflag(lastrace->flags, F_HITDICE, 1, 0, NA, ""); addflag(lastrace->flags, F_EVASION, 60, NA, NA, NULL); - addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d2"); + addflag(lastrace->flags, F_HASATTACK, OT_ZAPPER, NA, NA, "1d2-1"); 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); @@ -7711,7 +7862,6 @@ void initrace(void) { addflag(lastrace->flags, F_NOBODYPART, BP_SHOULDERS, NA, NA, NULL); addflag(lastrace->flags, F_NOBODYPART, BP_LEGS, NA, NA, NULL); 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_TREMORSENSE, 4, NA, NA, NULL); addflag(lastrace->flags, F_DTIMMUNE, DT_ALL, NA, NA, NULL); @@ -7762,6 +7912,10 @@ int isbleeding(lifeform_t *lf) { int isblind(lifeform_t *lf) { if (!lf) return B_FALSE; + + if (lfhasflag(lf, F_ASLEEP)) { + return B_TRUE; + } if (lfhasflag(lf, F_BLIND)) { return B_TRUE; } @@ -7770,6 +7924,7 @@ int isblind(lifeform_t *lf) { return B_TRUE; } } + return B_FALSE; } @@ -7886,6 +8041,20 @@ flag_t *isdrunk(lifeform_t *lf) { return lfhasflag(lf, F_DRUNK); } +// returns second weapon if you are dual weilding +object_t *isdualweilding(lifeform_t *lf) { + object_t *priwep,*secwep; + // dual weilding? + priwep = getweapon(lf); + secwep = getsecmeleeweapon(lf); + if (priwep && secwep) { + if (priwep != secwep) { // twohanded weapons dont count + return secwep; + } + } + return B_FALSE; +} + int isfleeing(lifeform_t *lf) { if (lfhasflag(lf, F_FLEEFROM)) { return B_TRUE; @@ -8045,6 +8214,9 @@ int isprone(lifeform_t *lf) { if (lfhasflag(lf, F_PRONE)) { return B_TRUE; } + if (lfhasflag(lf, F_ASLEEP)) { + return B_TRUE; + } return B_FALSE; } @@ -8067,6 +8239,15 @@ flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt) { return NULL; } +flag_t *isresting(lifeform_t *lf) { + flag_t *f; + f = lfhasflag(lf, F_ASLEEP); + if (f && (f->val[2] != NA)) { + return f; + } + return NULL; +} + object_t *isstuck(lifeform_t *lf) { object_t *o; @@ -8555,10 +8736,6 @@ void autoskill(lifeform_t *lf) { slev = PR_ADEPT; } - if (lf == player) { - dblog("test"); - } - for (o = lf->pack->first ; o ; o = o->next) { if (isweapon(o) && canweild(lf, o)) { sk = getobskill(o); @@ -8904,21 +9081,23 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml } // low hitpoint warning - if (isplayer(lf)) { - int warnthresh; - warnthresh = (int)((float)0.25 * (float)lf->maxhp); - if (lf->hp <= warnthresh) { - warn("*** LOW HITPOINT WARNING ***"); - more(); - } - } else if (prebleed != postbleed) { - if (ispetof(lf, player) && !canhear(player, lf->cell)) { - warn("You feel worried about your %s.", noprefix(lfname)); - } else { - makenoise(lf, N_LOWHP); - } - if (ispetof(lf, player)) { - more(); + if (amt > 0) { + if (isplayer(lf)) { + int warnthresh; + warnthresh = (int)((float)0.25 * (float)lf->maxhp); + if (lf->hp <= warnthresh) { + warn("*** LOW HITPOINT WARNING ***"); + more(); + } + } else if (prebleed != postbleed) { + if (ispetof(lf, player) && !canhear(player, lf->cell)) { + warn("You feel worried about your %s.", noprefix(lfname)); + } else { + makenoise(lf, N_LOWHP); + } + if (ispetof(lf, player)) { + more(); + } } } // you wake up if you were hit! @@ -9141,8 +9320,7 @@ int modattr(lifeform_t *lf, enum ATTRIB attr, int amt) { } // enforce limits - if (lf->att[attr] > 18) lf->att[attr] = 18; - if (lf->att[attr] < 0) lf->att[attr] = 0; + limit(&lf->att[attr], 0, 18); if ((gamemode == GM_GAMESTARTED) && (amt != 0) && (isplayer(lf) || cansee(player, lf))) { char lfname[BUFLEN], verb[BUFLEN], adverb[BUFLEN]; @@ -9254,10 +9432,10 @@ void modhunger(lifeform_t *lf, int amt) { statdirty = B_TRUE; - if ((posthlev >= H_PECKISH) && (amt > 0)) { + if ((posthlev >= H_VHUNGRY) && (amt > 0)) { stopresting(lf); } - if (posthlev >= H_STARVING) { + if (posthlev > H_STARVING) { useringofmiracles(lf, 2); // reset hunger f->val[0] = 0; @@ -9297,11 +9475,16 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { // if anything nearby hears it, it might respond for (l = c->map->lf; l ; l = l->next) { if (l != noisemaker) { + int difficulty; //if (canhear(l, c) && haslos(l, c)) { - if (canhear(l, c) && (haslos(l, c) || skillcheck(l, SC_LISTEN, 17, 0))) { + + // listen check difficulty is based on sound distance vs max hearing distance + difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 18); + + if (canhear(l, c) && (haslos(l, c) || skillcheck(l, SC_LISTEN, difficulty, 0))) { flag_t *f; // announce? - if (isplayer(l) && !lfhasflag(l, F_RESTING) && !lfhasflag(l, F_ASLEEP)) { + if (isplayer(l) && !lfhasflag(l, F_ASLEEP)) { // never say "you hear xxx" if you can see the lf that caused the noise. if (noisemaker && cansee(l, noisemaker)) { if (seetext) { @@ -9380,8 +9563,23 @@ void noise(cell_t *c, lifeform_t *noisemaker, char *text, char *seetext) { if (f->lifetime > 0) { // ie. temporary timeeffectsflag(f, rnd(1,10)); } else if (f->lifetime == PERMENANT) { - // wake up! - killflag(f); + if (f->val[2] == NA) { // ie asleep rather than 'resting' + // wake up! + if (isplayer(l)) { + msg("A nearby noise awakens you!"); + } + killflag(f); + } else { + // ie resting on purpose via 'r' + // only wake up if the sound if very close + if (getcelldist(c, l->cell) == 1) { + // wake up! + if (isplayer(l)) { + msg("A nearby noise awakens you!"); + } + killflag(f); + } + } // make it temporary //f->lifetime = rnd(1,10); } @@ -9784,6 +9982,12 @@ void relinklf(lifeform_t *src, map_t *dst) { // strat resting... void startresting(lifeform_t *lf, int willtrain) { int traincounter; + + if (isplayer(lf)) { + statdirty = B_TRUE; + needredraw = B_TRUE; + } + if (willtrain) { traincounter = 50; traincounter = modifybystat(traincounter, player, A_IQ); @@ -9794,7 +9998,11 @@ void startresting(lifeform_t *lf, int willtrain) { // stop hiding killflagsofid(lf->flags, F_HIDING); - addflag(lf->flags, F_RESTING, B_TRUE, NA, traincounter, NULL); + if (willtrain) { + addflag(lf->flags, F_TRAINING, B_TRUE, NA, traincounter, NULL); + } else { + addflag(lf->flags, F_ASLEEP, B_TRUE, NA, B_TRUE, NULL); + } // stop movement for all allies if (isplayer(lf)) { @@ -9807,14 +10015,11 @@ void startresting(lifeform_t *lf, int willtrain) { } if (isplayer(lf)) { - msg("You start %s...",(traincounter == NA) ? "resting" : "training"); + if (willtrain) { + msg("You start training..."); + } drawmsg(); drawcursor(); - } else if (cansee(player, lf)) { - char buf[BUFLEN]; - getlfname(lf, buf); - capitalise(buf); - msg("%s starts resting.",buf); } } @@ -10371,6 +10576,7 @@ void initskills(void) { 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_CHANNELING, "Channeling", "Lets you make better use of magical items."); + addskill(SK_TWOWEAPON, "Dual Weilding", "Allows you to weild two melee weapons at once."); 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_SPOTHIDDEN, "Searching", "Helps you to spot hidden traps or creatures."); @@ -10396,7 +10602,7 @@ void initskills(void) { addskill(SK_SS_DEATH, "Necromancy", "Boosts casting of spells from this school."); addskill(SK_SS_DIVINATION, "Divination", "Boosts casting of spells from this school."); addskill(SK_SS_FIRE, "Fire Magic", "Boosts casting of spells from this school."); - addskill(SK_SS_ICE, "Ice Magic", "Boosts casting of spells from this school."); + addskill(SK_SS_COLD, "Cold Magic", "Boosts casting of spells from this school."); addskill(SK_SS_GRAVITY, "Gravitation Magic", "Boosts casting of spells from this school."); addskill(SK_SS_LIFE, "Life Magic", "Boosts casting of spells from this school."); addskill(SK_SS_MODIFICATION, "Modification", "Boosts casting of spells from this school."); @@ -10526,7 +10732,12 @@ int real_skillcheck(lifeform_t *lf, enum CHECKTYPE ct, int diff, int mod, int *r attrib = getevasion(lf) / 5; break; case SC_LISTEN: - attrib = (getskill(lf, SK_LISTEN)*2); + // if you are asleep, listen check doesn't help. + if (lfhasflag(lf, F_ASLEEP)) { + attrib = 0; + } else { + attrib = (getskill(lf, SK_LISTEN)*2); + } break; case SC_RESISTMAG: attrib = (getattr(lf, A_CON)/4) + (getattr(lf, A_IQ)/4) + getmr(lf); @@ -10681,6 +10892,7 @@ int skillcheckvs(lifeform_t *lf1, enum CHECKTYPE ct1, int mod1, lifeform_t *lf2, return B_FALSE; } + int slipon(lifeform_t *lf, object_t *o) { char obname[BUFLEN]; char lfname[BUFLEN]; @@ -10695,7 +10907,7 @@ int slipon(lifeform_t *lf, object_t *o) { // slip! if (isplayer(lf) || cansee(player, lf)) { char damstring[BUFLEN]; - msg("%s slip%s on %s.",lfname, isplayer(lf) ? "" : "s", obname); + msg("%s slip%s on %s and falls to the ground.",lfname, isplayer(lf) ? "" : "s", obname); sprintf(damstring, "slipping on %s",obname); losehp(lf, 1, DT_FALL, NULL, damstring); } @@ -10825,27 +11037,35 @@ int stone(lifeform_t *lf) { void stopresting(lifeform_t *lf) { flag_t *f; - // stop resting! - f = hasflag(lf->flags, F_RESTING); - if (f) { - int training = B_FALSE; - if (f->val[2] != NA) { - training = B_TRUE; - } - /* - if (training && f->val[2] == 0) { - killflag(f); - */ - //lf->timespent = 0; + if (isplayer(lf)) { + statdirty = B_TRUE; + needredraw = B_TRUE; + } + + // stop training + f = hasflag(lf->flags, F_TRAINING); + if (f) { killflag(f); if (isplayer(lf)) { - msg("Your %s is interrupted!", training ? "training" : "rest"); + msg("Your training is interrupted!"); } else if (cansee(player, lf)) { char buf[BUFLEN]; getlfname(lf, buf); capitalise(buf); - msg("%s stops %s.",buf, training ? "training" : "resting"); + msg("%s stops training.",buf); + } + } + // stop resting! + f = isresting(lf); + if (f) { + killflag(f); + if (isplayer(lf)) { + msg("Your rest is interrupted!"); + } else if (cansee(player, lf)) { + char buf[BUFLEN]; + getlfname(lf, buf); + msg("%s stops resting.",buf); } } } @@ -10992,12 +11212,11 @@ void taketime(lifeform_t *lf, long howlong) { } int throwat(lifeform_t *thrower, object_t *o, cell_t *where) { - if (!hasbp(thrower, BP_HANDS)) { if (isplayer(thrower)) msg("You have no hands to throw with!"); return B_TRUE; } - taketime(thrower, SPEED_THROW); + taketime(thrower, getactspeed(thrower)); return fireat(thrower, o, 1, where, getthrowspeed(getattr(thrower, A_STR)), NULL); } @@ -11107,6 +11326,9 @@ void turneffectslf(lifeform_t *lf) { } } + // get more hungry + modhunger(lf, 1); + // regeneration sumflags(lf->flags, F_REGENERATES, &i, NULL, NULL); if (i > 0) { @@ -12132,10 +12354,20 @@ int rest(lifeform_t *lf, int onpurpose) { int hpheal = 1; flag_t *rf; int training = B_FALSE; + int resting = B_FALSE; + object_t *restob = NULL; - rf = lfhasflag(lf, F_RESTING); - if (rf && rf->val[2] != NA) { + + rf = lfhasflag(lf, F_TRAINING); + if (rf) { training = B_TRUE; + } else { + rf = isresting(lf); + if (rf) { + resting = B_TRUE; + // ie. resting via 'R' + restob = getrestob(lf); + } } taketime(lf, getactspeed(lf)); @@ -12170,154 +12402,126 @@ int rest(lifeform_t *lf, int onpurpose) { healtime = ff->val[0]; } else { // 3 turns = heal 1 hp - healtime = 3; + healtime = DEFAULTRESTHEALTIME; + } + + // modify via restob if resting using 'R' + if (restob) { + if (rf->val[1] != NA) { + healtime -= rf->val[1]; + limit(&healtime, 1, NA); + } } if (f->val[0] >= healtime) { + int difficulty; + if (isplayer(lf)) { + // ie. for hp, at con <= 4 and no first aid skill, you NEVER Heal! + difficulty = 25; + } else { + // ai passes more easily + difficulty = 10; + } + + // modify difficulty if you're resting properly via 'R' + if (resting && restob) { + flag_t *f; + f = hasflag(restob->flags, F_HELPSREST); + if (f) { + difficulty -= f->val[0]; + limit(&difficulty, 0, NA); + } + } + //if (isplayer(lf)) msg("hp given."); if (lf->hp < lf->maxhp) { - int difficulty; // pass a skill check to regain hp - if (isplayer(lf)) { - // ie. at con <= 4 and no first aid skill, you NEVER Heal! - difficulty = 25; - } else { - // ai passes more easily - difficulty = 10; - } - if (skillcheck(lf, SC_CON, 25, getskill(lf, SK_FIRSTAID))) { + if (skillcheck(lf, SC_CON, difficulty, getskill(lf, SK_FIRSTAID))) { gainhp(lf, hpheal); } } if (lf->mp < getmaxmp(lf)) { // pass a skill check to regain mp - if (skillcheck(lf, SC_IQ, 25, getskill(lf, SK_SPELLCASTING))) { + if (skillcheck(lf, SC_IQ, difficulty, getskill(lf, SK_SPELLCASTING))) { gainmp(lf, mpheal); } } killflag(f); - } } } - // if resting/training with 'R'... - if (rf) { + if (training) { wantclearmsg = B_FALSE; - if (training) { - rf->val[2]--; - if (rf->val[2] == 0) { - // ask about gaining skills - if (isplayer(lf)) { - msg("You finish training."); - more(); - } - killflag(rf); // kill resting/training flag. + rf->val[2]--; + if (rf->val[2] == 0) { + // ask about gaining skills + if (isplayer(lf)) { + msg("You finish training."); + more(); + } + killflag(rf); // kill resting/training flag. - //if (lf->skillpoints || getattpoints(player)) { - //if (isplayer(lf)) more(); - enhanceskills(lf); - //} - /* - 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; + enhanceskills(lf); + } + } else if (resting) { + // just asleep/resting + wantclearmsg = B_FALSE; + flag_t *hf; + int fullpartyrest = B_FALSE; - 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."); + // resting + if (lf->hp >= lf->maxhp) { + hf = lfhasflag(lf, F_RESTUNTILHP); + if (hf) killflag(hf); + } + if (lf->mp >= getmaxmp(lf)) { + hf = lfhasflag(lf, F_RESTUNTILMP); + if (hf) killflag(hf); + } + + hf = lfhasflag(lf, F_RESTUNTILALLIES); + if (hf) { + int moretogo = B_FALSE; + lifeform_t *l; + + fullpartyrest = B_TRUE; + + for (l = lf->cell->map->lf ; l ; l = l->next) { + if ((l != lf) && areallies(l, lf)) { + if (l->hp < l->maxhp) { + moretogo = B_TRUE; + break; } } - */ - } - } else { - flag_t *hf; - int fullpartyrest = B_FALSE; - - // resting - if (lf->hp >= lf->maxhp) { - hf = lfhasflag(lf, F_RESTUNTILHP); - if (hf) killflag(hf); + if (!moretogo) { + killflag(hf); } - if (lf->mp >= getmaxmp(lf)) { - hf = lfhasflag(lf, F_RESTUNTILMP); - if (hf) killflag(hf); - } - - hf = lfhasflag(lf, F_RESTUNTILALLIES); - if (hf) { - int moretogo = B_FALSE; - lifeform_t *l; - - fullpartyrest = B_TRUE; - - for (l = lf->cell->map->lf ; l ; l = l->next) { - if ((l != lf) && areallies(l, lf)) { - if (l->hp < l->maxhp) { - moretogo = B_TRUE; - break; - } - } - } - if (!moretogo) { - killflag(hf); + } + + if (!lfhasflag(lf, F_RESTUNTILHP) && + !lfhasflag(lf, F_RESTUNTILMP) && + !lfhasflag(lf, F_RESTUNTILALLIES)) { + if (isplayer(lf)) { + if (fullpartyrest) { + msg("Your party has finished resting."); + } else { + msg("You finish resting."); } + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s finishes resting.",lfname); } - - if (!lfhasflag(lf, F_RESTUNTILHP) && - !lfhasflag(lf, F_RESTUNTILMP) && - !lfhasflag(lf, F_RESTUNTILALLIES)) { - if (isplayer(lf)) { - if (fullpartyrest) { - msg("Your party has finished resting."); - } else { - msg("You finish resting."); - } - } else if (cansee(player, lf)) { - char lfname[BUFLEN]; - getlfname(lf, lfname); - msg("%s finishes resting.",lfname); - } - killflag(rf); - wantclearmsg = B_FALSE; - } - } // end if resting/training - } // end if (rf) - } + killflag(rf); + wantclearmsg = B_FALSE; + } + } + } // end if !poisoned if (onpurpose && wantclearmsg) { if (isplayer(lf)) { @@ -12554,7 +12758,6 @@ int weild(lifeform_t *lf, object_t *o) { statdirty = B_TRUE; } - if (o) { getobname(o, buf, o->amt); } @@ -12619,6 +12822,26 @@ int weild(lifeform_t *lf, object_t *o) { return B_TRUE; } + // if we are skilled at twoweaponing, and somehting is in the way, + // ask if we want to use our other hand. + if (!twohanded && hasbp(lf, otherloc)) { + oo = getequippedob(lf->pack, weildloc); + if (getskill(lf, SK_TWOWEAPON) && oo && !hasflag(oo->flags, F_TWOHANDED)) { + char buf2[BUFLEN]; + char ch; + sprintf(buf2, "Weild %s in your left hand?",buf); + ch = askchar(buf2, "yn","y", B_TRUE); + if (ch == 'y') { + enum BODYPART temp; + // swap locations. + temp = weildloc; + weildloc = otherloc; + otherloc = temp; + } + } + } + + // any other objects in the way? for (oo = lf->pack->first ; oo ; oo = oo->next) { f = hasflagval(oo->flags, F_EQUIPPED, weildloc, -1, -1, NULL); if (f) { diff --git a/lf.h b/lf.h index a5824ec..d866f13 100644 --- a/lf.h +++ b/lf.h @@ -34,8 +34,10 @@ int cantakeoff(lifeform_t *lf, object_t *o); int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *targob, cell_t *targcell); void checkxp(enum RACE rid); float comparelfs(lifeform_t *lf1, lifeform_t *lf2); +int countinnateattacks(lifeform_t *lf); int countmoney(lifeform_t *lf); int countnearbyallies(lifeform_t *lf); +int countnearbyhurtallies(lifeform_t *lf); void debug(lifeform_t *lf); void die(lifeform_t *lf); void dumplev(void); @@ -45,6 +47,7 @@ int eat(lifeform_t *lf, object_t *o); void enhanceskills(lifeform_t *lf); object_t *eyesshaded(lifeform_t *lf); int fall(lifeform_t *lf, lifeform_t *fromlf, int announce); +int fallasleep(lifeform_t *lf, int howlong); void fightback(lifeform_t *lf, lifeform_t *attacker); job_t *findjob(enum JOB jobid); job_t *findjobbyname(char *name); @@ -105,6 +108,7 @@ char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer); glyph_t *getlfglyph(lifeform_t *lf); enum MATERIAL getlfmaterial(lifeform_t *lf); enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid); +int getmaxattacks(lifeform_t *lf); float getmaxcarryweight(lifeform_t *lf); float getmaxliftweight(lifeform_t *lf); int getmaxmp(lifeform_t *lf); @@ -121,6 +125,8 @@ char *getlfnamea(lifeform_t *lf, char *buf); 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); int getspellspeed(lifeform_t *lf); char *getplayername(char *buf); char *getplayernamefull(char *buf); @@ -133,6 +139,7 @@ object_t *getrandomarmour(lifeform_t *lf); //int getrandommonlevel(int depth); race_t *getrandomrace(map_t *map, int forcedepth); race_t *getreallyrandomrace(void); +object_t *getrestob(lifeform_t *lf); enum SKILLLEVEL getskill(lifeform_t *lf, enum SKILL id); char *getspeedname(int speed, char *buf); char *getspeednameshort(int speed, char *buf); @@ -177,6 +184,7 @@ enum BURDENED isburdened(lifeform_t *lf); int ischarmable(lifeform_t *lf); int isdead(lifeform_t *lf); flag_t *isdrunk(lifeform_t *lf); +object_t *isdualweilding(lifeform_t *lf); int isfleeing(lifeform_t *lf); int isfreebp(lifeform_t *lf, enum BODYPART bp); int isfriendly(lifeform_t *lf); @@ -193,6 +201,7 @@ flag_t *ispoisoned(lifeform_t *lf); int ispolymorphed(lifeform_t *lf); int isprone(lifeform_t *lf); flag_t *isresistantto(flagpile_t *fp, enum DAMTYPE dt); +flag_t *isresting(lifeform_t *lf); object_t *isstuck(lifeform_t *lf); flag_t *isvulnto(flagpile_t *fp, enum DAMTYPE dt); void killjob(job_t *job); diff --git a/log.txt b/log.txt index 682f75b..9ed9d1f 100644 --- a/log.txt +++ b/log.txt @@ -2,612 +2,5 @@ ====== NEW LOGFILE ==== -xxx -xxx -xxx -xxx -xxx -xxx -xxx -xxx -xxx -xxx -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -finding random lf with rarity val 92-100 - --> possibility: kobold, rarity=95 --> possibility: xat, rarity=95 --> possibility: giant bat, rarity=95 --> possibility: giant newt, rarity=100 --> possibility: giant rat, rarity=95 -got 5 possibilities. -rollhitdice() - rolling 2d4 + 2 -rollhitdice() - mod is +44% -rollhitdice() ---- die 1/2 == 4 -rollhitdice() ---- die 2/2 == 4 -TOTAL: 8 - -> modified to: 11 -test givejob() starting. -processing normal flag: 228 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 174 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 175 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 173 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 263 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 175 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 260 -processing normal flag: 338 -test -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { cannot see my master - adding F_TARGETCELL for last known loc } -.oO { something going to targecell: 1, 2 } -.oO { walking from 1,4 towards f_targetcell (1,2) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,3 } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving randomly } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { cannot see my master - adding F_TARGETCELL for last known loc } -.oO { your young wolf going to targecell: 1, 1 } -.oO { walking from 1,3 towards f_targetcell (1,1) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,2 } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { didn't find any obs i want } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving randomly } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { cannot see my master - adding F_TARGETCELL for last known loc } -.oO { something going to targecell: 1, 1 } -.oO { walking from 3,1 towards f_targetcell (1,1) ... } -.oO { successfully walked towards f_targetcell. arrived at 2,1 } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { didn't find any obs i want } -.oO { walking from 2,1 towards f_targetcell (1,1) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,1 } -.oO { arrived at f_targetcell. removing. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { i can see my master - moving towards them } -.oO { success. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { cannot see my master - adding F_TARGETCELL for last known loc } -.oO { something going to targecell: 1, 13 } -.oO { walking from 1,10 towards f_targetcell (1,13) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,11 } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { didn't find any obs i want } -.oO { walking from 1,11 towards f_targetcell (1,13) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,12 } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { didn't find any obs i want } -.oO { walking from 1,12 towards f_targetcell (1,13) ... } -.oO { successfully walked towards f_targetcell. arrived at 1,13 } -.oO { arrived at f_targetcell. removing. } -AIMOVE: your young wolf -.oO { looking for covetted objects... } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { looking for any ob which i want. } -.oO { no targetcell, so looking for remote objects } -.oO { didn't find any obs i want } -.oO { i do not have a target or can't move towards it. } -.oO { i am friendly to the player. looking for a target. } -.oO { cannot see my master and am at last known loc. trying last known dir (Southeast) } -.oO { ...successfully } diff --git a/map.c b/map.c index 2200062..6e15582 100644 --- a/map.c +++ b/map.c @@ -45,6 +45,27 @@ cell_t *addcell(map_t *m, int x, int y) { return cell; } +void addhomeobs(lifeform_t *lf) { + flag_t *f; + for (f = lf->flags->first ; f ; f = f->next) { + if (f->id == F_HOMEOB) { + addob(lf->cell->obpile, f->text); + } else if (f->id == F_HOMELEVOB) { + int i,amt; + amt = rnd(f->val[0],f->val[1]); + for (i = 0; i < amt; i++) { + cell_t *c; + // pick new EMPTY random spot + c = getrandomcell(lf->cell->map); + while (!cellwalkable(NULL, c, NULL)) { + c = getrandomcell(lf->cell->map); + } + addob(c->obpile, f->text); + } + } + } +} + map_t *addmap(void) { map_t *a; int id; @@ -166,7 +187,6 @@ lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int auto newlf->born = B_FALSE; if (lfhasflag(lf, F_ASLEEP)) addflag(newlf->flags, F_ASLEEP, B_TRUE, NA, NA, NULL); newlf->born = B_TRUE; - } } } @@ -735,6 +755,7 @@ void createmap(map_t *map, int depth, int habitat) { cell_t *cell, *c; object_t *o; int db = B_FALSE; + lifeform_t *lf; // parameters int turnpct = DEF_TURNPCT; @@ -1240,33 +1261,11 @@ void createmap(map_t *map, int depth, int habitat) { c = getrandomroomcell(map, i); // if nothing there if (c && isempty(c) && !countobs(c->obpile)) { - /* - if (roomspecial[i]) { - if (getrand(1,4) == 1) { // less chance of monster - addlifeform(x, y, curz,getrandommonster(curz), - getrand(1,curz+1), C_AI, B_FALSE, B_TRUE); - } else { - //add objects based on room type - if (roomspecial[i] == SP_MEDLAB) { - addspecialroomob(x, y, curz, SP_MEDLAB, - OR, 3, OP_AI_HEALS, OP_REVIVES); - } else if (roomspecial[i] == SP_COMPLAB) { - addspecialroomob(x, y, curz, SP_COMPLAB, - OR, 0); - } else if (roomspecial[i] == SP_ALIENNEST) { - addspecialroomob(x, y, curz, SP_ALIENNEST, - OR, 0); - } - } - } else { - */ // slightly more chance of objects in rooms addrandomthing(c,60); done = B_TRUE; - //dblog("----> Success ob at (%d,%d).",c->x,c->y); } else { ntries++; - //dblog("----> Failed, now at retry #%d/%d",ntries, numobs); } if (ntries >= numobs) { @@ -1280,132 +1279,11 @@ void createmap(map_t *map, int depth, int habitat) { if (db) dblog("Finished adding objects."); - /* - // some extra monsters in corridors - for (i = 0; i < getrand(3,8); i++) { - int x,y; - lifeform_t *lf; - lf = addlifeform(rand() % MAZEW, rand() % MAZEH,curz,getrandommonster(curz), getrand(1,curz+1), C_AI, B_FALSE, B_TRUE); - done = B_FALSE; - while (!done) { - getrandomcell(&x, &y, curz,C_EMPTY ); - if (isempty(x,y,curz)) { - lf->x = x; - lf->y = y; - lf->z = curz; - done = B_TRUE; - } - } + + // add home objects + for (lf = map->lf ; lf ; lf = lf->next) { + addhomeobs(lf); } - */ - - - /* - - // add a fixed revival booth - done = B_FALSE; - while (!done) { - getrandomcell(&x,&y, curz,C_ROOM); // get a random cell in a room - if (isempty(x,y,curz)) { - if (!cellhasobject(x,y,curz)) { - done = B_TRUE; - } - } - } - addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_REVIVAL); - - // emergency lighting - for (y = 0; y < MAZEH; y++) { - for (x = 0; x < MAZEW; x++) { - if (getfloor(x,y,curz) == C_EMPTY) { - if (isempty(x,y,curz) && !hasdangerousobject(NULL,x,y,curz)) { - // chance of a light... - int lightchance = 5; - int roll = getrand(1,100); - if (roll <= lightchance) { - addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_EMERGLIGHT); - } - } - } - } - } - - // add the reactor - done = B_FALSE; - while (!done) { - getrandomcell(&x,&y, curz,C_ROOM); // get a random cell in a room - if (getdistance(x,y,wreck->dockpos.x,wreck->dockpos.y) >= 20) { - if (isempty(x,y,curz)) { - if (!cellhasobject(x,y,curz)) { - done = B_TRUE; - } - } - } - } - wreck->mazelev[curz].reactorpos.x = x; - wreck->mazelev[curz].reactorpos.y = y; - addobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_REACTOR); - wreck->mazelev[curz].powered = B_TRUE; - wreck->mazelev[curz].lightlevel = getrand(50,100); - -//printf("reactor at %d,%d,%d\n",x,y,curz); - - // all empty cells around it change - for (cury = y-2 ; cury <= y+2; cury++) { - for (curx = x-2 ; curx <= x+2; curx++) { - if (isonmap(curx,cury,curz)) { - if (!issolid(curx,cury,curz)) { - wreck->mazelev[curz].maze[cury*MAZEW+curx].floor = C_EMPTYHAZARD; - } - } - } - } - - - // calculate level difficulty - wreck->mazelev[curz].mondifficulty = 0; - wreck->mazelev[curz].mapdifficulty = 0; - - // monsters - for (lf = wreck->mazelev[curz].lifeform ; lf ; lf = lf->next) { - if (lf->controller != C_HUMAN) { - wreck->mazelev[curz].mondifficulty += (getrdifficulty(lf->race)); - } - } - // maze layout & objects - for (y = 0; y < MAZEH; y++) { - for (x = 0; x < MAZEW; x++) { - switch (numexits(x,y,curz)) { - case 2: // corner - wreck->mazelev[curz].mapdifficulty += 0.5; - break; - case 1: // dead end - wreck->mazelev[curz].mapdifficulty += 1; - break; - } - - if (containerhasobject(&wreck->mazelev[curz].maze[y*MAZEW+x].floorobs, O_SPAWNPIT)) { - wreck->mazelev[curz].mondifficulty += DF_SPAWNPIT; - } - } - } - - // fix exithp - for (y = 0; y < MAZEH; y++) { - for (x = 0; x < MAZEW; x++) { - int d; - for (d = D_NORTH ; d <= D_WEST; d++) { - int extype = getexit(x,y,curz,d); - if (isbreakableexit(getexit(x,y,curz,d))) { - // using setexit will make sure the hp is right - setexit(x,y,curz,d,extype); - } - } - } - } - */ - - //printf("*** Level difficulty is %0.2f\n", getmazedifficulty(curz)); map->beingcreated = B_FALSE; } @@ -2499,11 +2377,19 @@ int linkstairs(object_t *o) { void makedoor(cell_t *cell) { object_t *o; map_t *m; + char doorbuf[BUFLEN]; m = cell->map; - setcelltype(cell, getemptycelltype(cell->map->habitat)); - o = addob(cell->obpile, "wooden door"); + setcelltype(cell, getemptycelltype(m->habitat)); + + if ((rnd(1,100) + m->depth) >= 66) { + strcpy(doorbuf, "iron door"); + } else { + strcpy(doorbuf, "wooden door"); + } + + o = addob(cell->obpile, doorbuf); if (o && (rnd(1,2) == 1)) { opendoor(NULL, o); } else { diff --git a/map.h b/map.h index 9b4f072..568a2ef 100644 --- a/map.h +++ b/map.h @@ -1,6 +1,7 @@ #include "defs.h" cell_t *addcell(map_t *map, int x, int y); +void addhomeobs(lifeform_t *lf); map_t *addmap(void); lifeform_t *addmonster(cell_t *c, enum RACE raceid, int jobok, int amt, int autogen); void addrandomob(cell_t *c); diff --git a/move.c b/move.c index 300b447..fd6dc00 100644 --- a/move.c +++ b/move.c @@ -484,11 +484,22 @@ int getdirtowards(cell_t *src, cell_t *dst, lifeform_t *srclf, int wantcheck, in return bestdir; } + +// use 'n/a' for zero chance of falling. 0 means 'calculate based on distance' int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallcheckdiff) { int i; char lfname[BUFLEN]; + char newlfname[BUFLEN]; int seen; - int hitwall = B_FALSE; + int mightfall = B_TRUE; + cell_t *newcell; + lifeform_t *newlf; + + // calculate chance of falling + if (fallcheckdiff == 0) { + // chance based on distance + fallcheckdiff = howfar*10; + } getlfname(lf,lfname); if (cansee(player, lf)) { @@ -519,11 +530,31 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc switch (reason) { case E_WALLINWAY: case E_OFFMAP: - msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s"); + if (seen) msg("%s slam%s into a wall!",lfname,isplayer(lf) ? "" : "s"); losehp(lf, rnd(1,6), DT_BASH, pusher, "slamming into a wall"); - hitwall = B_TRUE; // stop moving i = howfar; + // don't fall + mightfall = B_FALSE; + break; + case E_LFINWAY: + newcell = getcellindir(lf->cell, dir); + newlf = newcell->lf; + if (newlf) { // should always be true + int momentumleft; + getlfname(newlf, newlfname); + if (seen) msg("%s slam%s into %s!",lfname,isplayer(lf) ? "" : "s",newlfname); + // remember our momentum + momentumleft = howfar - i; + // stop moving + i = howfar; + // higher chance of both falling + if (fallcheckdiff != NA) { + fallcheckdiff += (momentumleft*5); + } + // confer our remaining momentum on to them + knockback(newcell->lf, dir, momentumleft, lf, fallcheckdiff); // NOTE: recursive call + } break; default: break; @@ -531,16 +562,13 @@ int knockback(lifeform_t *lf, int dir, int howfar, lifeform_t *pusher, int fallc } } - // if you ran into a wall, it will prevent you from falling back. - if (!hitwall) { - int diff; - if (fallcheckdiff) { - diff = fallcheckdiff; - } else { - diff = howfar*10; - } + if (fallcheckdiff == NA) { + mightfall = B_FALSE; + } + + if (mightfall) { // save to avoid falling - if (!skillcheck(lf, SC_FALL, howfar*10, 0)) { + if (!skillcheck(lf, SC_FALL, fallcheckdiff, 0)) { fall(lf, NULL, B_TRUE); } } @@ -622,6 +650,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { int preroom = -1, postroom = -1; int prespeed = B_FALSE, postspeed = B_FALSE; + assert(newcell); + getlfname(lf, lfname); if (newcell->map != lf->cell->map) { @@ -748,7 +778,7 @@ int movelf(lifeform_t *lf, cell_t *newcell) { } } // end if crushable - if (o->type->id == OT_VINE) { + if ((o->type->id == OT_VINE) && !hasjob(lf, J_DRUID)) { char obname[BUFLEN]; getobname(o,obname,o->amt); if (isplayer(lf)) { @@ -807,7 +837,8 @@ int movelf(lifeform_t *lf, cell_t *newcell) { if (isplayer(l)) { if (cansee(l, lf) && areenemies(lf, l)) { - if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_RESTING)) { + if (lfhasflag(l, F_RUNNING) || lfhasflag(l, F_TRAINING)) { + // TODO: also check for isresting(l), if we have allies standing watch char lfname2[BUFLEN]; getlfname(lf, lfname); sprintf(lfname2, "%s",noprefix(lfname)); @@ -924,7 +955,7 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { // see objects on ground if (isplayer(lf)) { int numobs; - numobs = countobs(newcell->obpile); + numobs = countnoncosmeticobs(newcell->obpile); if ((numobs == 0) && !newcell->writing) { // just clear the message buffer if (!didmsg) clearmsg(); @@ -964,10 +995,10 @@ int moveto(lifeform_t *lf, cell_t *newcell, int onpurpose, int dontclearmsg) { // measure distance when determining which way is "towards" // // in general: -// use orthogonal for voluntary movement (eg. monster moving +// use orthogonal/dt_orth for voluntary movement (eg. monster moving // towards player), compass // -// use compass for involuntary movement (eg. being knocked back by +// use compass/dt_compass for involuntary movement (eg. being knocked back by // an explosion) // int movetowards(lifeform_t *lf, cell_t *dst, int dirtype) { @@ -1284,6 +1315,9 @@ int initiatemove(lifeform_t *lf, cell_t *cell, int *didmsg) { if ((o->type->id == OT_WEB) && (lf->race->baseid == R_SPIDER)) { continue; } + if ((o->type->id == OT_VINE) && hasjob(lf, J_DRUID)) { + continue; + } f = hasflag(o->flags, F_RESTRICTMOVEMENT); if (f) { diff --git a/nexus.c b/nexus.c index 34afc17..7d66db4 100644 --- a/nexus.c +++ b/nexus.c @@ -192,7 +192,7 @@ int main(int argc, char **argv) { skill_t *sk; initprompt(&prompt, "Select your spell specialty:"); addchoice(&prompt, 'a', getskillname(SK_SS_AIR), NULL, findskill(SK_SS_AIR)); - addchoice(&prompt, 'i', getskillname(SK_SS_ICE), NULL, findskill(SK_SS_ICE)); + addchoice(&prompt, 'i', getskillname(SK_SS_COLD), NULL, findskill(SK_SS_COLD)); addchoice(&prompt, 'f', getskillname(SK_SS_FIRE), NULL, findskill(SK_SS_FIRE)); getchoice(&prompt); sk = (skill_t *) prompt.result; @@ -491,21 +491,16 @@ void donextturn(map_t *map) { int donormalmove = B_TRUE; flag_t *f; - if (donormalmove) { - // paralyzed etc? - if (isimmobile(who)) { - rest(who, B_FALSE); - donormalmove = B_FALSE; - } - } - // resting? if (donormalmove) { - f = hasflag(who->flags, F_RESTING); + f = isresting(who); + if (!f) { + f = lfhasflag(who, F_TRAINING); + } if (f) { // check for interrupt of resting... if (isplayer(who) && checkforkey()) { - msg("Stopped resting."); + msg("Stopped %s.",(f->id == F_TRAINING) ? "training" : "resting"); killflag(f); } else { rest(who, B_TRUE); @@ -514,6 +509,15 @@ void donextturn(map_t *map) { } } + + if (donormalmove) { + // paralyzed etc? + if (isimmobile(who)) { + rest(who, B_FALSE); + donormalmove = B_FALSE; + } + } + if (donormalmove) { if (isplayer(who)) { drawcursor(); @@ -528,7 +532,7 @@ void donextturn(map_t *map) { } } - if (hasflag(player->flags, F_RESTING)) { + if (hasflag(player->flags, F_ASLEEP)) { // ooo is this right ? needredraw = B_FALSE; } else if (isdead(who) || cansee(player, who)) { @@ -782,13 +786,17 @@ int isplayerturn(void) { int limit(int *what, int min, int max) { int limited = B_FALSE; - if (*what < min) { - *what = min; - limited = B_TRUE; + if (min != NA) { + if (*what < min) { + *what = min; + limited = B_TRUE; + } } - if (*what > max) { - *what = max; - limited = B_TRUE; + if (max != NA) { + if (*what > max) { + *what = max; + limited = B_TRUE; + } } return limited; } @@ -887,7 +895,7 @@ int rollhitdice(lifeform_t *lf) { int roll = 0; int i; float mod; - int db = B_TRUE; + int db = B_FALSE; f = hasflag(lf->flags, F_HITDICE); if (f) { diff --git a/objects.c b/objects.c index 53f113a..955ce9c 100644 --- a/objects.c +++ b/objects.c @@ -78,6 +78,7 @@ enum OBCLASS sortorder[] = { char *techadjective[] = { "crazy", + "mysterious", "odd", "strange", "weird", @@ -539,9 +540,6 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { } } if (db) dblog("DB: FOUND: ot->name = '%s'", ot->name ); - if (ot->id == OT_WOODENDOOR) { - dblog("xxx"); - } // override blessed status from flags... f = hasflag(ot->flags, F_STARTBLESSED); @@ -721,19 +719,19 @@ object_t *addobject(obpile_t *where, char *name, int canstack) { if (cf) { switch (rf->val[0]) { case SZ_MINI: - cf->val[1] = 5; + cf->val[1] = 1; break; case SZ_TINY: - cf->val[1] = 25; + cf->val[1] = 10; break; case SZ_SMALL: - cf->val[1] = 55; + cf->val[1] = 25; break; case SZ_MEDIUM: - cf->val[1] = 90; + cf->val[1] = 75; break; case SZ_HUMAN: - cf->val[1] = 100; + cf->val[1] = 120; break; case SZ_LARGE: cf->val[1] = 150; @@ -1849,6 +1847,18 @@ int countobs(obpile_t *op) { return count; } +int countnoncosmeticobs(obpile_t *op) { + object_t *o; + + int count = 0; + for (o = op->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_COSMETIC)) { + count++; + } + } + return count; +} + int curseob(object_t *o) { int rv = B_FALSE; lifeform_t *lf; @@ -2972,6 +2982,16 @@ char *getobequipinfo(object_t *o, char *buf) { } else { strcat(buf, " (weapon)"); } + } else if (f->val[0] == BP_SECWEAPON) { + if (isshield(o)) { + strcat(buf, " (shield)"); + } else if (ismeleeweapon(o)) { + strcat(buf, " (second weapon)"); + } else if (isfirearm(o)) { + strcat(buf, " (firearm)"); + } else { + strcat(buf, " (in left hand)"); + } } else { strcat(buf, " ("); strcat(buf, getbodypartequipname(f->val[0])); @@ -3771,7 +3791,7 @@ char *getschoolname(enum SPELLSCHOOL sch) { case SS_MENTAL: return "Psionic Powers"; case SS_AIR: return "Elemental/Air Magic"; case SS_FIRE: return "Elemental/Fire Magic"; - case SS_ICE: return "Elemental/Ice Magic"; + case SS_COLD: return "Elemental/Cold Magic"; case SS_MODIFICATION: return "Modification Magic"; case SS_DEATH: return "Necromancy"; case SS_NATURE: return "Nature"; @@ -3795,7 +3815,7 @@ char *getschoolnameshort(enum SPELLSCHOOL sch) { case SS_WILD: return "Wild Magic"; case SS_AIR: return "Air Magic"; case SS_FIRE: return "Fire Magic"; - case SS_ICE: return "Ice Magic"; + case SS_COLD: return "Cold Magic"; case SS_DEATH: return "Necromancy"; case SS_LIFE: return "Life Magic"; case SS_MENTAL: return "Psionic Powers"; @@ -4358,7 +4378,7 @@ void initobjects(void) { // object types // dungeon features - addot(OT_WOODENDOOR, "wooden door", "A sturdy wooden door.", MT_WOOD, 150, OC_DFEATURE); + addot(OT_DOORWOOD, "wooden door", "A sturdy wooden door.", MT_WOOD, 150, OC_DFEATURE); // GLYPH here is a special case in getglyph addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); @@ -4371,6 +4391,20 @@ void initobjects(void) { addflag(lastot->flags, F_DTVULN, DT_BASH, NA, NA, NULL); addflag(lastot->flags, F_DTVULN, DT_CHOP, NA, NA, NULL); + addot(OT_DOORIRON, "iron door", "A strong iron door.", MT_METAL, 300, OC_DFEATURE); + // GLYPH here is a special case in getglyph + addflag(lastot->flags, F_DOOR, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_IMPASSABLE, SZ_MAX, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_BLOCKSTHROW, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_LOCKABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 60, 60, NA, NULL); + addflag(lastot->flags, F_DTIMMUNE, DT_PIERCE, NA, NA, NULL); + addflag(lastot->flags, F_DTIMMUNE, DT_SLASH, NA, NA, NULL); + addflag(lastot->flags, F_DTRESIST, DT_CHOP, NA, NA, NULL); + addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_DFEATURE); addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, NA, NA, "\\"); @@ -4546,7 +4580,7 @@ void initobjects(void) { // potions (sorted by rarity) addot(OT_POT_JUICE, "potion of fruit juice", "Tasty (but not very fresh) fruit juice!", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); - addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-8 health to whoever drinks it.", MT_GLASS, 1, OC_POTION); + addot(OT_POT_HEALINGMIN, "potion of minor healing", "Restores 1-10 health to whoever drinks it.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); addot(OT_POT_WATER, "potion of water", "Plain, regular water.", MT_GLASS, 1, OC_POTION); @@ -4555,6 +4589,9 @@ void initobjects(void) { addot(OT_POT_HEALING, "potion of healing", "Restores 10-20 health to whoever drinks it.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); + addot(OT_POT_HEALINGMAJ, "potion of major healing", "Restores 20-30 health to whoever drinks it.", MT_GLASS, 1, OC_POTION); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 72, NA, NULL); + addflag(lastot->flags, F_AIHEALITEM, B_TRUE, NA, NA, NULL); addot(OT_POT_OIL, "potion of oil", "A bottle of cooking oil.", MT_GLASS, 1, OC_POTION); addflag(lastot->flags, F_RARITY, H_DUNGEON, 83, NA, NULL); addflag(lastot->flags, F_DIECONVERT, NA, NA, NA, "puddle of oil"); @@ -4918,7 +4955,7 @@ void initobjects(void) { /////////////////// // l2 addot(OT_S_CONECOLD, "cone of cold", "Shoots a blast of ice cold air, dealing 2-6 cold damage.", MT_NOTHING, 0, OC_SPELL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ICE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_NEED, NA, NULL); @@ -4927,7 +4964,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 2, NA, NA, NULL); // l3 addot(OT_S_COLDBURST, "cold burst", "Creates a radial blast of coldness out from the caster.", MT_NOTHING, 0, OC_SPELL); - addflag(lastot->flags, F_SPELLSCHOOL, SS_ICE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJSELF, NA, NA, NULL); /////////////////// @@ -5013,6 +5050,13 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 4, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_THORNS, "thorns", "Sharp thorns grow from your skin, dealing 1d4 damage to attackers.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); addot(OT_S_WEB, "web", "Slows down pursuers with a burst of sticky spider web.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); @@ -5042,6 +5086,7 @@ void initobjects(void) { addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); addot(OT_S_HAILSTORM, "hail storm", "Creates an intense storm of hail, causing damage to all within.", MT_NOTHING, 0, OC_SPELL); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); @@ -5157,6 +5202,12 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addot(OT_S_HEALINGMAJ, "major healing", "Restores 20-30 health to the caster.", MT_NOTHING, 0, OC_SPELL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_LIFE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); /////////////////// // modification /////////////////// @@ -5313,6 +5364,9 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL); + addot(OT_A_FLURRY, "flurry", "Perform a flurry of attacks, forcing your opponent backwards.", 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); addot(OT_A_GRAB, "grab", "You can grab hold of nearby enemies to prevent their escape.", 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); @@ -5379,6 +5433,8 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_STEALTH, NA, NA, NULL); addot(OT_MAN_TECHUSAGE, "manual of technology", "Teaches you the skill 'technology'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_TECHUSAGE, NA, NA, NULL); + addot(OT_MAN_TWOWEAPON, "manual of dual weilding", "Teaches you the skill 'dual weilding'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_TWOWEAPON, NA, NA, NULL); // knowledge manuals addot(OT_MAN_LORE_ARCANA, "tome of arcane lore", "Teaches you the skill 'lore:arcana'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_LORE_ARCANA, NA, NA, NULL); @@ -5418,8 +5474,8 @@ void initobjects(void) { addflag(lastot->flags, F_MANUALOF, SK_SS_NATURE, NA, NA, NULL); addot(OT_MAN_SS_FIRE, "manual of fire magic", "Teaches you the skill 'fire magic'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_FIRE, NA, NA, NULL); - addot(OT_MAN_SS_ICE, "manual of ice magic", "Teaches you the skill 'ice magic'.", MT_PAPER, 3, OC_BOOK); - addflag(lastot->flags, F_MANUALOF, SK_SS_ICE, NA, NA, NULL); + addot(OT_MAN_SS_COLD, "manual of ice magic", "Teaches you the skill 'ice magic'.", MT_PAPER, 3, OC_BOOK); + addflag(lastot->flags, F_MANUALOF, SK_SS_COLD, NA, NA, NULL); addot(OT_MAN_SS_GRAVITY, "manual of gravitation magic", "Teaches you the skill 'gravitation magic'.", MT_PAPER, 3, OC_BOOK); addflag(lastot->flags, F_MANUALOF, SK_SS_GRAVITY, NA, NA, NULL); addot(OT_MAN_SS_LIFE, "manual of life magic", "Teaches you the skill 'life magic'.", MT_PAPER, 3, OC_BOOK); @@ -5680,6 +5736,10 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); // tools + addot(OT_BLANKET, "wool blanket", "A warm wool blanket for those cold winter nights.", MT_CLOTH, 2, OC_ARMOUR); + addflag(lastot->flags, F_RARITY, H_ALL, 80, NA, NULL); + addflag(lastot->flags, F_HELPSREST, 10, NA, NA, NULL); + addot(OT_BLINDFOLD, "blindfold", "Short length of wide cloth, used for blocking eyesight.", MT_CLOTH, 0.01, OC_TOOLS); addflag(lastot->flags, F_GOESON, BP_EYES, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_BLIND, B_TRUE, NA, NULL); @@ -5789,6 +5849,10 @@ void initobjects(void) { addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d1"); addflag(lastot->flags, F_ACCURACY, 50, NA, NA, NULL); + addot(OT_SLEEPINGBAG, "sleeping bag", "An insulated bag for sleeping in. Very comfortable.", MT_CLOTH, 4, OC_TECH); + addflag(lastot->flags, F_RARITY, H_ALL, 70, NA, NULL); + addflag(lastot->flags, F_HELPSREST, 15, NA, NA, NULL); + // tech - l1 addot(OT_POCKETWATCH, "pocket watch", "A portable timekeeping device made to be carried in a pocket.", MT_METAL, 0.1, OC_TECH); addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); @@ -5817,6 +5881,11 @@ void initobjects(void) { addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, IFACTIVE, NULL); addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addot(OT_TENT, "tent", "A easy to use, portable shelter made of fabric.", MT_CLOTH, 10, OC_TECH); + addflag(lastot->flags, F_RARITY, H_ALL, 60, NA, NULL); + addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL); + addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_TECHLEVEL, PR_NOVICE, NA, NA, NULL); // tech - l2 addot(OT_FLASHBANG, "flashbang", "A stun grenade which temporarily blinds all within sight.", MT_METAL, 1, OC_TECH); @@ -6439,6 +6508,7 @@ void initobjects(void) { addflag(lastot->flags, F_ARMOURRATING, 1, NA, NA, NULL); addflag(lastot->flags, F_OBHP, 6, 6, NA, NULL); addflag(lastot->flags, F_WATERPROOF, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_HELPSREST, 5, NA, NA, NULL); // armour - waist addot(OT_BELTLEATHER, "leather belt", "A plain leather belt.", MT_LEATHER, 0.2, OC_ARMOUR); addflag(lastot->flags, F_RARITY, H_ALL, 85, NA, NULL); @@ -6941,7 +7011,7 @@ void initobjects(void) { addflag(lastot->flags, F_USESSKILL, SK_SHORTBLADES, NA, NA, NULL); addflag(lastot->flags, F_ATTREQ, A_STR, 6, 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_RARITY, H_DUNGEON, 81, NA, NULL); addflag(lastot->flags, F_DAM, DT_PIERCE, NA, NA, "1d4"); addflag(lastot->flags, F_DISARMATTACK, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); @@ -7998,9 +8068,11 @@ lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level) { return newlf; } -void makeduller(object_t *o, int howmuch) { +// returns true if something hapepned +int makeduller(object_t *o, int howmuch) { char obname[BUFLEN]; int oldbonus,newbonus; + int rv = B_FALSE; // get object name before changing the bonus getobname(o,obname, 1); @@ -8025,7 +8097,11 @@ void makeduller(object_t *o, int howmuch) { msg("%s seems duller!",obname); } } + rv = B_TRUE; + } else { + rv = B_FALSE; } + return rv; } void makeknown(enum OBTYPE otid) { @@ -9835,13 +9911,6 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i break; case OT_POT_RESTORATION: failed = B_TRUE; - if (getmr(lf) && skillcheck(lf, SC_RESISTMAG, 30, 0)) { - if (isplayer(lf)) { - msg("You feel momentarily restored."); - } - break; - } - if (getattr(lf,A_STR) < lf->baseatt[A_STR]) { setattr(lf, A_STR, lf->baseatt[A_STR]); failed = B_FALSE; @@ -9978,7 +10047,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, enum BLESSTYPE potblessed, i if (seen) *seen = B_TRUE; } if (potblessed != B_CURSED) { - modhunger(lf, -pctof(10, (float)HUNGERCONST)); + modhunger(lf, -pctof(25, (float)HUNGERCONST)); } break; default: // nothing happens @@ -10114,7 +10183,7 @@ int readsomething(lifeform_t *lf, object_t *o) { if (isblessed(o)) power += 4; // enforce maximum - if (power > 10) power = 10; + limit(&power, NA, 10); // for unidentified scrolls which target an object, // let player select ANY object (even if it won't @@ -11128,8 +11197,8 @@ int fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int speed, } } // an actual physical shield? - shield = getequippedob(target->pack, BP_SECWEAPON); - if (shield && isshield(shield)) { + shield = getshield(target); + if (shield) { // block chance based on shield skill // ie. ST_AVERAGE = speed3 = 18 // ie. gun = speed10 = 60 = basically impossible diff --git a/objects.h b/objects.h index 4f71e2d..91705b1 100644 --- a/objects.h +++ b/objects.h @@ -33,6 +33,7 @@ void colourmatchob(object_t *o, lifeform_t *lf); void copyobprops(object_t *dst, object_t *src); int countnames(char **list); int countobs(obpile_t *op); +int countnoncosmeticobs(obpile_t *op); int curseob(object_t *o); void damageallobs(object_t *exception, obpile_t *op, int howmuch, int damtype); void dumprandomobs(int amt); @@ -161,7 +162,7 @@ void killoc(objectclass_t *oc); void killot(objecttype_t *ot); int knockbackob(object_t *o, int dir, int howfar, int power, lifeform_t *pusher); lifeform_t *makeanimated(lifeform_t *lf, object_t *o, int level); -void makeduller(object_t *o, int howmuch); +int makeduller(object_t *o, int howmuch); void makeknown(enum OBTYPE otid); void maketried(enum OBTYPE otid); void makewet(object_t *o, int amt); diff --git a/spell.c b/spell.c index bf0018d..e670079 100644 --- a/spell.c +++ b/spell.c @@ -184,6 +184,50 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // attack attackcell(user, targcell); } + } else if (abilid == OT_A_FLURRY) { + int dir; + int dirch; + if (!isdualweilding(user)) { + if (isplayer(user)) msg("You need two be dual-weilding to perform an attack flurry!"); + return B_TRUE; + } + + // ask for direction + if (targcell) { + dir = getdirtowards(user->cell, targcell, NULL, B_FALSE, DT_ORTH); + } else { + dirch = askchar("Flurry in which direction (- to cancel)", "yuhjklbn-","-", B_FALSE); + dir = chartodir(dirch); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; + } else { + targcell = getcellindir(user->cell, dir); + } + } + + target = targcell->lf; + if (!target) { + if (isplayer(user)) msg("There is nobody there to attack!"); + return B_TRUE; + } + getlfname(target, targetname); + + // announce + if (!isplayer(user) && cansee(player, user)) { + msg("%s performs a flurry of fast attacks!", username); + } + + // push them back + knockback(target, dir, 1, user, 5); + + // if we succeeded in pushing them... + if (target->cell != targcell) { + movelf(user, targcell); + } + + // now attack them + attackcell(user, target->cell); } else if (abilid == OT_A_GRAB) { char dirch; flag_t *f; @@ -1089,23 +1133,56 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (spellid == OT_S_AIRBLAST) { int dir; object_t *o,*nexto; - if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; - target = targcell->lf; + cell_t *firstobcell = NULL; + cell_t *nextc; + + if (targcell) { + if (!validatespellcell(caster, &targcell, TT_MONSTER, spellid, power)) return B_TRUE; + dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); + } else { + int dirch; + dirch = askchar("Airblast in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE); + if ((dirch == '.') || (dir == '-')) { + fizzle(caster); + return B_TRUE; + } + dir = chartodir(dirch); + } + + // keep going that dir until the next cell is a wall/lf/impassable ob + targcell = caster->cell; + nextc = getcellindir(targcell, dir); + while (nextc && cellwalkable(NULL, nextc, NULL)) { + targcell = nextc; + if (!firstobcell) { + // obs here? + for (o = targcell->obpile->first ;o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_COSMETIC)) { + firstobcell = targcell; + break; + } + } + } + + nextc = getcellindir(targcell, dir); + } if (cansee(player, caster)) { if (seenbyplayer) *seenbyplayer = B_TRUE; msg("%s emit%s a powerful blast of air!", castername, isplayer(caster) ? "" : "s"); } - - dir = getdirtowards(caster->cell, targcell, target, B_FALSE, DT_COMPASS); - // lfs - if (target) { + // if it was a lifeform which stopped us... + if (nextc->lf) { + targcell = nextc; + target = targcell->lf; knockback(target, dir, power, caster, 0); - } else { + } else if (firstobcell) { // objects - for (o = targcell->obpile->first ;o ; o = nexto) { + for (o = firstobcell->obpile->first ;o ; o = nexto) { nexto = o->next; - if (!hasflag(o->flags, F_NOPICKUP)) knockbackob(o, dir, power, power, caster); + if (!hasflag(o->flags, F_NOPICKUP) && !hasflag(o->flags, F_COSMETIC)) { + knockbackob(o, dir, power, power, caster); + } } } } else if (spellid == OT_S_ANIMATEDEAD) { @@ -2628,7 +2705,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ howlong = getspellduration(5,25,blessed) + power; addtempflag(target->flags, F_FASTACTMOVE, 10, NA, NA, NULL, howlong); } - } else if (spellid == OT_S_HEALING) { + } else if ((spellid == OT_S_HEALING) || (spellid == OT_S_HEALINGMIN) || (spellid == OT_S_HEALINGMAJ)) { int donesomething = B_FALSE; if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; target = targcell->lf; @@ -2641,24 +2718,59 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (killflagsofid(target->flags, F_PAIN)) { donesomething = B_TRUE; } + if (killflagsofid(target->flags, F_POISONED)) { + donesomething = B_TRUE; + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + + if ((spellid == OT_S_HEALINGMIN) && donesomething) { + // minor healing will stop here + return B_FALSE; + } if (target->hp < target->maxhp) { - switch (blessed) { - case B_BLESSED: - gainhp(target, 20 + (power*2)); + int min,max; + switch (spellid) { + case OT_S_HEALINGMIN: + default: + min = 1; max = 10; break; - case B_UNCURSED: - gainhp(target, rnd(10,20) + (power*2)); + case OT_S_HEALING: + min = 10; max = 20; break; - case B_CURSED: - gainhp(target, 10); + case OT_S_HEALINGMAJ: + min = 20; max = 30; break; } + gainhp(target, getspellduration(min,max,blessed) + (power*2)); + if (isplayer(target)) { if (target->hp >= target->maxhp) { - msg("Your wounds close themselves!"); + switch (spellid) { + case OT_S_HEALINGMIN: + msg("All of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are healed!"); + break; + } } else { - msg("Some of your wounds close themselves!"); + switch (spellid) { + case OT_S_HEALINGMIN: + msg("Some of your scrapes and bruises are healed!"); + break; + case OT_S_HEALING: + default: + msg("Some of your wounds close themselves!"); + break; + case OT_S_HEALINGMAJ: + msg("Your injuries are partially healed!"); + break; + } } if (seenbyplayer) *seenbyplayer = B_TRUE; } else if (haslos(player, target->cell)) { @@ -2668,57 +2780,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } donesomething = B_TRUE; } - if (killflagsofid(target->flags, F_POISONED)) { - donesomething = B_TRUE; - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - - if (!donesomething) { - if (isplayer(target)) { - nothinghappens(); - } - } - } else if (spellid == OT_S_HEALINGMIN) { - int donesomething = B_FALSE; - if (!validatespellcell(caster, &targcell,TT_ALLY, spellid, power)) return B_TRUE; - target = targcell->lf; - if (!target) { - fizzle(caster); - return B_FALSE; - } - - // cure bad effects instead of healing - if (killflagsofid(target->flags, F_PAIN)) { - return B_FALSE; - } - - if (target->hp < target->maxhp) { - switch (blessed) { - case B_BLESSED: - gainhp(target, 8 + power); - break; - case B_UNCURSED: - gainhp(target, rnd(1,8) + power); - break; - case B_CURSED: - gainhp(target, 1); - break; - } - if (isplayer(target)) { - msg("%s of your scrapes and bruises are healed!", - (target->hp >= target->maxhp) ? "All" : "Some"); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } else if (haslos(player, target->cell)) { - getlfname(target, buf); - msg("%s looks a little healthier!", buf); - if (seenbyplayer) *seenbyplayer = B_TRUE; - } - donesomething = B_TRUE; - } - if (killflagsofid(target->flags, F_POISONED)) { - donesomething = B_TRUE; - if (seenbyplayer) *seenbyplayer = B_TRUE; - } if (!donesomething) { if (isplayer(target)) { @@ -4233,7 +4294,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } howlong = getspellduration(5,10,blessed) + (power/2); - addtempflag(target->flags, F_ASLEEP, B_TRUE, NA, NA, NULL, howlong); + fallasleep(target, F_ASLEEP); if (isplayer(target) || haslos(player, target->cell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } @@ -4747,6 +4808,14 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (failed) { fizzle(caster); } + } else if (spellid == OT_S_THORNS) { + flag_t *f; + // always targetted at caster + targcell = caster->cell; + target = caster; + + f = addtempflag(caster->flags, F_RETALIATE, 1, 4, DT_PIERCE, "sharp thorns", FROMSPELL); + f->obfrom = spellid; } else if (spellid == OT_S_TURNUNDEAD) { int i; // works on all undead in sight @@ -5079,8 +5148,8 @@ enum SKILL getschoolskill(enum SPELLSCHOOL ss) { return SK_SS_NATURE; case SS_FIRE: return SK_SS_FIRE; - case SS_ICE: - return SK_SS_ICE; + case SS_COLD: + return SK_SS_COLD; case SS_GRAVITY: return SK_SS_GRAVITY; case SS_LIFE: