diff --git a/ai.c b/ai.c index 7b60379..810e225 100644 --- a/ai.c +++ b/ai.c @@ -394,178 +394,188 @@ object_t *aigetrangedattack(lifeform_t *lf, lifeform_t *target, enum RANGEATTACK int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim, lifeform_t **spelllf, cell_t **spellcell, object_t **spellob, enum FLAG purpose) { int specialcase = B_FALSE; flag_t *f; + enum SPELLTARGET spelltarg = ST_NONE; // default - at victim. if (spelllf) *spelllf = victim; if (spellcell) *spellcell = victim->cell; if (spellob) *spellob = NULL; - f = hasflag(spelltype->flags, purpose); + f = lfhasflagval(lf, F_AISPELLTARGETOVERRIDE, spelltype->id, NA, NA, NULL); if (f) { - switch (f->val[0]) { - case ST_VICTIM: - // at victim. - if (spelllf) *spelllf = victim; - if (spellcell) *spellcell = victim->cell; - if (spellob) *spellob = NULL; - break; - case ST_ADJSELF: // cast at myself when next to victim - if (getcelldist(lf->cell, victim->cell) <= 1) { - if (spelllf) *spelllf = lf; - if (spellcell) *spellcell = lf->cell; - if (spellob) *spellob = NULL; - } - break; - case ST_ADJVICTIM: // cast at victim when next to victim - if (getcelldist(lf->cell, victim->cell) <= 1) { - if (spelllf) *spelllf = victim; - if (spellcell) *spellcell = victim->cell; - if (spellob) *spellob = NULL; - } - break; - case ST_SELF: + spelltarg = f->val[1]; + } else { + f = hasflag(spelltype->flags, purpose); + if (f) { + spelltarg = f->val[0]; + } + } + + switch (spelltarg) { + case ST_VICTIM: + // at victim. + if (spelllf) *spelllf = victim; + if (spellcell) *spellcell = victim->cell; + if (spellob) *spellob = NULL; + break; + case ST_ADJSELF: // cast at myself when next to victim + if (getcelldist(lf->cell, victim->cell) <= 1) { if (spelllf) *spelllf = lf; if (spellcell) *spellcell = lf->cell; if (spellob) *spellob = NULL; - break; - case ST_ANYWHERE: - if (spelllf) *spelllf = NULL; - if (spellcell) *spellcell = NULL; - if (spellob) *spellob = NULL; - break; - case ST_SPECIAL: - specialcase = B_TRUE; - break; - } - - if (specialcase) { - if (spelltype->id == OT_A_CLIMB) { - int i,nposs = 0; - cell_t *poss[MAXCANDIDATES]; - // cell in sight and adjacent? aispellok() should have already confirmed - // that there will be at least one of these. - for (i = 1; i < lf->nlos; i++) { - if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldist(lf->cell, lf->los[i]) == 1)) { - poss[nposs++] = lf->los[i]; - } - } - if (!nposs) { - if (spellcell) spellcell = NULL; - if (spelllf) *spelllf = NULL; - if (spellob) *spellob = NULL; - return B_TRUE; - } - - if (spellcell) { - *spellcell = poss[rnd(0,nposs-1)]; - } - if (spelllf) *spelllf = NULL; - if (spellob) *spellob = NULL; - } else if (spelltype->id == OT_A_JUMP) { - cell_t *cell[MAXCANDIDATES],*c; - cell_t *poss[MAXCANDIDATES]; - int ncells,i,bestdist,nposs; - - if (purpose == F_AICASTTOATTACK) { - bestdist = 99; - } else { - bestdist = -99; - } - getradiuscells(lf->cell, 2, DT_COMPASS, B_TRUE, LOF_WALLSTOP, B_FALSE, cell, &ncells, 0); - for (i = 0; i < ncells; i++) { - int disttovictim; - c = cell[i]; - if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { - continue; - } - disttovictim = getcelldist(victim->cell, c); - if (purpose == F_AICASTTOATTACK) { - // get closest cell to victim - if (disttovictim < bestdist) { - bestdist = disttovictim; - } - } else { - // get furthest cell from victim - if (disttovictim > bestdist) { - bestdist = disttovictim; - } - } - } - // now get all possible cells... - nposs = 0; - for (i = 0; i < ncells; i++) { - int disttovictim; - c = cell[i]; - if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { - continue; - } - disttovictim = getcelldist(victim->cell, c); - if (disttovictim == bestdist) { - poss[nposs++] = c; - } - } - // cast spell at one of the cells we found. - // we should ALWAYS have at least one cell, because aispellok() - // will check this. - if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; - } else if (spelltype->id == OT_S_DIG) { - cell_t *cell[MAXCANDIDATES],*poss[MAXCANDIDATES]; - int ncells,i,nposs = 0; - getradiuscells(lf->cell, 1, DT_COMPASS, B_TRUE, LOF_DONTNEED, B_FALSE, cell, &ncells, 0); - for (i = 0; i < ncells; i++) { - if (cell[i]->type->solid && - (cell[i]->type->material->id == MT_STONE) && - getcelldist(cell[i], victim->cell) == 1) { - poss[nposs++] = cell[i]; - break; - } - } - - // aim at an adjacent wall cell - if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; - } else if (spelltype->id == OT_S_TELEKINESIS) { - float maxweight; - object_t *poss[MAXPILEOBS]; - int nposs; - int i; - // find nearest object which can be picked up - - // this is copied out of the telekenesis spell code! - maxweight = getlfweight(lf, B_NOOBS) + - (getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100)); - - nposs = 0; - for (i = 0; i < lf->nlos; i++) { - if (lf->los[i] != lf->cell) { - object_t *o; - for (o = lf->los[i]->obpile->first ; o ; o = o->next) { - if (!hasflag(o->flags, F_NOPICKUP) && - getobweight(o) <= maxweight) { - poss[nposs] = o; - nposs++; - if (nposs >= MAXPILEOBS) break; - } - } - if (nposs >= MAXPILEOBS) break; - } - } - // should always be true since we check this in aispellok - if (nposs > 0) { - if (spellob) *spellob = poss[rnd(0,nposs-1)]; - } - - // cast spell at the victim + } + break; + case ST_ADJVICTIM: // cast at victim when next to victim + if (getcelldist(lf->cell, victim->cell) <= 1) { if (spelllf) *spelllf = victim; if (spellcell) *spellcell = victim->cell; - } else if (spelltype->id == OT_S_CHARM) { - lifeform_t *l; - l = getnearbypeaceful(lf); - if (l) { - if (spelllf) *spelllf = l; - if (spellcell) *spellcell = l->cell; - if (spellob) *spellob = NULL; + if (spellob) *spellob = NULL; + } + break; + case ST_SELF: + if (spelllf) *spelllf = lf; + if (spellcell) *spellcell = lf->cell; + if (spellob) *spellob = NULL; + break; + case ST_ANYWHERE: + if (spelllf) *spelllf = NULL; + if (spellcell) *spellcell = NULL; + if (spellob) *spellob = NULL; + break; + case ST_SPECIAL: + specialcase = B_TRUE; + break; + case ST_NONE: + break; + } + + if (specialcase) { + if (spelltype->id == OT_A_CLIMB) { + int i,nposs = 0; + cell_t *poss[MAXCANDIDATES]; + // cell in sight and adjacent? aispellok() should have already confirmed + // that there will be at least one of these. + for (i = 1; i < lf->nlos; i++) { + if (!lf->los[i]->lf && lf->los[i]->type->solid && (getcelldist(lf->cell, lf->los[i]) == 1)) { + poss[nposs++] = lf->los[i]; } } + if (!nposs) { + if (spellcell) spellcell = NULL; + if (spelllf) *spelllf = NULL; + if (spellob) *spellob = NULL; + return B_TRUE; + } + + if (spellcell) { + *spellcell = poss[rnd(0,nposs-1)]; + } + if (spelllf) *spelllf = NULL; + if (spellob) *spellob = NULL; + } else if (spelltype->id == OT_A_JUMP) { + cell_t *cell[MAXCANDIDATES],*c; + cell_t *poss[MAXCANDIDATES]; + int ncells,i,bestdist,nposs; + + if (purpose == F_AICASTTOATTACK) { + bestdist = 99; + } else { + bestdist = -99; + } + getradiuscells(lf->cell, 2, DT_COMPASS, B_TRUE, LOF_WALLSTOP, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + int disttovictim; + c = cell[i]; + if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { + continue; + } + disttovictim = getcelldist(victim->cell, c); + if (purpose == F_AICASTTOATTACK) { + // get closest cell to victim + if (disttovictim < bestdist) { + bestdist = disttovictim; + } + } else { + // get furthest cell from victim + if (disttovictim > bestdist) { + bestdist = disttovictim; + } + } + } + // now get all possible cells... + nposs = 0; + for (i = 0; i < ncells; i++) { + int disttovictim; + c = cell[i]; + if (!cellwalkable(lf, c, NULL) || celldangerous(lf, c, B_TRUE, NULL)) { + continue; + } + disttovictim = getcelldist(victim->cell, c); + if (disttovictim == bestdist) { + poss[nposs++] = c; + } + } + // cast spell at one of the cells we found. + // we should ALWAYS have at least one cell, because aispellok() + // will check this. + if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; + } else if (spelltype->id == OT_S_DIG) { + cell_t *cell[MAXCANDIDATES],*poss[MAXCANDIDATES]; + int ncells,i,nposs = 0; + getradiuscells(lf->cell, 1, DT_COMPASS, B_TRUE, LOF_DONTNEED, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + if (cell[i]->type->solid && + (cell[i]->type->material->id == MT_STONE) && + getcelldist(cell[i], victim->cell) == 1) { + poss[nposs++] = cell[i]; + break; + } + } + + // aim at an adjacent wall cell + if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; + } else if (spelltype->id == OT_S_TELEKINESIS) { + float maxweight; + object_t *poss[MAXPILEOBS]; + int nposs; + int i; + // find nearest object which can be picked up + + // this is copied out of the telekenesis spell code! + maxweight = getlfweight(lf, B_NOOBS) + + (getlfweight(lf, B_NOOBS) * (getstatmod(lf, A_IQ) / 100)); + + nposs = 0; + for (i = 0; i < lf->nlos; i++) { + if (lf->los[i] != lf->cell) { + object_t *o; + for (o = lf->los[i]->obpile->first ; o ; o = o->next) { + if (!hasflag(o->flags, F_NOPICKUP) && + getobweight(o) <= maxweight) { + poss[nposs] = o; + nposs++; + if (nposs >= MAXPILEOBS) break; + } + } + if (nposs >= MAXPILEOBS) break; + } + } + // should always be true since we check this in aispellok + if (nposs > 0) { + if (spellob) *spellob = poss[rnd(0,nposs-1)]; + } + + // cast spell at the victim + if (spelllf) *spelllf = victim; + if (spellcell) *spellcell = victim->cell; + } else if (spelltype->id == OT_S_CHARM) { + lifeform_t *l; + l = getnearbypeaceful(lf); + if (l) { + if (spelllf) *spelllf = l; + if (spellcell) *spellcell = l->cell; + if (spellob) *spellob = NULL; + } } } return B_FALSE; @@ -1962,14 +1972,24 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG char why[BUFLEN]; if (reason == E_NOMP) { strcpy(why, "not enough mp"); + } else if (reason == E_CLIMBING) { + strcpy(why, "climbing"); } else if (reason == E_NOSTAM) { strcpy(why, "not enough stamina"); + } else if (reason == E_LOWIQ) { + strcpy(why, "lowiq"); + } else if (reason == E_PRONE) { + strcpy(why, "prone"); + } else if (reason == E_SWIMMING) { + strcpy(why, "swimming"); } else if (reason == E_TOOPOWERFUL) { strcpy(why, "spell too powerful"); } else if (reason == E_NOTREADY) { strcpy(why, "abil not ready"); } else if (reason == E_NEEDGRAB) { strcpy(why, "needs grab"); + } else if (reason == E_INJURED) { + strcpy(why, "injured"); } else { strcpy(why, "unknown reason"); } @@ -2252,6 +2272,15 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } } + if (ot->id == OT_S_ICECRUST) { + object_t *wep; + wep = getweapon(lf); + if (!wep) { + specificcheckok = B_FALSE; + } else if (hasflag(wep->flags, F_FROZEN)) { + specificcheckok = B_FALSE; + } + } if ((ot->id == OT_S_INVISIBILITY) && lfhasflag(victim, F_INVISIBLE)) { specificcheckok = B_FALSE; } @@ -2297,6 +2326,11 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG specificcheckok = B_FALSE; } } + if (ot->id == OT_S_SUMMONWEAPON) { + if (getweapon(lf)) { + specificcheckok = B_FALSE; + } + } if ((ot->id == OT_A_SWOOP) || (ot->id == OT_A_CHARGE)) { cell_t *adjcell; flag_t *willflag, *srflag; diff --git a/attack.c b/attack.c index fc8fdce..496dd81 100644 --- a/attack.c +++ b/attack.c @@ -781,7 +781,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) if (!willheal) { enum SKILLLEVEL slev; - float loremult; + float loreadd = 0; // blessed vs undead adjustdamforblessings(&(dam[0]), victim, wep->blessed); @@ -806,11 +806,11 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) // bonus for knowledge about the other lf's race? applied LAST. slev = getlorelevel(lf, victim->race->raceclass->id); if (slev == PR_INEPT) { - loremult = 1; + loreadd = 0; } else { - loremult = 1 + (slev * 0.1); + loreadd = slev; } - dam[0] = (int) ( (float)dam[0] * loremult ); + dam[0] = (int) ( (float)dam[0] + loreadd ); } if (aidb) dblog(".oO { dealing %d %s damage }", dam[0], getdamname(damtype[0])); @@ -1293,7 +1293,7 @@ int attackob(lifeform_t *lf, object_t *o, object_t *wep, flag_t *damflag) { // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { - dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); + dam[ndam] += getstrdammod(lf); } // damtype? @@ -1443,7 +1443,7 @@ int attackwall(lifeform_t *lf, cell_t *c, object_t *wep, flag_t *damflag) { // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { - dam[ndam] = (int)((float)dam[ndam] * getstrdammod(lf)); + dam[ndam] += getstrdammod(lf); } // damtype? @@ -2044,35 +2044,21 @@ int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag) { return dam; } -// returns a multiplier -float getstrdammod(lifeform_t *lf) { - float mod = 0; - float base; - // <9 = penalty - // 9,10,11,12 = average - // >12 = bonus +// returns amt of hp to modify damage by. (in range -3 to 3) +int getstrdammod(lifeform_t *lf) { + int mod = 0; + int base; base = getattr(lf, A_STR); - if ((base >= 45) && (base <= 60)) { - mod = 1; + mod = 0; } else if (base > 60) { base -= 60; // ie. 0 - 40 - mod = 1 + (base / 12.0); // ie. up to 1.3 / +30% + mod = base / 13; } else { // ie. 0 through 44 - // 0 = 0.1 - // 5 = 0.2 - // 10 = 0.3 - // 15 = 0.4 - // 20 = 0.5 - // 25 = 0.6 - // 30 = 0.7 - // 35 = 0.8 - // 40 = 0.9 - - mod = ((base/5) * 0.1); // ie. 10 -> 0.2 or 15 -> 0.3 - mod += 0.1; // ie. 10 -> 0.3 or 15 -> 0.4 + base = 45 - base; + mod = base / 13; } return mod; } diff --git a/attack.h b/attack.h index 249d5b9..0be169b 100644 --- a/attack.h +++ b/attack.h @@ -24,7 +24,7 @@ void getdamrange(object_t *o, flag_t *f, int *min, int *max); //float getdamreducepct(float armourrating); int getdamroll(object_t *o, lifeform_t *victim, flag_t *damflag); //int getunarmeddamroll(flag_t *f); -float getstrdammod(lifeform_t *lf); +int getstrdammod(lifeform_t *lf); //obpile_t *getunarmedweapon(lifeform_t *lf, flag_t **uflag); int ismeleedam(enum DAMTYPE damtype); int isphysicaldam(enum DAMTYPE damtype); diff --git a/data.c b/data.c index ab96b33..2298c60 100644 --- a/data.c +++ b/data.c @@ -686,15 +686,17 @@ void initjobs(void) { addjob(J_ROGUE, "Rogue", "Rogues (sometimes known as \"thieves\") are criminals who are skilled in the appropriation of valuable goods. They can hide in the shadows, stab unsuspecting victims in the back and foil the most cunning traps."); // stats - addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -15, NA, NULL); - addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 20, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_STR, -10, NA, NULL); + addflag(lastjob->flags, F_JOBATTRMOD, A_AGI, 15, NA, NULL); addflag(lastjob->flags, F_JOBATTRMOD, A_CON, -10, NA, NULL); // initial objects addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "dagger"); + addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather cloak"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "leather armour"); addflag(lastjob->flags, F_STARTOB, 100, NA, NA, "5 lockpicks"); // initial skills addflag(lastjob->flags, F_STARTSKILL, SK_ATHLETICS, PR_BEGINNER, NA, NULL); + addflag(lastjob->flags, F_STARTSKILL, SK_ARMOUR, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CARTOGRAPHY, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_CLIMBING, PR_BEGINNER, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_STEALTH, PR_BEGINNER, NA, NULL); @@ -708,6 +710,7 @@ void initjobs(void) { addflag(lastjob->flags, F_STARTSKILL, SK_THROWING, PR_NOVICE, NA, NULL); addflag(lastjob->flags, F_STARTSKILL, SK_LORE_HUMANOID, PR_BEGINNER, NA, NULL); // learnable skills + addflag(lastjob->flags, F_CANLEARN, SK_ARMOUR, PR_NOVICE, NA, NULL); // limit addflag(lastjob->flags, F_CANLEARN, SK_CHANNELING, PR_SKILLED, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_COOKING, NA, NA, NULL); addflag(lastjob->flags, F_CANLEARN, SK_PERCEPTION, PR_SKILLED, NA, NULL); @@ -965,7 +968,7 @@ void initobjects(void) { addobmod(OM_SHODDY,"shoddy"); addflag_real(lastobmod->flags, F_SHODDY, B_TRUE, NA, NA, NULL, PERMENANT, B_KNOWN, -1); addobmod(OM_POISONED,"poisoned"); - addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 30, "15-30", PERMENANT, B_KNOWN, -1); + addflag_real(lastobmod->flags, F_HITCONFER, F_POISONED, SC_POISON, 40, "15-30", PERMENANT, B_KNOWN, -1); addflag_real(lastobmod->flags, F_HITCONFERVALS, P_VENOM, 1, NA, NULL, PERMENANT, B_KNOWN, -1); addobmod(OM_WET1,"damp"); addflag_real(lastobmod->flags, F_WET, W_DAMP, NA, NA, NULL, PERMENANT, B_KNOWN, -1); @@ -2851,7 +2854,7 @@ void initobjects(void) { // elemental - fire /////////////////// // l1 - addot(OT_S_SPARK, "flambe", "Creates very hot but short lived burst of flame around the target, dealing 1-6 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SPARK, "flambe", "Creates very hot but short lived burst of flame around the target, dealing 2d2 fire damage to creatures and objects.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_FIRE, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); @@ -2960,6 +2963,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); // l3 addot(OT_S_CRYSTALSHIELD, "crystalline shield", "Summons a shield of ice crystals to protect you from missiles.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how effective the shield is."); @@ -2968,6 +2972,7 @@ void initobjects(void) { addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); addot(OT_S_COLDRAY, "cold ray", "Shoots a blast of ice cold air, dealing 3d6 cold damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines how difficult the ray is to dodge."); addflag(lastot->flags, F_SPELLSCHOOL, SS_COLD, NA, NA, NULL); @@ -3243,6 +3248,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); + addflag(lastot->flags, F_CASTINGTIME, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); /////////////////// // gravity @@ -3604,13 +3610,15 @@ void initobjects(void) { addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); - addot(OT_S_SUMMONWEAPON, "summon weapon", "Summons a blade of pure magic into your hands. Deals 1-^bpower^n damage.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addot(OT_S_SUMMONWEAPON, "summon weapon", "Summons a blade of pure magic into your hands.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines its Damage Rating."); addflag(lastot->flags, F_SPELLSCHOOL, SS_SUMMONING, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 1, NA, NA, NULL); addflag(lastot->flags, F_MAXPOWER, 6, NA, NA, NULL); addflag(lastot->flags, F_VARPOWER, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONGOING, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SELF, NA, NA, NULL); // l2 addot(OT_S_CREATEFOOD, "sultan's feast", "Creates a meal in the target location.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines how much food is created."); @@ -3764,6 +3772,14 @@ void initobjects(void) { addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the amount of charges restored."); addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + // l5 + addot(OT_S_DETONATEDELAY, "delayed detonation", "Causes a given area to explode after a short delay.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_WILD, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // l6 addot(OT_S_DETONATE, "detonate", "Causes a given area to explode with massive force.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the size of the explosion."); @@ -3771,7 +3787,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); addflag(lastot->flags, F_TARGETTEDSPELL, TT_MONSTER|TT_DOOR, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); - + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); // divine powers (spells/abilities) addot(OT_A_BLINDALL, "nosight", "Make everyone on the level blind.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); @@ -4810,6 +4826,7 @@ void initobjects(void) { addflag(lastot->flags, F_LINKOB, OT_POT_WATER, NA, NA, NULL); //addflag(lastot->flags, F_WALKDAM, DT_WATER, NA, NA, "0d1+1"); addflag(lastot->flags, F_WALKDAMBP, BP_FEET, DT_WATER, FALLTHRU, "0d1+1"); + addflag(lastot->flags, F_SLIPPERY, 1, NA, NA, NULL); addot(OT_PUDDLEWATERL, "large puddle of water", "A large pool of water.", MT_WATER, 20, OC_MISC, SZ_MEDIUM); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); @@ -5143,7 +5160,6 @@ void initobjects(void) { addflag(lastot->flags, F_WALKDAM, DT_HEAT, NA, NA, "1d1+1"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); - addot(OT_SLEETSTORM, "storm of sleet", "An intense storm of sleet. Hampers movement", MT_GAS, 0, OC_EFFECT, SZ_LARGE); addflag(lastot->flags, F_GLYPH, C_CYAN, UNI_SHADEMED, NA, NULL); addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); @@ -5215,7 +5231,7 @@ void initobjects(void) { addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_STENCH, B_TRUE, 1, NA, NULL); + addflag(lastot->flags, F_WALKDAM, DT_POISONGAS, NA, NA, "1d2"); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addot(OT_METHANEPUFF, "puff of methane gas", "A small puff of foul-smelling gas.", MT_GAS, 0, OC_EFFECT, SZ_MEDIUM); @@ -5225,7 +5241,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); - addflag(lastot->flags, F_WALKDAM, DT_POISONGAS, NA, NA, "1d2"); + addflag(lastot->flags, F_STENCH, B_TRUE, 1, NA, NULL); addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); addot(OT_HAILSTORM, "hail storm", "An intense storm of damaging hail.", MT_GAS, 0, OC_EFFECT, SZ_LARGE); @@ -5264,6 +5280,17 @@ void initobjects(void) { addflag(lastot->flags, F_OBDIETEXT, B_TRUE, NA, NA, "vanishes"); addflag(lastot->flags, F_PRODUCESLIGHT, 2, NA, NA, NULL); + addot(OT_VIBCLOUD, "vibrating cloud", "A cloud of unstable molecules.", MT_GAS, 0, OC_EFFECT, SZ_LARGE); + addflag(lastot->flags, F_GLYPH, C_ORANGE, UNI_SHADEMED, NA, NULL); + addflag(lastot->flags, F_NODIECONVERTTEXT, NA, NA, NA, NULL); + addflag(lastot->flags, F_OBHP, 4, 4, NA, NULL); + addflag(lastot->flags, F_OBHPDRAIN, 1, NA, NA, NULL); + addflag(lastot->flags, F_EXPLODEONDEATH, NA, 2, NA, "8d2"); + addflag(lastot->flags, F_NOOBDAMTEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOOBDIETEXT, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_THEREISHERE, B_TRUE, NA, NA, "!"); + addot(OT_VINE, "entangling vine", "A living vine which grasps nearby creature", MT_SILK, 0.1, OC_EFFECT, SZ_HUMAN); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 82, RR_UNCOMMON, NULL); @@ -5693,6 +5720,7 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 10, 10, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); + killflagsofid(lastot->flags, F_ENCHANTABLE); addot(OT_SPECTACLES, "pair of spectacles", "Eyewear with special lenses to enhance your vision.", MT_GLASS, 0.01, OC_ARMOUR, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); @@ -5702,6 +5730,7 @@ void initobjects(void) { addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, 1, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); + killflagsofid(lastot->flags, F_ENCHANTABLE); addot(OT_SUNGLASSES, "pair of sunglasses", "Tinted eyewear to protect against sunlight.", MT_GLASS, 0.01, OC_ARMOUR, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); @@ -5713,6 +5742,7 @@ void initobjects(void) { addflag(lastot->flags, F_TINTED, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOQUALITY, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); + killflagsofid(lastot->flags, F_ENCHANTABLE); addot(OT_EYEPATCH, "eyepatch", "A small patch of black material which covers one eye. Scary looking.", MT_CLOTH, 0.01, OC_ARMOUR, SZ_TINY); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); @@ -5721,6 +5751,7 @@ void initobjects(void) { addflag(lastot->flags, F_SCARY, 2, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_VISRANGEMOD, -2, NA, NULL); addflag(lastot->flags, F_CRITPROTECTION, 50, NA, NA, NULL); + killflagsofid(lastot->flags, F_ENCHANTABLE); // armour - shields addot(OT_BUCKLER, "buckler", "A small, unobtrusive wooden shield.", MT_WOOD, 3.00, OC_ARMOUR, SZ_SMALL); @@ -5730,6 +5761,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 20, 20, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); // similar to a buckler, but repairable, lighter, and less durable addot(OT_SHIELDHIDE, "hide shield", "A small shield constructed out of animal skin.", MT_LEATHER, 2.00, OC_ARMOUR, SZ_SMALL); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_COMMON, NULL); @@ -5738,6 +5770,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 5, NA, NULL); addflag(lastot->flags, F_OBHP, 18, 18, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_SHIELD, "shield", "A medium-sized metal shield.", MT_METAL, 4.00, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); @@ -5745,12 +5778,14 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 15, NA, NULL); addflag(lastot->flags, F_OBHP, 30, 30, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_SHIELDLARGE, "large shield", "A large (if somewhat cumbersome) shield.", MT_METAL, 6.00, OC_ARMOUR, SZ_MEDIUM); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 20, NA, NULL); addflag(lastot->flags, F_OBHP, 40, 40, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); addot(OT_SHIELDTOWER, "tower shield", "An enormous but very cumbersome shield.", MT_METAL, 11.00, OC_ARMOUR, SZ_HUMAN); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); addflag(lastot->flags, F_SHIELD, B_TRUE, NA, NA, NULL); @@ -5758,6 +5793,7 @@ void initobjects(void) { addflag(lastot->flags, F_GOESON, BP_SECWEAPON, NA, NA, NULL); addflag(lastot->flags, F_EQUIPCONFER, F_SHIELDPENALTY, 30, NA, NULL); addflag(lastot->flags, F_OBHP, 50, 50, NA, NULL); + addflag(lastot->flags, F_CRITPROTECTION, 100, NA, NA, NULL); // rings addot(OT_RING_EDUCATION, "ring of education", "Boosts earned XP and Skill points.", MT_METAL, 0.1, OC_RING, SZ_MINI); @@ -5990,6 +6026,7 @@ void initobjects(void) { addot(OT_TENTACLE, "tentacle", "tentacle object", MT_FLESH, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_BASH, 10, NA, NULL); + addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "slap"); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); @@ -7285,6 +7322,9 @@ void initrace(void) { addflag(lastrace->flags, F_MPMOD, -3, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_LIGHT, NA, NA, "1d6"); addflag(lastrace->flags, F_TAMABLE, 35, NA, NA, NULL); + // for ai: + addflag(lastrace->flags, F_WANTS, OT_GOLD, NA, NA, NULL); + addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, NA, NA, NULL); addrace(R_ELF, "elf", 60, '@', C_GREEN, MT_FLESH, RC_HUMANOID, "Elves are slender, graceful beings around human-sized but far nimbler. They have high intelligence and magical affinity, but a lack of physical strength. Elves meditate instead of sleeping, thus maintaining basic awareness."); @@ -8056,7 +8096,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "8d4"); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4"); addflag(lastrace->flags, F_ARMOURRATING, 9, NA, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -8554,11 +8594,11 @@ void initrace(void) { addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SIZE, SZ_LARGE, NA, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_CAVE, 60, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_FOREST, 66, NA, NULL); - addflag(lastrace->flags, F_RARITY, H_SWAMP, 66, NA, NULL); - addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "7d4+0"); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, 60, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, 60, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, 66, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, 66, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4+0"); addflag(lastrace->flags, F_EVASION, -5, NA, NA, NULL); addflag(lastrace->flags, F_ARMOURRATING, 11, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -8686,6 +8726,37 @@ void initrace(void) { addflag(lastrace->flags, F_DIURNAL, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + + addrace(R_CRYMIDIA, "crymidia", 10, 'e', C_WHITE, MT_ICE, RC_MAGIC, "A floating crystalline form, a crymidia is formed when a mass of crystal becomes sentient."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "10-20 chunks of ice"); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "chunk of ice"); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4"); + addflag(lastrace->flags, F_LEVITATING, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_LEVITATION, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_LEVITATION, 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_CANWILL, OT_S_SUMMONWEAPON, NA, NA, "pw:4;"); + addflag(lastrace->flags, F_CANWILL, OT_S_ICECRUST, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CRYSTALARM, NA, NA, "pw:4;"); + addflag(lastrace->flags, F_CANWILL, OT_S_CRYSTALSHIELD, NA, NA, "pw:4;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "shimmers"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_COLD, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SHIELDS, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addrace(R_PEGASUS, "pegasus", 130, 'Q', C_GREY, MT_FLESH, RC_MAGIC, "A legendary white, winged horse."); setbodytype(lastrace, BT_QUADRAPED); addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); @@ -8906,6 +8977,31 @@ void initrace(void) { addflag(lastrace->flags, F_WANTSOBFLAG, F_EDIBLE, B_COVETS, NA, NULL); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); + addrace(R_SKOOB, "skoob", 40, 'n', C_WHITE, MT_ICE, RC_MAGIC, "Your typical snowman right down to the carrot nose, with just a two key differences: it is alive, and it is homocidal."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "carrot"); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "puddle of water"); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_CANWILL, OT_S_SNOWBALL, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CANWILL, OT_S_SLIDE, NA, NA, "pw:10;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "rubs its hands together"); + addflag(lastrace->flags, F_HASATTACK, OT_TOUCHCHILL, 3, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_SS_COLD, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CASTCHANCE, 60, NA, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + + addrace(R_OOZEGREY, "sizzling slime", 10, 'j', C_GREEN, MT_SLIME, RC_SLIME, "Exactly what it sounds like - a small lump of green ooze. Green, acidic ooze."); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "puddle of slime"); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -9007,7 +9103,7 @@ void initrace(void) { addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, UNLIMITED, NA, NA, NULL); - addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_WHITE, MT_ICE, RC_MAGIC, "A small magical creature made from freezing ice."); + addrace(R_SPRITEICE, "ice sprite", 5, 'n', C_CYAN, MT_ICE, RC_MAGIC, "A small magical creature made from freezing ice."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "sheet of ice"); addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, "small puddle of water"); @@ -9544,6 +9640,38 @@ void initrace(void) { addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 14, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + + + addrace(R_BILCO, "bilco", 25, ';', C_BOLDCYAN, MT_FLESH, RC_ANIMAL, "Bilcos appear to be abnormally large frogs with a strange blue tinge. Seasoned travellers know to beware the bilco's gurgle, which portends them belching out a massive torrent of water."); + setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_VULNTOSALT, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_AQUATIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SEWER, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4"); + addflag(lastrace->flags, F_HASATTACK, OT_TONGUE, 3, NA, NULL); + addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, SV_SHOUT, NA, "croaks^croaking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, SV_SHOUT, NA, "croaking^croaking"); + addflag(lastrace->flags, F_NOISETEXT, N_SPELLCAST, SV_SHOUT, NA, "gurgles loudly^a loud gurgling"); + addflag(lastrace->flags, F_CANWILL, OT_A_JUMP, NA, NA, "stamcost:0;"); + addflag(lastrace->flags, F_CANWILL, OT_S_FLOOD, 20, 20, "pw:6;"); + addflag(lastrace->flags, F_CANWILL, OT_S_WATERJET, NA, NA, "pw:4;"); + addflag(lastrace->flags, F_STARTSKILL, SK_SWIMMING, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, NULL); + addflag(lastrace->flags, F_AISPELLTARGETOVERRIDE, OT_S_FLOOD, ST_SELF, NA, NULL); + addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "hop"); + + addrace(R_CHICKEN, "chicken", 0.5, 'c', C_BROWN, MT_FLESH, RC_ANIMAL, "A common farm-yard chicken."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); @@ -9694,10 +9822,11 @@ void initrace(void) { addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_DTVULN, DT_POISONGAS, NA, NA, NULL); - addflag(lastrace->flags, F_SEEINDARK, 3, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 6, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); - addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "croaks^croaking"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "croaking^croaking"); addflag(lastrace->flags, F_CANWILL, OT_A_THRUST, NA, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_JUMP, NA, NA, "stamcost:0;"); addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); @@ -10275,6 +10404,38 @@ void initrace(void) { addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); + addrace(R_WOLFWINTER, "winter wolf", 25, 'd', C_CYAN, MT_FLESH, RC_ANIMAL, "Wolves which have lived in close proximity to the undead sometimes mutate into these frosty beasts. While their claws have become less sharp, they instead deal unnatural cold damage."); + setbodytype(lastrace, BT_QUADRAPED); + addbodypart(lastrace, BP_TAIL, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_FAST, NA, NA, ""); + addflag(lastrace->flags, F_ENHANCESMELL, 6, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "5d4+2"); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 3, NA, NULL); + addflag(lastrace->flags, F_EXTRADAM, DT_COLD, NA, NA, "1d6"); + addflag(lastrace->flags, F_DTIMMUNE, DT_COLD, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); + addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); + addflag(lastrace->flags, F_NOSPELLS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CARNIVORE, 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); + addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_LOWHP, 2, NA, "whines in pain^whining"); + addflag(lastrace->flags, F_NOISETEXT, N_FRUSTRATED, 3, NA, "growls^growling"); + addflag(lastrace->flags, F_FLEEONHPPCT, 50, NA, NA, ""); + addflag(lastrace->flags, F_HASSKILL, SK_SWIMMING, PR_BEGINNER, NA, NULL); + addflag(lastrace->flags, F_MORALE, 11, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_COLDRAY, 10, 10, "pw:2;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "unleashes its icy breath"); + addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_FATALFOOD, OT_CHOCOLATE, NA, NA, NULL); + addrace(R_WORMGLUT, "glutworm", 25, 'W', C_MAGENTA, MT_FLESH, RC_ANIMAL, "Gigantic worms who swallow their prey whole, slowly digesting their still living bodies."); addbodypart(lastrace, BP_HEAD, NULL); addbodypart(lastrace, BP_TAIL, NULL); @@ -10738,6 +10899,26 @@ void initrace(void) { // end dragons // insects + addrace(R_BLASTBUG, "blastbug", 2, 'x', C_ORANGE, MT_STONE, RC_INSECT, "Blastbugs have somehow evolved the ability to de-stabalise nearby oxygen molecules, resulting in devestation explosions."); + setbodytype(lastrace, BT_QUADRAPED); + addbodypart(lastrace, BP_TAIL, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4+0"); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, NA, NA, "100"); // massively strong to hold stones + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "snorts^a snort"); + addflag(lastrace->flags, F_DTIMMUNE, DT_EXPLOSIVE, NA, NA, NULL); + addflag(lastrace->flags, F_CORPSEFLAG, F_EXPLODEONDEATH, NA, 2, "32d2"); + addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_WANTS, OT_STONE, B_COVETS, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_DETONATEDELAY, 20, 20, "pw:1;range:3;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "vibrates"); + addrace(R_BUTTERFLY, "butterfly", 0.01, 'i', C_YELLOW, MT_FLESH, RC_ANIMAL, "A harmless, colourful butterfly."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -10870,6 +11051,21 @@ void initrace(void) { addflag(lastrace->flags, F_TREMORSENSE, 3, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); + addrace(R_FIREBUG, "firebug", 2, 'x', C_RED, MT_FLESH, RC_INSECT, "Constantly burning insects which attack their victims with fire."); + setbodytype(lastrace, BT_QUADRAPED); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "2d4"); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TOUCHBURN, 3, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "flares its flames^crackling flames"); + addflag(lastrace->flags, F_MORALE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addrace(R_GLOWBUG, "glowbug", 1, 'i', C_WHITE, MT_FLESH, RC_INSECT, "Glowbugs are tiny flying creatures, magically producing light from their bodies."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_INSECT, B_TRUE, NA, NA, NULL); @@ -10984,6 +11180,7 @@ void initrace(void) { addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_HIGH, NA, NULL); addflag(lastrace->flags, F_CANWILL, OT_A_HURRICANESTRIKE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_BLINKASS, 3, 3, "pw:1;"); addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 2, NA, NULL); addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); @@ -11117,6 +11314,61 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addrace(R_SKELETONFIRE, "fire skeleton", 20, 'Z', C_RED, MT_BONE, RC_UNDEAD, "A walking set of flaming bones, imbued with the power of fire. They have all the advantages of normal skeletons but tend to burn victims with their flame rather than use weapons."); + setbodytype(lastrace, BT_HUMANOID); + setbodypartname(lastrace, BP_WEAPON, "right metacarpals"); + setbodypartname(lastrace, BP_SECWEAPON, "left metacarpals"); + setbodypartname(lastrace, BP_BODY, "ribs"); + setbodypartname(lastrace, BP_HEAD, "skull"); + setbodypartname(lastrace, BP_SHOULDERS, "scapulas"); + setbodypartname(lastrace, BP_HANDS, "carpals"); + setbodypartname(lastrace, BP_WAIST, "coccyx"); + setbodypartname(lastrace, BP_LEGS, "fibulas"); + setbodypartname(lastrace, BP_FEET, "tarsals"); + setbodypartname(lastrace, BP_RIGHTFINGER, "right phalange"); + setbodypartname(lastrace, BP_LEFTFINGER, "left phalange"); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_MINDLESS, NA, NULL); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "5-20 flaming bones"); + addflag(lastrace->flags, F_BLOODOB, NA, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "3d4"); + addflag(lastrace->flags, F_EVASION, -10, 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_HASATTACK, OT_TOUCHBURN, 7, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_BASH, NA, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_FALL, NA, NA, "1d3+3"); + addflag(lastrace->flags, F_DTRESIST, DT_PIERCE, NA, NA, NULL); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + + addrace(R_WRAITHICE, "ice wraith", 20, 'Z', C_CYAN, MT_ICE, RC_UNDEAD, "Ice wraiths look like frozen humanoid forms, often garbed in threadbare clothing."); + setbodytype(lastrace, BT_HUMANOID); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4"); + 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_TOUCHCHILL, 7, NA, NULL); + addflag(lastrace->flags, F_DTVULN, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 50, NA, NA, "shoddy cloak"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "scheeches^a screech"); + addflag(lastrace->flags, F_SILENTMOVE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_A_SPRINT, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addrace(R_GHAST, "ghast", 50, 'Z', C_MAGENTA, MT_FLESH, RC_UNDEAD, "A more slender and ghost-like form of ghoul. Ghasts are cunning and deadly, and possess a paralyzing touch."); setbodytype(lastrace, BT_HUMANOID); setbodypartname(lastrace, BP_HANDS, "claws"); @@ -11752,17 +12004,17 @@ void initskills(void) { char buf[BUFLEN]; addskilldesc(sk->id, PR_INEPT, "At each skill level, more information about related creatures will be shown.", B_FALSE); - addskilldesc(sk->id, PR_INEPT, "Each level also gives +10% damage and accuracy against related creatures.", B_FALSE); + addskilldesc(sk->id, PR_INEPT, "Each level also gives +1 damage and +2 accuracy against related creatures.", B_FALSE); - snprintf(buf, BUFLEN, "^gYou now know basic information about %s.", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou now know basic information about %s.^n", rc->pluralname); addskilldesc(sk->id, PR_NOVICE, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou can now determine how much damage %s will deal.", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou can now determine how much damage %s will deal.^n", rc->pluralname); addskilldesc(sk->id, PR_BEGINNER, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou can now determine how dangerous %s are.", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou can now determine how dangerous %s are.^n", rc->pluralname); addskilldesc(sk->id, PR_ADEPT, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou can now anticipate how %s will react.", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou can now anticipate how %s will react.^n", rc->pluralname); addskilldesc(sk->id, PR_SKILLED, buf, B_TRUE); - snprintf(buf, BUFLEN, "^gYou now know everything there is to know about %s.", rc->pluralname); + snprintf(buf, BUFLEN, "^gYou now know everything there is to know about %s.^n", rc->pluralname); addskilldesc(sk->id, PR_MASTER, buf, B_TRUE); } } diff --git a/data/hiscores.db b/data/hiscores.db index a27c465..bc2a317 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 19e2a2b..7b56c32 100644 --- a/defs.h +++ b/defs.h @@ -708,8 +708,10 @@ enum CELLTYPE { CT_VILLAGEGROUND, CT_FAKE, CT_FLOORFLESH, - CT_FLOORSHOP, - CT_FLOORWOOD, + CT_FLOORCARPET, + CT_FLOORSHOP, + CT_FLOORTILE, + CT_FLOORWOOD, CT_GRASS, CT_LOOPCORRIDOR, CT_LOWFLOOR, @@ -900,6 +902,7 @@ enum RACE { R_BUGBEAR, R_COCKATRICE, R_CREEPINGCLAW, + R_CRYMIDIA, R_DARKMANTLE, R_EYEBAT, R_GIANTHILL, @@ -935,6 +938,7 @@ enum RACE { R_SATYR, R_SHADOWCAT, R_SINKMITE, + R_SKOOB, R_SPRITEFIRE, R_SPRITEGRAVE, R_SPRITEICE, @@ -967,6 +971,7 @@ enum RACE { R_BEAR, R_BEARCUB, R_BEARGRIZZLY, + R_BILCO, R_CHICKEN, R_DOG, R_DOGBLINK, @@ -993,8 +998,9 @@ enum RACE { R_SPIDER, R_SPIDERFUNNELWEB, R_SPIDERREDBACK, - R_WOLF, R_WOLFYOUNG, + R_WOLF, + R_WOLFWINTER, R_WORMGLUT, // dragons R_DRAGONBLUE, @@ -1007,8 +1013,10 @@ enum RACE { R_DRAGONWHITEY, R_DRAGONWHITEA, // insects + R_BLASTBUG, R_BUTTERFLY, R_CENTIPEDE, + R_FIREBUG, R_GLOWBUG, R_GIANTFLY, R_GIANTBLOWFLY, @@ -1028,6 +1036,8 @@ enum RACE { R_GHOST, R_GHOUL, R_SKELETON, + R_SKELETONFIRE, + R_WRAITHICE, R_ZOMBIE, // special R_DANCINGWEAPON, @@ -1477,6 +1487,7 @@ enum OBTYPE { OT_S_ALARM, OT_S_MANASPIKE, OT_S_DETONATE, + OT_S_DETONATEDELAY, OT_S_ENERGYBOLT, OT_S_ENERGYBLAST, OT_S_FLASH, @@ -1677,6 +1688,7 @@ enum OBTYPE { OT_METHANEPUFF, OT_POISONCLOUD, OT_POISONPUFF, + OT_VIBCLOUD, OT_VINE, OT_WEB, // armour - multipart @@ -1956,6 +1968,7 @@ enum NOISETYPE { N_FRUSTRATED, N_SONICBOLT, N_WARCRY, + N_SPELLCAST, }; enum LFSIZE { @@ -2729,6 +2742,9 @@ enum FLAG { // if v0 != OT_NONE, only use text for spellid v0 // if v2 is 'appendyou' " at xxx" will // be appended. + F_AISPELLTARGETOVERRIDE, // when casting spellid v0, this lf will + // use v1 (ST_xxx) instead of what the AICASTTOxxx + // flag specifies. F_NODEATHANNOUNCE, // don't say 'the xx dies' if this lf dies F_NODEATHSPEECH, // lf doesn't talk when dying F_BEHEADED, // use special corpse drop code @@ -3071,6 +3087,8 @@ enum FLAG { // rest of the map. F_VAULTRANDOMMAP, // v0=minwidth, v1=minheight. this vault's map is // v0/1 can be NA. + // OPTIONAL: v2 = floor cell type id + // OPTIONAL: text = wall cell type id (int) // just a normal random room F_KEEPMARGIN, // this vault must be at least v0 from e/w of map // and at least v1 from n/s of map @@ -3166,6 +3184,7 @@ enum LIGHTLEV { // spell targets enum SPELLTARGET { + ST_NONE = 0, // dont cast at all. for debugging. ST_VICTIM, // cast at victim ST_ADJVICTIM, // cast at victim who is next to us ST_SELF, // cast at myself @@ -3656,6 +3675,7 @@ typedef struct lifeform_s { float forgettimer; struct obpile_s *pack; + struct obpile_s *polypack; // for melded objects when polymorphed struct flagpile_s *flags; diff --git a/doc/glyphs.txt b/doc/glyphs.txt index 0ee6b46..0b8143f 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -12,7 +12,7 @@ B = bat c = cockatricoe C = celestial / divine ? d = canine/dog -e = eye +e = eye or floating thing E = elemental ? f = feline/cat F = flora (flowers, plants, etc) @@ -21,7 +21,6 @@ G = large goblin h = humanoid H = large humanoid i = insect -P = gastroPod j = jelly/ooze/leech k = kobold m = mutant @@ -30,6 +29,7 @@ N = necron o = orc O = ogre p = sPirit +P = gastroPod q = quadraped Q = large quadraped r = rodent diff --git a/god.c b/god.c index ffed34e..4c13031 100644 --- a/god.c +++ b/god.c @@ -616,12 +616,9 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { } break; case 2: - snprintf(obtogive, BUFLEN, "3-5 cursed potions of water"); - break; - case 3: snprintf(obtogive, BUFLEN, "cursed branded weapon"); break; - case 4: // poison your weapon + case 3: // poison your weapon wep = getweapon(player); if (wep && canbepoisoned(wep->type->id)) { applyobmod(wep, findobmod(OM_POISONED)); @@ -630,7 +627,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { rollagain = B_TRUE; } break; - case 5: // resistant/immune to necrotic + case 4: // resistant/immune to necrotic if (lfhasflagval(player, F_DTRESIST, DT_NECROTIC, NA, NA, NULL)) { if (lfhasflagval(player, F_DTIMMUNE, DT_NECROTIC, NA, NA, NULL)) { rollagain = B_TRUE; @@ -643,7 +640,7 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { f->obfrom = god->race->id; } break; - case 6: + case 5: // become a vampire if (player->race->id == R_VAMPIRE) { rollagain = B_TRUE; } else { @@ -651,6 +648,13 @@ int godgiftmaybe(enum RACE rid, int fromtemple) { setrace(player, R_VAMPIRE, B_TRUE); // ie. don't set origrace! } break; + case 6: // necromancy spells + if (!getskill(lf, SK_SS_DEATH)) { + giveskill(lf, SK_SS_DEATH); + } else { + snprintf(obtogive, BUFLEN, "spellbook of necromancy"); + } + break; } } break; @@ -793,7 +797,11 @@ void godsay(enum RACE rid, int says, char *format, ...) { void modpiety(enum RACE rid, int amt) { lifeform_t *god; flag_t *f; + + god = findgod(rid); + if (godblocked(god->race->id)) return; + f = lfhasflag(god, F_PIETY); if (!f) return; f->val[0] += amt; @@ -1013,27 +1021,61 @@ int prayto(lifeform_t *lf, lifeform_t *god) { dospelleffects(NULL, OT_S_DISPERSAL, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_FALSE); } } else { - int i,first = B_TRUE; - msg("\"Allow me to reveal your surroundings...\""); - dospelleffects(god, OT_S_MAPPING, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); - dospelleffects(god, OT_S_REVEALHIDDEN, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); - // unlock doors - for (i = 0; i < player->nlos; i++) { - cell_t *c; - object_t *o; - c = player->los[i]; - if (c != player->cell) { - o = hascloseddoor(c); - if (o && hasflag(o->flags, F_LOCKED)) { - if (first) { - msg("\"Access granted!\""); - first = B_FALSE; + int redo = B_TRUE; + object_t *possob[MAXPILEOBS]; + int npossob,i,first; + while (redo) { + + redo = B_FALSE; + + switch (rnd(1,2)) { + case 1: + msg("\"Allow me to reveal your surroundings...\""); + dospelleffects(god, OT_S_MAPPING, 5, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + dospelleffects(god, OT_S_REVEALHIDDEN, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); + // unlock doors + first = B_TRUE; + for (i = 0; i < player->nlos; i++) { + cell_t *c; + object_t *o; + c = player->los[i]; + if (c != player->cell) { + o = hascloseddoor(c); + if (o && hasflag(o->flags, F_LOCKED)) { + if (first) { + msg("\"Access granted!\""); + first = B_FALSE; + } + killflagsofid(o->flags, F_LOCKED); + noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); + } + } } - killflagsofid(o->flags, F_LOCKED); - noise(c, NULL, NC_OTHER, SV_TALK, "the click of a lock.", NULL); - } - } - } + break; + case 2: // identify objects + npossob = 0; + for (o = lf->pack->first ; o ; o = o->next) { + if (!isknown(o)) { + possob[npossob++] = o; + } + } + if (npossob) { + char oldname[BUFLEN],newname[BUFLEN]; + o = possob[rnd(0,npossob-1)]; + getobname(o,oldname,o->amt); + identify(o); + getobname(o,newname,o->amt); + msg("\"%s %s you are carrying %s %s!\"", + (o->amt == 1) ? "That" : "Those", + noprefix(oldname), + (o->amt == 1) ? "is" : "are", + newname); + } else { + redo = B_TRUE; + } + break; + } // end switch + }// end while redo } break; case R_GODMERCY: diff --git a/io.c b/io.c index f897842..f071c09 100644 --- a/io.c +++ b/io.c @@ -6079,19 +6079,14 @@ char *makedesc_ob(object_t *o, char *retbuf) { col = C_GREY; } if (f->val[1] != NA) { - sprintf(buf, "^%dIt requires at least %d %s to use%s.", col, f->val[1], getattrname(f->val[0]), + sprintf(buf, "^%dIt requires at least %d %s to use%s.^n\n", col, f->val[1], getattrname(f->val[0]), strlen(f->text) ? " effectively" : ""); - if (f->val[2] != NA) { - char bbuf[BUFLEN]; - sprintf(bbuf, " (bonus at %d)", f->val[2]); - strcat(buf, bbuf); - } + strncat(retbuf, buf, HUGEBUFLEN); } if (f->val[2] != NA) { - sprintf(buf, "^nIt can be used more effectively with at least %d %s.\n", f->val[2], getattrname(f->val[0])); + sprintf(buf, "^nIt can be used more effectively with at least %d %s^n.\n", f->val[2], getattrname(f->val[0])); + strncat(retbuf, buf, HUGEBUFLEN); } - strcat(buf, "^n\n"); - strncat(retbuf, buf, HUGEBUFLEN); if (usable && isweapon(o)) { if (pctmod > 0) { @@ -7675,6 +7670,11 @@ int dothrow(obpile_t *op, object_t *o) { // calculate throw range maxdist = getmaxthrowrange(player, o); + if (maxdist < 1) { + msg("You are not strong enough to throw that."); + return B_TRUE; + } + // ask where to throw it snprintf(buf2, BUFLEN, "Throw %s where?",buf); snprintf(subprompt, BUFLEN, "%s->Throw->",buf); @@ -10174,8 +10174,8 @@ void showlfstats(lifeform_t *lf, int showall) { objecttype_t *ot; int first; int i; - float dammod; - int accmod; + int dammod; + //int accmod; enum BODYPART bp; enum BODYPART missingbp[MAXBODYPARTS]; int nmissingbp; @@ -10250,7 +10250,7 @@ void showlfstats(lifeform_t *lf, int showall) { y2 = 2; dammod = getstrdammod(lf); - accmod = getstatmod(lf, A_AGI); + //accmod = getstatmod(lf, A_AGI); if (isplayer(lf)) { getplayername(buf); @@ -10391,11 +10391,11 @@ void showlfstats(lifeform_t *lf, int showall) { char buf2[BUFLEN]; switch (i) { case A_STR: - if (dammod > 1) { - snprintf(buf2, BUFLEN, ", +%d%% dmg", (int)((dammod * 100) - 100) ); + if (dammod >= 1) { + snprintf(buf2, BUFLEN, ", +%d dmg", dammod); strcat(buf, buf2); - } else if (dammod < 1) { - snprintf(buf2, BUFLEN, ", -%d%% dmg", (int)(100 - (dammod * 100)) ); + } else if (dammod <= -1) { + snprintf(buf2, BUFLEN, ", -%d dmg", abs(dammod)); strcat(buf, buf2); } break; diff --git a/lf.c b/lf.c index 0340465..23ce0a4 100644 --- a/lf.c +++ b/lf.c @@ -544,8 +544,10 @@ int cancast(lifeform_t *lf, enum OBTYPE oid, int *mpcost) { return B_FALSE; } if (isswimming(lf) && (getskill(lf, SK_SWIMMING) < PR_EXPERT)) { - reason = E_SWIMMING; - return B_FALSE; + if (!isaquatic(lf)) { + reason = E_SWIMMING; + return B_FALSE; + } } if (isclimbing(lf)) { reason = E_CLIMBING; @@ -1678,6 +1680,8 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } + // noise.... + makenoise(lf, N_SPELLCAST); // announce if (!isplayer(lf) && !fromob) { @@ -2387,6 +2391,8 @@ void die(lifeform_t *lf) { castspell(lf, OT_S_FLASH, NULL, NULL, lf->cell, NULL, NULL); } + loseconcentration(lf); + // revert to your original form first. if (lfhasflag(lf, F_POLYMORPHED)) { if (lfhasflag(lf, F_ORIGRACE)) { @@ -2644,6 +2650,12 @@ void die(lifeform_t *lf) { if (copyflag(corpse->flags, lf->flags, F_REVIVETIMER)) { killflagsofid(corpse->flags, F_OBHPDRAIN); } + // special case + if (lf->race->id == R_BLASTBUG) { + flag_t *hpflag; + hpflag = hasflag(corpse->flags, F_OBHP); + if (hpflag) hpflag->val[0] = rnd(4,5); + } // corpse of a player pet? if (ispetof(lf, player)) { @@ -3474,10 +3486,14 @@ int eat(lifeform_t *lf, object_t *o) { // blink! dospelleffects(lf, OT_S_BLINK, 1, lf, NULL, NULL, B_UNCURSED, NULL, B_TRUE); + stopeating = B_TRUE; + } else if (hasflagval(o->flags, F_CORPSEOF, R_BLASTBUG, NA, NA, NULL)) { + dospelleffects(lf, OT_S_DETONATE, 10, lf, NULL, lf->cell, B_UNCURSED, NULL, B_TRUE); stopeating = B_TRUE; } + // eating your pet is very bad! if (isplayer(lf) && hasflagval(o->flags, F_PETOF, player->id, NA, NA, NULL)) { angergodmaybe(R_GODPURITY, 150, GA_EAT); @@ -4365,10 +4381,13 @@ int flee(lifeform_t *lf) { flag_t *retflag[MAXCANDIDATES]; int nretflags; + if (lfhasflag(lf, F_DEBUG)) db = B_TRUE; real_getlfname(lf, lfname, B_FALSE, B_FALSE); + if (isdead(lf)) return B_FALSE; + // are we fleeing? getflags(lf->flags, retflag, &nretflags, F_FLEEFROM, F_NONE); @@ -4397,7 +4416,7 @@ int flee(lifeform_t *lf) { // player let something flee? if (isplayer(thisone)) { pleasegodmaybe(R_GODMERCY, 5); - angergodmaybe(R_GODDEATH, 25, GA_MERCY); + angergodmaybe(R_GODDEATH, 15, GA_MERCY); } killflag(f); } else { @@ -5513,8 +5532,8 @@ int getavgdam(lifeform_t *lf, int forxp) { dammod = getstrdammod(lf); // 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); + mindam += dammod; + maxdam += dammod; } if (mindam < 0) mindam = 0; @@ -9841,12 +9860,19 @@ int injure(lifeform_t *lf, enum BODYPART where, enum DAMTYPE damtype) { if (hasbp(lf, bp2)) { object_t *o[2]; char buf[BUFLEN]; + enum BODYPART fingerbp; int i; // drop anyting in that hand o[0] = getequippedob(lf->pack, bp2); - if (bp2 == BP_WEAPON) o[1] = getequippedob(lf->pack, BP_RIGHTFINGER); - else o[1] = getequippedob(lf->pack, BP_LEFTFINGER); + if (bp2 == BP_WEAPON) { + o[1] = getequippedob(lf->pack, BP_RIGHTFINGER); + fingerbp = BP_RIGHTFINGER; + } else { + o[1] = getequippedob(lf->pack, BP_LEFTFINGER); + fingerbp = BP_LEFTFINGER; + } addflag(lf->flags, F_NOBODYPART, bp2, B_FROMINJURY, NA, NULL); + addflag(lf->flags, F_NOBODYPART, fingerbp, B_FROMINJURY, NA, NULL); inj = IJ_HANDMISSING; sprintf(buf, "%s is destroyed^cannot use this hand", getbodypartname(lf, bp2)); desc = strdup(buf); @@ -10720,9 +10746,14 @@ void killlf(lifeform_t *lf) { while (lf->pack->first) { killob(lf->pack->first); } - // kill object pile free(lf->pack); lf->pack = NULL; + // kill any remaining obs + while (lf->polypack->first) { + killob(lf->polypack->first); + } + free(lf->polypack); + lf->polypack = NULL; // kill flags killflagpile(lf->flags); @@ -11269,6 +11300,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { a->created = B_FALSE; a->pack = addobpile(a, NOLOC, NOOB); + a->polypack = addobpile(a, NOLOC, NOOB); a->turnsskipped = 0; @@ -11786,7 +11818,7 @@ void applylfdammod(int *dam, lifeform_t *lf, object_t *wep) { enum SKILLLEVEL slev; // modify for strength if (!hasflag(wep->flags, F_NOSTRDAMMOD) && !lfhasflag(lf, F_NOSTRDAMMOD)) { - *dam = (int)((float)*dam * getstrdammod(lf)); + *dam = *dam + getstrdammod(lf); } // strength scaling on weapon @@ -12862,8 +12894,7 @@ int losehp_real(lifeform_t *lf, int amt, enum DAMTYPE damtype, lifeform_t *froml // cold: dam*10 chance of shattering potions, or damaging other things. for (o = lf->pack->first ; o ; o = nexto) { nexto = o->next; - //if (isvulnto(o->flags, DT_COLD) && pctchance(amt*10)) { - if (isvulnto(o->flags, DT_COLD, B_FALSE)) { + if (isvulnto(o->flags, DT_COLD, B_FALSE) && pctchance(amt*10)) { int newdam; // object takes 1/4 of damage newdam = pctof(25, amt); @@ -15317,7 +15348,9 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { race_t *newrace; char buf[BUFLEN]; flag_t *retflag[MAXCANDIDATES]; + race_t *origrace = NULL; int nretflags; + int reverting = B_FALSE; //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging newrace = findrace(rid); @@ -15332,20 +15365,23 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { loseconcentration(lf); + // were we already polymorphed? + f = lfhasflag(lf, F_ORIGRACE); + if (f) { + origrace = findrace(f->val[0]); + } + + if (origrace && (newrace == origrace)) { + reverting = B_TRUE; + } + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging if (frompolymorph && (gamemode == GM_GAMESTARTED) && lf->race) { - race_t *origrace = NULL; - // remove 'become a ghost' flag killflagsofid(lf->flags, F_RISEASGHOST); - // were we already polymorphed? - f = lfhasflag(lf, F_ORIGRACE); - if (f) { - origrace = findrace(f->val[0]); - } // announce - if (origrace && (newrace == origrace)) { + if (reverting) { // reverting to original form.... if (!isdead(lf)) { if (isplayer(lf)) { @@ -15370,12 +15406,6 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { killflagsofid(lf->flags, F_ORIGRACE); killflagsofid(lf->flags, F_POLYMORPHED); - // restore stats - for (i = 0; i < MAXATTS; i++) { - lf->att[i] = lf->origatt[i]; - lf->baseatt[i] = lf->origatt[i]; - if (isplayer(lf)) statdirty = B_TRUE; - } } else { if (isplayer(lf)) { msg("^wYou transform into %s %s!", isvowel(newrace->name[0]) ? "an" : "a", newrace->name); @@ -15450,12 +15480,28 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging - // generate stats - for (i = 0; i < MAXATTS; i++) { - rollstat(lf, i); - lf->baseatt[i] = lf->att[i]; + if (reverting) { + // restore stats - note that your "base" attrib score + // is set to your original one here. + for (i = 0; i < MAXATTS; i++) { + lf->att[i] = lf->origatt[i]; + lf->baseatt[i] = lf->origatt[i]; + } + if (isplayer(lf)) statdirty = B_TRUE; + } else { + // remember original atts + for (i = 0; i < MAXATTS; i++) { + lf->origatt[i] = lf->att[i]; + } + + // generate new stats + for (i = 0; i < MAXATTS; i++) { + rollstat(lf, i); + lf->baseatt[i] = lf->att[i]; + } } + if (!retainhp) { // generate hp/maxhp from hit dice lf->maxhp = 0; @@ -15488,6 +15534,8 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { lf->born = B_TRUE; + setlosdirty(lf); + // check whether: // new race can equip things (F_NOBODYPART xx) // new race can hold objects (F_NOPACK xx) @@ -15500,19 +15548,36 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging // no pack? if (lfhasflag(lf, F_NOPACK)) { - // drop everything - if (countobs(lf->pack, B_FALSE)) { - if (isplayer(lf)) { - msg("Your possessions drop to the ground!"); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s possessions drop to the ground!",buf, getpossessive(buf)); + if (reverting) { + // drop everything + if (countobs(lf->pack, B_FALSE)) { + if (isplayer(lf)) { + msg("Your possessions drop to the ground!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s possessions drop to the ground!",buf, getpossessive(buf)); + } + } + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + moveob(o, lf->cell->obpile, o->amt); + } + } else { + // meld + if (countobs(lf->pack, B_FALSE)) { + if (isplayer(lf)) { + msg("Your possessions meld into your new form!"); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s possessions meld into its new form!",buf, getpossessive(buf)); + } + } + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + moveob(o, lf->polypack, o->amt); } - } - for (o = lf->pack->first ; o ; o = nexto) { - nexto = o->next; - - moveob(o, lf->cell->obpile, o->amt); } } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging @@ -15521,6 +15586,41 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { if (!hasbp(lf, bp)) { o = getequippedob(lf->pack, bp); if (o) { + if (reverting) { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + // drop it! + if (isplayer(lf)) { + msg("Your %s drops to the ground!",noprefix(obname)); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s %s drop to the ground!",buf, getpossessive(buf), + noprefix(obname)); + } + moveob(o, lf->cell->obpile, o->amt); + } else { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + // drop it! + if (isplayer(lf)) { + msg("Your %s melds into your new form!",noprefix(obname)); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s %s melds into its new form!",buf, getpossessive(buf), + noprefix(obname)); + } + moveob(o, lf->polypack, o->amt); + } + } + } + } + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging + + for (o = lf->pack->first ; o ; o = nexto) { + nexto = o->next; + + if (!canpickup(lf, o, o->amt)) { + if (reverting) { char obname[BUFLEN]; getobname(o, obname, o->amt); // drop it! @@ -15532,28 +15632,20 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { noprefix(obname)); } moveob(o, lf->cell->obpile, o->amt); + } else { + char obname[BUFLEN]; + getobname(o, obname, o->amt); + if (isplayer(lf)) { + msg("Your %s melds into your new form!",noprefix(obname)); + } else if (cansee(player, lf)) { + getlfname(lf, buf); + msg("%s%s %s melds into its new form!",buf, getpossessive(buf), + noprefix(obname)); + } + moveob(o, lf->polypack, o->amt); } } } - //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging - - for (o = lf->pack->first ; o ; o = nexto) { - nexto = o->next; - - if (!canpickup(lf, o, o->amt)) { - char obname[BUFLEN]; - getobname(o, obname, o->amt); - // drop it! - if (isplayer(lf)) { - msg("Your %s drops to the ground!",noprefix(obname)); - } else if (cansee(player, lf)) { - getlfname(lf, buf); - msg("%s%s %s drop to the ground!",buf, getpossessive(buf), - noprefix(obname)); - } - moveob(o, lf->cell->obpile, o->amt); - } - } //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging @@ -15566,6 +15658,16 @@ void setrace(lifeform_t *lf, enum RACE rid, int frompolymorph) { //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging } // end if gamestarted + if (reverting) { + // restore objects + while (lf->polypack->first) { + moveob(lf->polypack->first, lf->pack, lf->polypack->first->amt); + } + // in case something which affects our vision came out of ->polypack + setlosdirty(lf); + } + + //if (gamemode == GM_GAMESTARTED) checkmapflags(player->cell->map); // debugging } @@ -19013,13 +19115,17 @@ int wear(lifeform_t *lf, object_t *o) { if (isplayer(lf)) msg("You have nowhere to wear that!"); return B_TRUE; } - ch = getchoice(&prompt); + if (isplayer(lf)) { + ch = getchoice(&prompt); - if (ch == '-') { - bp = BP_NONE; - if (isplayer(lf)) msg("Cancelled."); - return B_TRUE; - } else bp = *((enum BODYPART *)prompt.result); + if (ch == '-') { + bp = BP_NONE; + if (isplayer(lf)) msg("Cancelled."); + return B_TRUE; + } else bp = *((enum BODYPART *)prompt.result); + } else { + bp = *((enum BODYPART *)prompt.choice[rnd(0,prompt.nchoices - 1)].data); + } possbp[0] = bp; nparts = 1; diff --git a/map.c b/map.c index f746584..3a177a5 100644 --- a/map.c +++ b/map.c @@ -1212,6 +1212,14 @@ int damagecell(cell_t *c, int amt, enum DAMTYPE damtype) { if (getshardobname(cellmat, what)) { fragments(c, what, 3, 3); } + } else { + switch (cellmat) { + case MT_STONE: + addob(c->obpile, "50-100 stones"); + break; + default: + break; + } } } return B_FALSE; @@ -5822,18 +5830,28 @@ int getslipperyness(cell_t *c, object_t **slipob) { object_t *o,*bestob = NULL; int bestslip = 0; int totalslip = 0; + int addition = 0; if (slipob) *slipob = NULL; + + switch (c->type->id) { + case CT_FLOORTILE: addition = 2; break; + case CT_FLOORCARPET: addition = -2; break; + default: addition = 0; break; + } + for (o = c->obpile->first ; o ; o = o->next) { int thisslip; sumflags(o->flags, F_SLIPPERY, &thisslip, NULL, NULL); + thisslip += addition; + limit(&thisslip, 0, NA); if (thisslip > 0) { if (thisslip > bestslip) { bestob = o; bestslip = thisslip; } + thisslip *= o->amt; + totalslip += thisslip; } - thisslip *= o->amt; - totalslip += thisslip; } totalslip *= 2; @@ -6009,28 +6027,32 @@ void initmap(void) { addhabitat(H_SWAMP, "swamp", CT_CORRIDOR, CT_WALL, 3, 50, 0, MAXVISRANGE); // cell types - solid - addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 100); - addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEDARK, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 50); - addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 50); - addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 50); - addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 25); - addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0, 200); + addcelltype(CT_WALL, "rock wall", UNI_SHADEDARK, C_GREY, B_SOLID, B_OPAQUE, MT_STONE, 0, 50); + addcelltype(CT_WALLDIRT, "dirt wall", UNI_SHADEDARK, C_BROWN, B_SOLID, B_OPAQUE, MT_STONE, 0, 25); + addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 40); + addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 30); + addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 20); + addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0, 75); // cell types - non-solid addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, B_EMPTY, B_TRANS, MT_STONE, 0, -1); addcelltype(CT_CORRIDOR, "rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1); addcelltype(CT_LOOPCORRIDOR, "rock floor", 'L', C_GREY, B_EMPTY, B_TRANS, MT_STONE, 0, -1); + addcelltype(CT_FLOORCARPET, "carpetted floor", '.', C_YELLOW, B_EMPTY, B_TRANS, MT_CLOTH, 0, -1); addcelltype(CT_FLOORWOOD, "wood floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); addcelltype(CT_FLOORFLESH, "flesh floor", '.', C_RED, B_EMPTY, B_TRANS, MT_FLESH, 0, -1); addcelltype(CT_FLOORSHOP, "shop floor", '.', C_BROWN, B_EMPTY, B_TRANS, MT_WOOD, 0, -1); + addcelltype(CT_FLOORTILE, "tiled floor", '.', C_WHITE, B_EMPTY, B_TRANS, MT_METAL, 0, -1); addcelltype(CT_GRASS, "grass", '.', C_GREEN, B_EMPTY, B_TRANS, MT_PLANT, 0, -1); addcelltype(CT_DIRT, "dirt", '.', C_BROWN, B_EMPTY, B_TRANS, MT_STONE, 0, -1); addcelltype(CT_LOWFLOOR, "low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -1, -1); addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -2, -1); // region types - addregiontype(RG_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 0); + // maxdepth stairs stair major? depthmod + // perlev dir + addregiontype(RG_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 0); addregiontype(RG_MAINDUNGEON, "The Main Dungeon", B_FALSE, H_DUNGEON, 25, 3, D_DOWN, B_TRUE, 0); - addregiontype(RG_CAVE, "The Goblin Caves", B_TRUE, H_CAVE, 5, 1, D_DOWN, B_TRUE, 5); + addregiontype(RG_CAVE, "The Goblin Caves", B_TRUE, H_CAVE, 5, 1, D_DOWN, B_TRUE, 2); addregiontype(RG_HEAVEN, "The Realm of Gods", B_FALSE, H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0); addregiontype(RG_PIT, "A Pit", B_FALSE, H_PIT, 1, 1, D_DOWN, B_FALSE, 0); addregiontype(RG_SEWER, "A Sewer", B_FALSE, H_SEWER, 1, 0, D_NONE, B_FALSE, 2); diff --git a/move.c b/move.c index 55d3e09..72a3f46 100644 --- a/move.c +++ b/move.c @@ -2076,7 +2076,9 @@ int closedoor(lifeform_t *lf, object_t *o) { f = hasflag(o->flags, F_DOOR); addflag(o->flags, F_IMPASSABLE, f->val[0], f->val[1], f->val[2], f->text); - addflag(o->flags, F_BLOCKSVIEW, B_TRUE, NA, NA, NULL); + if (hasflag(o->type->flags, F_BLOCKSVIEW)) { + copyflag(o->flags, o->type->flags, F_BLOCKSVIEW); + } if (lf) { // stop sprinting diff --git a/objects.c b/objects.c index 0dd5737..e3d8038 100644 --- a/objects.c +++ b/objects.c @@ -2516,13 +2516,6 @@ int canseeob(lifeform_t *lf, object_t *o) { return B_FALSE; } } - - if (isblind(player) || (o->pile->where && !haslos(player, o->pile->where)) ) { - if (hasflag(o->flags, F_NOFEEL)) { - return B_FALSE; - } - } - f = hasflag(o->flags, F_TRAIL); if (f) { if (f->val[2] == S_SIGHT) { @@ -2572,6 +2565,15 @@ int canseeob(lifeform_t *lf, object_t *o) { } } + if (o->pile->where && (o->pile->where->map == lf->cell->map)) { + if (isblind(lf) || (!haslos(lf, o->pile->where)) ) { + if (hasflag(o->flags, F_NOFEEL)) { + return B_FALSE; + } + } + } + + return B_TRUE; } @@ -3403,6 +3405,21 @@ recipe_t *findrecipefor(enum OBTYPE result) { return NULL; } +int fountain_will_dryup(object_t *o) { + if (hasflagval(o->flags, F_LINKOB, OT_POT_EXPERIENCE, NA, NA, NULL) || + onein(ONEIN_FOUNTAINDRYUP)) { + cell_t *loc; + loc = getoblocation(o); + if (haslos(player, loc)) { + char fname[BUFLEN]; + getobname(o, fname, o->amt); + msg("%s dries up.", fname); + } + return B_TRUE; + } + return B_FALSE; +} + void fragments(cell_t *centre, char *what, int speed, int howfar) { cell_t *c,*dst; int n,dir; @@ -4384,7 +4401,9 @@ enum DEPTH getobdepth(object_t *o, lifeform_t *lf) { char *getobdesc(object_t *o, char *buf) { int blind = B_FALSE; + int known = B_FALSE; if (gamemode == GM_GAMESTARTED) { + // can't see the object ? if (o->pile->owner == player) { if (!haslos(player, player->cell) || isblind(player)) { if (!hasflag(o->flags, F_FEELTEXT)) { @@ -4393,7 +4412,15 @@ char *getobdesc(object_t *o, char *buf) { } } } - if (isknown(o) && !blind) { + + if (isknown(o)) { + known = B_TRUE; + } else { + if (o->pile->parentob && hasflag(o->pile->parentob->flags, F_SHOP)) { + known = B_TRUE; + } + } + if (known && !blind) { if (o->type->id == OT_CORPSE) { flag_t *f; f = hasflag(o->flags, F_CORPSEOF); @@ -7958,11 +7985,12 @@ void obdie(object_t *o) { if (f->val[2] == B_IFACTIVATED) { if (isactivated(o)) { explodeob(o, f, f->val[1]); + return; } } else { explodeob(o, f, f->val[1]); + return; } - return; } @@ -8920,7 +8948,6 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { getobname(newob, newobname, newob->amt); msgnocap("%c - %s.",newob->letter, newobname); } - // kill the ground object? switch (oo->type->id) { case OT_SPLASHWATER: case OT_BLOODSPLASH: @@ -8930,20 +8957,13 @@ int operate(lifeform_t *lf, object_t *o, cell_t *where) { removeob(oo, 1); break; case OT_FOUNTAIN: - if (hasflagval(oo->flags, F_LINKOB, OT_POT_EXPERIENCE, NA, NA, NULL) || - onein(ONEIN_FOUNTAINDRYUP)) { - cell_t *loc; - loc = getoblocation(oo); - if (haslos(player, loc)) { - char fname[BUFLEN]; - getobname(oo, fname, oo->amt); - msg("%s dries up.", obname); - } + if (fountain_will_dryup(oo)) { removeob(oo, oo->amt); } break; default: break; + } } else { msg("That doesn't seem like a very good idea."); @@ -9403,7 +9423,6 @@ int pour(lifeform_t *lf, object_t *o) { // god effects if (isplayer(lf)) { pleasegodmaybe(R_GODPURITY, 3); - angergodmaybe(R_GODDEATH, 15, GA_HERESY); } } else if ((o->type->id == OT_POT_WATER) && (o->blessed == B_CURSED)) { // unholy water if (isplayer(lf)) { @@ -9416,7 +9435,6 @@ int pour(lifeform_t *lf, object_t *o) { if (!isknown(o)) makeknown(o->type->id); // god effects if (isplayer(lf)) { - pleasegodmaybe(R_GODDEATH, 3); angergodmaybe(R_GODPURITY, 25, GA_HERESY); } } else if (o->type->id == OT_POT_INVULN) { @@ -9648,13 +9666,10 @@ void quaff(lifeform_t *lf, object_t *o) { } // fountains sometimes dry up - if ((o->type->id == OT_FOUNTAIN) && onein(ONEIN_FOUNTAINDRYUP)) { - cell_t *loc; - // dry up (ie. remove DONTKILL property) - drinkflag->val[2] = NA; - loc = getoblocation(o); - if (haslos(player, loc)) { - msg("%s dries up.", obname); + if (o->type->id == OT_FOUNTAIN) { + if (fountain_will_dryup(o)) { + // dry up (ie. remove DONTKILL property) + drinkflag->val[2] = NA; } } @@ -9877,6 +9892,7 @@ void potioneffects(lifeform_t *lf, enum OBTYPE oid, object_t *o, enum BLESSTYPE break; case OT_POT_FURY: + lf->stamina = getmaxstamina(lf); abilityeffects(lf, OT_A_RAGE, lf->cell, lf, NULL); break; case OT_POT_GASEOUSFORM: @@ -10547,6 +10563,7 @@ int readsomething(lifeform_t *lf, object_t *o) { removeob(o, 1); } else if (o->type->id == OT_SCR_PERMENANCE) { int ndone = 0; + enum ATTRIB a; flag_t *f; // makes certain flags permenant for (f = lf->flags->first ; f ; f = f->next) { @@ -10555,6 +10572,17 @@ int readsomething(lifeform_t *lf, object_t *o) { ndone++; } } + // make enhanced/reduced attributes permenant + for (a = 0; a < MAXATTS; a++) { + int innate,actual; + innate = lf->att[a]; + actual = getattr(lf, a); + if (actual != innate) { + lf->att[a] = actual; + ndone++; + if (isplayer(lf)) statdirty = B_TRUE; + } + } if (isplayer(lf)) { if (ndone) { @@ -11929,7 +11957,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp glyph_t *gl; gl = getglyph(o); anim(where, srcloc, gl->ch, gl->colour); - msg("%s is reflected away from %s!", obname, targetname); + msg("%s %s reflected away from %s!", obname, (o->amt == 1) ? "is" : "are", targetname); } // adjust target where = srcloc; @@ -12031,7 +12059,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp if (check_for_block(thrower, target, getthrowdam(o) + speed, DT_PROJECTILE, difficulty, attackname)) { announcedmiss = B_TRUE; youhit = B_FALSE; - missiledam += ((speed*2)+1); + missiledam += ((speed*2)+rnd(1,4)); } } @@ -12218,7 +12246,7 @@ int real_fireat(lifeform_t *thrower, object_t *o, int amt, cell_t *where, int sp wepeffects(o->flags, target->cell, hasflag(o->flags, F_DAM), dam); - missiledam += ((speed*2)+1); + missiledam += ((speed*2)+rnd(1,4)); if (willtangle) { missiledam = 0; // don't damage the misisle diff --git a/objects.h b/objects.h index 6a1a9cf..cd4e2e6 100644 --- a/objects.h +++ b/objects.h @@ -63,6 +63,7 @@ obmod_t *findobmod(enum OBMOD id); objecttype_t *findot(enum OBTYPE id); objecttype_t *findotn(char *name); // find objecttype by name recipe_t *findrecipefor(enum OBTYPE result); +int fountain_will_dryup(object_t *o); void fragments(cell_t *centre, char *what, int speed, int howfar); void genhiddennames(void); enum LFSIZE getarmoursize(object_t *o); diff --git a/save.c b/save.c index 586c96e..224d779 100644 --- a/save.c +++ b/save.c @@ -276,6 +276,34 @@ lifeform_t *loadlf(FILE *f, cell_t *where) { } if (db) dblog("----> done (id=%ld)",thisid); } + + // now repeat the above for polypack... + obcount = 0; + obid = 9998; // for testing + rv = fscanf(f, "polyob:%ld\n",&obid); + while (obid != -1) { + if (db) dblog("--> Load ob id %d into polypack list...",obid); + l->polypack->oblist[obcount] = obid; + obcount++; + fscanf(f, "polyob:%ld\n",&obid); + } + // terminate with -1s! + for (i = obcount ; i < MAXPILEOBS; i++) { + l->polypack->oblist[i] = -1; + } + if (db) dblog("--> Finished polypack oblist. Found %d objects.",obcount); + // now load object defs for this lf's pack! + fscanf(f, "polyobdefs\n"); + for (i = 0; i < obcount; i++) { + long thisid; + if (db) dblog("--> Creating polypack ob #%d for lf.",i); + //if (db) dblog("-----> ob %d/%d...\n",i+1,obcount); + if (loadob(f, l->polypack, &thisid)) { + dblog("Error - can't create object %d/%d!\n",i+1,obcount); + exit(1); + } + if (db) dblog("----> done (id=%ld)",thisid); + } // is this the player? if (l->controller == C_PLAYER) { @@ -857,6 +885,19 @@ int savelf(FILE *f, lifeform_t *l) { saveob(f, o); } + // lifeform polypack objects + obcount = 0; + for (o = l->polypack->first ; o ; o = o->next) { + fprintf(f, "polyob:%ld\n",o->id); + obcount++; + } + fprintf(f, "polyob:-1\n"); + fprintf(f, "polyobdefs\n"); + // now save our polypack object definitions + for (o = l->polypack->first ; o ; o = o->next) { + saveob(f, o); + } + return B_FALSE; } diff --git a/spell.c b/spell.c index 052fa73..27523b2 100644 --- a/spell.c +++ b/spell.c @@ -2317,7 +2317,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef if (isplayer(user)) { msg("You try to trip %s, but fail.",targetname); } else if (cansee(player, user)) { - msg("%s tries to trip %s, but fail.",username, targetname); + msg("%s tries to trip %s, but fails.",username, targetname); } } } else if (abilid == OT_A_TUMBLE) { @@ -4828,7 +4828,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("%s forms %s %s%s %s!", obname, getbodypartequipname(bp[i]), castername, getpossessive(castername), getbodypartname(target, bp[i])); } - wear(target, o); + // don't use "wear" because we don't want it being announced. + addflag(o->flags, F_EQUIPPED, bp[i], -1, -1, NULL); // set its values f = hasflag(o->flags, F_OBHP); if (f) { @@ -4861,7 +4862,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } o = addob(target->pack, "ice crystal shield"); if (o) { - if (canwear(target, o, BP_NONE)) { + if (canwear(target, o, BP_SECWEAPON)) { flag_t *f; enum LFSIZE sz; if (power <= 2) { @@ -4878,7 +4879,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("A %s shield of shimmering ice forms in %s%s hand!", getsizetext(sz), castername, getpossessive(castername)); } - wear(target, o); + // don't use "wear" because we don't want it being announced. + addflag(o->flags, F_EQUIPPED, BP_SECWEAPON, -1, -1, NULL); // set its values f = hasflag(o->flags, F_OBHP); if (f) { @@ -5244,11 +5246,17 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } // end if isplayer } else if (spellid == OT_S_DETONATE) { // don't need line of fire! - explodecells(targcell, 20, B_TRUE, NULL, power / 4, DT_ORTH, B_TRUE); + explodecells(targcell, 20+(power*2), B_TRUE, NULL, power / 4, DT_ORTH, B_TRUE); if (haslos(player, targcell)) { if (seenbyplayer) *seenbyplayer = B_TRUE; } + } else if (spellid == OT_S_DETONATEDELAY) { + addobfast(targcell->obpile, OT_VIBCLOUD); + if (haslos(player, targcell)) { + msg("The air nearby begins to vibrate violently..."); more(); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } } else if (spellid == OT_S_EQANDOP) { flag_t *f; f = addtempflag(caster->flags, F_REFLECTION, B_TRUE, NA, NA, NULL, FROMSPELL); @@ -6468,7 +6476,6 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // affect equipped objects for (o = target->pack->first ; o ; o = nexto) { nexto = o->next; - // destroy metal items on the ground if (ismetal(o->material->id)) { int dodam = B_FALSE; if (isequippedon(o, BP_WEAPON) || isequippedon(o, BP_SECWEAPON)) { @@ -6491,7 +6498,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ noprefix(obname), OBS1(o)); if (seenbyplayer) *seenbyplayer = B_TRUE; } - takedamage(o, rnd(1,4), DT_HEAT); + takedamage(o, rnd(6,12), DT_HEAT); } } } @@ -6515,7 +6522,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // affect objects on ground for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; - // destroy metal items on the ground + // damage metal items on the ground if (ismetal(o->material->id)) { if (haslos(player, targcell)) { char obname[BUFLEN]; @@ -6524,7 +6531,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; donesomething = B_FALSE; } - takedamage(o, rnd(1,4), DT_HEAT); + takedamage(o, rnd(6,12), DT_HEAT); } } } @@ -8592,17 +8599,13 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_FALSE; } amttolose = power*2; - // only announce if the target will have some stamina left. - // if they drop to 0, modstamina will handle the announce. - if (getstamina(target) >= amttolose) { - if (isplayer(target)) { - msg("You suddenly feel very lethargic!"); - } else if (cansee(player, target)) { - char targname[BUFLEN]; - getlfname(target, targname); - msg("%s looks very lethargic!", targname); - } - } + if (isplayer(target)) { + msg("You suddenly feel very lethargic!"); + } else if (cansee(player, target)) { + char targname[BUFLEN]; + getlfname(target, targname); + msg("%s looks very lethargic!", targname); + } modstamina(target, -amttolose); } else if (spellid == OT_S_REPELINSECTS) { // just announce @@ -9080,7 +9083,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (targcell->lf) { - losehp(targcell->lf, rnd(1,6), DT_FIRE, caster, "a spark"); + losehp(targcell->lf, rnd(2,2), DT_FIRE, caster, "a spark"); } else { for (o = targcell->obpile->first ; o ; o = nexto) { nexto = o->next; @@ -9923,7 +9926,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // set its damage value f = hasflag(o->flags, F_DAM); if (f) { - f->val[1] = 2+(power*2); + f->val[1] = 2+power; } addflag(o->flags, F_CREATEDBYSPELL, spellid, NA, NA, NULL); } else { @@ -10054,6 +10057,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ char lfname[BUFLEN]; cell_t *retcell[MAXRETCELLS]; int nretcell,i; + int dam; // animation //anim(caster->cell, targcell, '}', C_BLUE); if (isplayer(caster) || cansee(player, caster)) { @@ -10062,30 +10066,37 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } + dam = roll("2d6"); + calcbresnham(caster->cell->map, caster->cell->x, caster->cell->y, targcell->x, targcell->y, retcell, &nretcell); for (i = 1; i < nretcell; i++) { target = haslf(retcell[i]); if (target) { - int dir,amt, i; + int dir,amt, n; object_t *arm[MAXBODYPARTS]; int narm = 0; + int dam; getlfname(target, lfname); // hit if (cansee(player, target)) { msg("%s %s hit by a jet of water!",lfname, is(target)); } + + // does less damage the further you are away. + if (dam > 0) dam--; + // water damage will generally be turn to zero unless people are specifically // vulnerable to water, so do bashing damage too. - losehp(target, roll("3d4"), DT_WATER, caster, "a high-pressure jet of water"); - losehp(target, roll("3d4"), DT_BASH, caster, "a high-pressure jet of water"); + losehp(target, dam, DT_WATER, caster, "a high-pressure jet of water"); + losehp(target, dam, DT_BASH, caster, "a high-pressure jet of water"); // knock backwards dir = getdirtowards(caster->cell, target->cell, target, B_FALSE, DT_COMPASS); amt = (power/3); if (amt < 2) amt = 2; knockback(target, dir, amt, caster, 0, B_TRUE); // rust getallouterarmour(target, arm, &narm); - for (i = 0; i < narm; i++) { - takedamage(arm[i], R_TRUSTY, DT_WATER); + for (n = 0; n < narm; n++) { + takedamage(arm[n], R_TRUSTY, DT_WATER); } // add water object addob(retcell[i]->obpile, "large puddle of water"); @@ -11160,8 +11171,11 @@ int getstamcost(lifeform_t *lf, enum OBTYPE oid) { flag_t *f; f = lfhasflagval(lf, F_CANWILL, oid, NA, NA, NULL); if (f) { + int newcost; // override stamina cost? - texttospellopts(f->text, "stamcost:", &stamcost, NULL); + if (texttospellopts(f->text, "stamcost:", &newcost, NULL)) { + stamcost = newcost; + } } if (stamcost == -1) { objecttype_t *ot; diff --git a/text.c b/text.c index b3973bd..604ca10 100644 --- a/text.c +++ b/text.c @@ -99,7 +99,7 @@ char *construct_hit_string(lifeform_t *lf, lifeform_t *victim, char *attackernam // modify victimname if required //if (helpless && !isbehind(lf, victim)) { - if (!isplayer(victim) && ishelplessvictim(victim, lf, &helpless)) { + if (victim && !isplayer(victim) && ishelplessvictim(victim, lf, &helpless)) { char *vn; // strip "the" from "the xxx" vn = strdup(victimname); @@ -1914,9 +1914,11 @@ void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *r } */ -void texttospellopts(char *text, ... ) { +// returns # opts filled in +int texttospellopts(char *text, ... ) { char *p; va_list args; + int nfilled = 0; char *validname[] = { "pw:", "dam:", @@ -1990,6 +1992,7 @@ void texttospellopts(char *text, ... ) { } else if (argtype[foundidx] == 's') { strcpy((char *)writeto, valfull); } + nfilled++; } } } @@ -1999,6 +2002,7 @@ void texttospellopts(char *text, ... ) { if (wantname) writeto = va_arg(args, void *); } va_end(args); + return nfilled; } char *you(lifeform_t *lf) { diff --git a/text.h b/text.h index 5f1b43c..9e3a495 100644 --- a/text.h +++ b/text.h @@ -60,7 +60,7 @@ char *strends(char *a, char *suffix); char *strstarts(char *a, char *prefix); int strpixmatch(char *haystack, char *needle); int texttodice(char *text, int *ndice, int *nsides, int *bonus); -void texttospellopts(char *text, ... ); +int texttospellopts(char *text, ... ); //void texttospellopts(char *text, int *power, char *damstr, int *needgrab, int *range, char *racestr); char *you(lifeform_t *lf); char *you_l(lifeform_t *lf); diff --git a/vaults/bedroom.vlt b/vaults/bedroom.vlt index 19b5036..4c5f92f 100644 --- a/vaults/bedroom.vlt +++ b/vaults/bedroom.vlt @@ -9,6 +9,7 @@ @end @legend +.:cell:carpetted floor #:cell:rock wall b:ob:wooden bed t:ob:wooden table diff --git a/vaults/diningroom.vlt b/vaults/diningroom.vlt index 1e3b88c..b929d1a 100644 --- a/vaults/diningroom.vlt +++ b/vaults/diningroom.vlt @@ -13,6 +13,7 @@ entertext:You enter a dining room. autodoors:75 autopop ! tables & chairs +fill(1,1,-2,-2) cell:tiled floor scatter(1,1,-2,-2) ob:wooden table:20% scatter(1,1,-2,-2) ob:wooden footstool:20% scatter(1,1,-2,-2) ob:random food:1-2