diff --git a/ai.c b/ai.c index 41902aa..a189d2d 100644 --- a/ai.c +++ b/ai.c @@ -476,6 +476,21 @@ void aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victi // 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]; @@ -1725,12 +1740,12 @@ int aiobok(lifeform_t *lf, object_t *o, lifeform_t *target) { switch (o->type->id) { case OT_POT_INVIS: case OT_WAND_INVIS: - if (lfhasflag(target, F_INVISIBLE)) { + if (target && lfhasflag(target, F_INVISIBLE)) { return B_FALSE; } break; case OT_POT_INVULN: - if (lfhasflag(target, F_INVULNERABLE)) { + if (target && lfhasflag(target, F_INVULNERABLE)) { return B_FALSE; } break; @@ -2025,6 +2040,18 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } } } + } else if (ot->id == OT_S_DIG) { + cell_t *cell[MAXCANDIDATES]; + int ncells,i; + 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) { + ok = B_TRUE; + break; + } + } } else if (ot->id == OT_A_JUMP) { cell_t *cell[MAXCANDIDATES],*c; int ncells,i; @@ -2434,11 +2461,11 @@ int lookforobs(lifeform_t *lf) { if (db) dblog(".oO { no targetcell, so looking for remote objects }"); for (i = 0 ; i < lf->nlos; i++) { int gothere = B_FALSE; + int celldist; c = lf->los[i]; + celldist = getcelldist(lf->cell, c); if ((c != lf->cell) && !c->lf && !lfhasflagval(lf, F_IGNORECELL, c->x, c->y, NA, NULL)) { - int celldist; - celldist = getcelldist(lf->cell, c); for (o = c->obpile->first ; o ; o = nexto) { nexto = o->next; @@ -2510,6 +2537,72 @@ int lookforobs(lifeform_t *lf) { return B_FALSE; } } + } else if ((celldist == 1) && c->lf && + (isunconscious(c->lf) || isasleep(c->lf)) && + (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) && !isundead(lf)) { + // intelligent enemies will loot unconscious lfs to make sure they are not a threat. + // + // in this case they'll loot more than normal. even if they wouldn't normally pick up + // some of these objects, they'll assume they are good because the player was holding + // them. + + int getit = B_FALSE; + for (o = c->lf->pack->first ; o ; o = nexto) { + nexto = o->next; + getit = B_FALSE; + if (aiwants_real(lf, o, &covets, &noids, oid, oidcovet, &nwantflags, wantflag, wantflagcovet)) { + getit = B_TRUE; + } else if (areenemies(lf, c->lf) && (isweapon(o) || isarmour(o))) { + getit = B_TRUE; + } else { + if (aiobok(lf, o, NULL)) { + flag_t *retflag[MAXCANDIDATES]; + int nretflags; + getflags(o->flags, retflag, &nretflags, F_AIBOOSTITEM, F_AIFLEEITEM, F_AIHEALITEM, F_NONE); + if (nretflags) { + getit = B_TRUE; + } + } + } + + // if we are in battle only go for it if we covet it + if (getit) { + if (target && !covets) getit = B_FALSE; + if (isdangerousob(o, lf, B_TRUE) || !aipickupok(lf, o)) getit = B_FALSE; + } + if (getit) { + break; + } + } + + if (getit) { + int returnnow = B_FALSE; + if (db) dblog(".oO { adjacent unconscious lf has ob i want (%s) }",o->type->name); + // try to pick it up + if (aipickup(lf, o)) { + if (db) dblog(".oO { pickup of %s failed, trying to eat! }",o->type->name); + } else { + returnnow = B_TRUE; // got it! + } + + if (!returnnow) { + if (eat(lf, o)) { + if (db) dblog(".oO { eating %s failed }",o->type->name); + } else { + returnnow = B_TRUE; + } + } + + if (returnnow) { + // if they were only sleeping, they wake up a bit + f = isasleep(c->lf); + if (f) { + timeeffectsflag(f, 3 + rnd(1,3)); + } + return B_TRUE; + } + } + } } } diff --git a/attack.c b/attack.c index 9d1b19f..ea8c3f0 100644 --- a/attack.c +++ b/attack.c @@ -279,10 +279,31 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { attacktarget = o; } else { // TODO: attack wall? - if (isplayer(lf) && !lfhasflag(lf, F_HURRICANESTRIKE)) { - msg("There is nothing there to attack!"); - } - return B_TRUE; + if (!lfhasflag(lf, F_HURRICANESTRIKE)) { + /* + flag_t *sf; + lifeform_t *stomachlf = NULL; + sf = hasflag(lf->cell->map->flags, F_STOMACHOF); + if (sf) { + stomachlf = findlf(NULL, sf->val[0]); + } + // we ARE allowed to attack stomach walls. + if (sf && stomachlf && (c->type->id == CT_WALLFLESH)) { + attacktype = AT_LF; + attacktarget = stomachlf; + } else { + // not allowed to attack normal walls + if (isplayer(lf)) { + msg("There is nothing there to attack!"); + } + return B_TRUE; + } + */ + if (isplayer(lf)) { + msg("There is nothing there to attack!"); + } + return B_TRUE; + } // end if !hurricanestrike } } } @@ -350,7 +371,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { int first; // player never invalidates their equipped weapons - if (isplayer(lf) && gotweapon) { + //if (isplayer(lf) && gotweapon) { + if (gotweapon) { first = lastweaponidx+1; } else { first = 0; @@ -921,15 +943,15 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) warn("%s", buf); } } - if (!isplayer(lf) && !isplayer(victim)) { - noise(lf->cell, lf, NC_OTHER, 3, "fighting.", NULL); - } + //if (!isplayer(lf) && !isplayer(victim)) { + noise(lf->cell, lf, NC_FIGHTING, 3, "fighting.", NULL); + //} if (fatal) { if (strstr(buf, "behead")) { // we'll need to place the severed head object addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); } - if (!hasflag(victim->flags, F_NODEATHANNOUNCE)) { + if (cansee(player, victim) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { // don't also say "the xx dies" addflag(victim->flags, F_NODEATHANNOUNCE, B_TRUE, NA, NA, NULL); } @@ -1117,7 +1139,7 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) char damstring[BUFLEN]; rdam = rolldie(f->val[0], f->val[1]); if (cansee(player, victim)) { - msg("^%c%s%s %s %s %s!", isplayer(victim) ? 'b' : 'n', victimname, getpossessive(victimname), + msg("^%c%s%s %s %s %s!", isplayer(lf) ? 'b' : 'n', victimname, getpossessive(victimname), noprefix(f->text), getattackverb(victim, NULL, f->val[2], rdam, lf->maxhp), attackername); @@ -1787,8 +1809,8 @@ void getdamrange(object_t *o, flag_t *f, int *min, int *max) { if (f) { if (hasflag(o->flags, F_MASTERWORK)) { - // 75%-100% - mindam = pctof(75,f->val[1]); + // 85%-100% + mindam = pctof(85,f->val[1]); maxdam = f->val[1]; } else if (hasflag(o->flags, F_SHODDY)) { // 25% - 75% diff --git a/data.c b/data.c index 329c85e..4ca3cf0 100644 --- a/data.c +++ b/data.c @@ -1736,54 +1736,63 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 250, NA, NA, NULL); addot(OT_AMETHYST, "amethyst", "A purple gemstone.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_MAGENTA, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 15, NA, NA, NULL); addot(OT_DIAMOND, "diamond", "A sparkling diamond.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 1000, NA, NA, NULL); addot(OT_EMERALD, "emerald", "A deep green gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_GREEN, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 650, NA, NA, NULL); addot(OT_OPAL, "opal", "An amorphous form of silica related to quartz.", MT_STONE, 0.1, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_GREY, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 70, NA, NA, NULL); addot(OT_PEARL, "pearl", "A small pinkish-white gem.", MT_STONE, 0.1, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_WHITE, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 30, NA, NA, NULL); addot(OT_RUBY, "ruby", "A large red gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_RED, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 110, NA, NA, NULL); addot(OT_SAPPHIRE, "sapphire", "A brilliant blue gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_CYAN, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 850, NA, NA, NULL); addot(OT_TOPAZ, "topaz stone", "A dull blue gem.", MT_STONE, 0.2, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BLUE, '*', NA, NULL); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); @@ -2206,6 +2215,9 @@ void initobjects(void) { // scrolls + addot(OT_SCR_AMNESIA, "scroll of amnesia", "Causes the reader to lose all accumulated skill points.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); + addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); addot(OT_SCR_AWARENESS, "scroll of awareness", "Mimics the effects of a 'heightened awareness' spell.", MT_PAPER, 0.5, OC_SCROLL, SZ_SMALL); addflag(lastot->flags, F_VALUE, 50, NA, NA, NULL); @@ -2430,6 +2442,13 @@ void initobjects(void) { 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_FALSE, LOF_NEED, NA, NULL); + addot(OT_S_FLAYFLESH, "flay flesh", "Causes invisible tendrils to strike your foe, causing an automatic slash critical on fleshy creatures.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_DEATH, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 3, 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_RANGE, 3, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_WALLSTOP, NA, NULL); addot(OT_S_PAIN, "pain", "Causes extreme pain in the target whenever they move.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Spell power determines the duration of the pain effect."); addflag(lastot->flags, F_SPELLSCHOOL, SS_ENCHANTMENT, NA, NA, NULL); @@ -2975,8 +2994,6 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, 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_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_NEED, NA, NULL); // l4 addot(OT_S_DIG, "dig", "Blasts away earth to create passages.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); @@ -2984,6 +3001,8 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SELF, NA, NA, NULL); addot(OT_S_ENTANGLE, "entangle", "Causes magical vines to hold enemies.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "The spell's power determines the strength of the vines."); addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); @@ -3567,7 +3586,7 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_DEBUG, "debug", "You can toggle debugging for a lifeform.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); - addot(OT_A_ENHANCE, "enhance", "Enhance a lifeform's stats.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addot(OT_A_ENHANCE, "enhance stats", "Enhance a lifeform's stats.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_LEARN, "learn", "Learn new skills.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); @@ -3642,6 +3661,8 @@ void initobjects(void) { addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); addflag(lastot->flags, F_NEEDSGRAB, B_TRUE, NA, NA, NULL); + addot(OT_A_ENHANCEOB, "enhance item", "Combine two regular items into a single masterwork item.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_FEIGNDEATH, "feign death", "Pretend to be dead.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addot(OT_A_FLIP, "flip", "Flip your opponent over your head.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); @@ -3655,6 +3676,10 @@ void initobjects(void) { addot(OT_A_GRAB, "grab", "You can grab hold of nearby enemies to prevent their escape.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); + addot(OT_A_EXPOSEDSTRIKE, "wild strike", "A wild blow directly at your enemy with no regard for safety. Almost always hits, but leaves you completely exposed to follow-up attacks.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); + //addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); + addflag(lastot->flags, F_STAMCOST, 1, NA, NA, NULL); addot(OT_A_HEAVYBLOW, "heavy blow", "Mighty blow which knocks enemies backwards.", MT_NOTHING, 0, OC_ABILITY, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_ABILITY, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_ADJVICTIM, NA, NA, NULL); @@ -5655,6 +5680,14 @@ void initobjects(void) { addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "peck"); + addot(OT_DRILL, "drills", "drills object", MT_METAL, 0, OC_WEAPON, SZ_TINY); + addflag(lastot->flags, F_DAM, DT_SLASH, 2, NA, NULL); + addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_ATTACKVERB, NA, NA, NA, "drill"); + addflag(lastot->flags, F_ACCURACY, 100, NA, NA, NULL); + addflag(lastot->flags, F_USESSKILL, SK_NONE, NA, NA, NULL); + addflag(lastot->flags, F_UNARMEDWEP, B_TRUE, NA, NA, NULL); + addot(OT_CLAWS, "claws", "claws object", MT_BONE, 0, OC_WEAPON, SZ_TINY); addflag(lastot->flags, F_DAM, DT_SLASH, 2, NA, NULL); addflag(lastot->flags, F_NOSTRDAMMOD, B_TRUE, NA, NA, NULL); @@ -6994,6 +7027,7 @@ void initrace(void) { // human monsters... addrace(R_BANDITLDR, "bandit leader", 75, '@', C_GREY, MT_FLESH, RC_HUMANOID, "Like a regular bandit, but bigger and stronger. Enough so to bully their followers into submission anyway."); + lastrace->baseid = R_BANDIT; setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_RARE, NULL); @@ -7024,6 +7058,7 @@ void initrace(void) { addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_ALL, NA, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_VARLEVEL, NA, NA, NA, NULL); + addflag(lastrace->flags, F_DEMANDSBRIBE, NA, 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_HITDICE, NA, NA, NA, "2d4"); @@ -8463,6 +8498,23 @@ void initrace(void) { addflag(lastrace->flags, F_NOFLEE, 5, NA, NA, NULL); addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addrace(R_SINKMITE, "sinkmite", 2, 'm', C_GREY, MT_FLESH, RC_ANIMAL, "A mutated humanoid with large drills in place of hands. It gained its name from its ability to 'sink' out of range when threatened."); + setbodytype(lastrace, BT_HUMANOID); + 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_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "4d4"); + addflag(lastrace->flags, F_DTIMMUNE, DT_PROJECTILE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_FALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_DRILL, 5, NA, NULL); + addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_DIG, NA, NA, "pw:1;"); + addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "pounds its drills into the ground"); + addrace(R_SPRITEFIRE, "fire sprite", 5, 'n', C_RED, MT_FIRE, RC_MAGIC, "A small magical creature surrounded by crackling flames."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "small fire"); @@ -9196,7 +9248,6 @@ void initrace(void) { addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); addflag(lastrace->flags, F_WALKVERB, NA, NA, NA, "hop"); - addrace(R_HAWKYOUNG, "young hawk", 1, 'A', C_GREY, MT_FLESH, RC_ANIMAL, "A young baby hawk."); // 'A' for Avian setbodytype(lastrace, BT_BIRD); lastrace->baseid = R_HAWK; @@ -9213,6 +9264,7 @@ void initrace(void) { addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "1d4+2"); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 2, NA, NULL); + addflag(lastrace->flags, F_MAXATTACKS, 1, 1, NA, NULL); addflag(lastrace->flags, F_EVASION, 10, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_NOPACK, B_TRUE, NA, NA, NULL); @@ -9726,7 +9778,7 @@ void initrace(void) { //addflag(lastrace->flags, F_WANTSOBFLAG, F_RARITY, NA, NA, NULL); // ie. everything addflag(lastrace->flags, F_CANWILL, OT_A_SWALLOW, 5, 5, NULL); addflag(lastrace->flags, F_CASTCHANCE, 100, NA, NA, NULL); - addflag(lastrace->flags, F_SPELLCASTTEXT, NA, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "opens its mouth wide.."); addflag(lastrace->flags, F_NOISETEXT, N_WALK, SV_ROAR, NA, "^slithering"); addflag(lastrace->flags, F_FLEEONHPPCT, 20, NA, NA, ""); addflag(lastrace->flags, F_MORALE, 50, NA, NA, NULL); @@ -10397,7 +10449,58 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); - addrace(R_QUASIT, "quasit", 4, '&', C_BROWN, MT_FLESH, RC_DEMON, "A tiny, bald humanoid with small spiked horns running down the middle of its scalp, leathery bat-like wings and of course sharp claws.."); + addrace(R_NECRONREAPER, "necron reaper", 65, 'N', C_RED, MT_FLESH, RC_DEMON, "An evil demonic creature, covered in spikes and the bright red blood of its victims."); + setbodytype(lastrace, BT_HUMANOID); + addbodypart(lastrace, BP_TAIL, NULL); + addbodypart(lastrace, BP_WINGS, NULL); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_RETALIATE, 1, 4, DT_PIERCE, "spikes"); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, NA, NA, NA, "6d4"); + addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 4, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); + 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_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); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_POLEARMS, PR_SKILLED, NA, NULL); + addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "scythe"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "screechs^an other-wordly screech"); + + addrace(R_NECRONTRAPPER, "necron trapper", 65, 'N', C_BLUE, MT_FLESH, RC_DEMON, "A wiry, muscled humanoid whose blue-black flesh seems to writhe and pulse. Its elongatd jaw holds razor-sharp fangs which drip with saliva."); + setbodytype(lastrace, BT_HUMANOID); + addbodypart(lastrace, BP_TAIL, NULL); + addbodypart(lastrace, BP_WINGS, NULL); + addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); + addflag(lastrace->flags, F_STARTHIDDENPCT, 70, 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_HITDICE, NA, NA, NA, "5d4"); + addflag(lastrace->flags, F_REGENERATES, 1, NA, NA, NULL); + addflag(lastrace->flags, F_ARMOURRATING, 6, 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_STARTATT, A_IQ, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 3, NA, NULL); + addflag(lastrace->flags, F_VAMPIRIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_SEEINDARK, 10, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_POISON, NA, NA, NULL); + addflag(lastrace->flags, F_DTRESIST, DT_FIRE, NA, NA, NULL); + addflag(lastrace->flags, F_DETECTMAGIC, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_STEALTH, PR_ADEPT, NA, NULL); + addflag(lastrace->flags, F_CANWILL, OT_S_ENTANGLE, 3, 3, "pw:5;"); + addflag(lastrace->flags, F_CANWILL, OT_S_INVISIBILITY, 5, 5, "pw:1;"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, NA, "grins"); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 2, NA, "screechs^an other-wordly screech"); + + addrace(R_QUASIT, "quasit", 4, '&', C_BROWN, MT_FLESH, RC_DEMON, "A tiny, bald humanoid with small spiked horns running down the middle of its scalp, leathery bat-like wings and of course sharp claws..."); setbodytype(lastrace, BT_HUMANOID); addbodypart(lastrace, BP_TAIL, NULL); addbodypart(lastrace, BP_WINGS, NULL); @@ -10866,13 +10969,12 @@ void initskills(void) { addskill(SK_LOCKPICKING, "Lockpicking", "Enhances your ability to pick locks.", 50); addskilldesc(SK_LOCKPICKING, PR_NOVICE, "^gYou gain the 'pick locks' ability.^n", B_FALSE); addskill(SK_METALWORK, "Metalwork", "Lets you repair metal objects.", 100); - addskilldesc(SK_METALWORK, PR_NOVICE, "^gYou can repair metal items up to 33% condition.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items up to 50% condition.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items up to 60% condition.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can repair metal items up to 70% condition.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_NOVICE, "^gYou can repair metal items up to 40% condition.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_BEGINNER, "^gYou can repair metal items up to 60% condition.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_ADEPT, "^gYou can repair metal items up to 80% condition.^n", B_FALSE); addskilldesc(SK_METALWORK, PR_SKILLED, "^gYou can re-size metal armour (at the expense of durability).^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can repair metal items up to 85% condition.^n", B_FALSE); - addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can fully repair metal items.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_EXPERT, "^gYou can fully repair metal items.^n", B_FALSE); + addskilldesc(SK_METALWORK, PR_MASTER, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); addskill(SK_RANGED, "Ranged Weapons", "Your ability to aim a ranged weapon like a bow or gun.", 50); addskilldesc(SK_RANGED, PR_INEPT, "^gYour ranged accuracy decreases by 32%% per cell.^n", B_FALSE); addskilldesc(SK_RANGED, PR_NOVICE, "^gYour ranged accuracy decreases by 22%% per cell.^n", B_FALSE); @@ -10885,13 +10987,15 @@ void initskills(void) { addskilldesc(SK_RANGED, PR_MASTER, "^gYour ranged attacks now deal 50% more damage.^n", B_TRUE); addskilldesc(SK_RANGED, PR_MASTER, "^gYour ranged accuracy decreases by 6%% per cell.^n", B_FALSE); addskill(SK_SEWING, "Sewing", "Lets you repair cloth or leather objects.", 100); - addskilldesc(SK_SEWING, PR_NOVICE, "^gYou can repair cloth items up to 33% condition.^n", B_FALSE); - addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can repair cloth items up to 50% condition^n", B_FALSE); - addskilldesc(SK_SEWING, PR_ADEPT, "^gYou can repair cloth items up to 60% condition^n", B_FALSE); - addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can repair cloth items up to 70% condition^n", B_FALSE); + addskilldesc(SK_SEWING, PR_NOVICE, "^gYou can repair cloth items up to 40% condition.^n", B_FALSE); + addskilldesc(SK_SEWING, PR_BEGINNER, "^gYou can repair cloth items up to 60% condition.^n", B_FALSE); + addskilldesc(SK_SEWING, PR_ADEPT, "^gYou can repair cloth items up to 80% condition.^n", B_FALSE); addskilldesc(SK_SEWING, PR_SKILLED, "^gYou can re-size cloth armour (at the expense of durability).^n", B_FALSE); - addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can repair cloth items up to 85% condition^n", B_FALSE); - addskilldesc(SK_SEWING, PR_MASTER, "^gYou can fully repair cloth items.^n", B_FALSE); + addskilldesc(SK_SEWING, PR_EXPERT, "^gYou can fully repair cloth items.^n", B_FALSE); + addskilldesc(SK_SEWING, PR_MASTER, "^gYou can increase an item's quality to masterwork using a duplicate.^n", B_FALSE); + + + addskill(SK_SHIELDS, "Shields", "Reduces shield accuracy penalty, and raises chance to block attacks.", 50); addskilldesc(SK_SHIELDS, PR_INEPT, "- Without this skill, shield accuracy penalties are tripled.", B_FALSE); addskilldesc(SK_SHIELDS, PR_NOVICE, "^gShield accuracy penalties are reduced by 1.^n", B_FALSE); @@ -11149,6 +11253,7 @@ void initskills(void) { addskilldesc(sk->id, PR_INEPT, "This skill increases your accuracy and damage when using matching weapons.", B_FALSE); addskilldesc(sk->id, PR_NOVICE, "^g-2 accuracy penalty.^n", B_FALSE); addskilldesc(sk->id, PR_BEGINNER, "^g-1 accuracy penalty^n", B_FALSE); + addskilldesc(sk->id, PR_BEGINNER, "^gYou gain the 'wild strike' ability.^n", B_FALSE); addskilldesc(sk->id, PR_ADEPT, "^g+10% damage bonus.^n", B_FALSE); addskilldesc(sk->id, PR_ADEPT, "^gYou can now alter your attack style to deal different damage types.", B_FALSE); addskilldesc(sk->id, PR_SKILLED, "^g+2 accuracy, +20% damage bonus.^n", B_FALSE); diff --git a/data/hiscores.db b/data/hiscores.db index cc3aa58..d0b980d 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index 1903821..3174b35 100644 --- a/defs.h +++ b/defs.h @@ -58,6 +58,7 @@ #define WE_PORTAL 3 #define WE_NOTWALL 4 #define WE_NOLF 5 +#define WE_SOLID 6 // Booleans #define B_FALSE (0) @@ -427,7 +428,8 @@ enum NOISECLASS { NC_NONE = 0, NC_MOVEMENT = 1, NC_SPEECH = 2, - NC_OTHER = 3, + NC_FIGHTING = 3, + NC_OTHER = 4, }; enum QUADRANT { @@ -452,6 +454,7 @@ enum SAYPHRASE { SP_BEGTHANKS, SP_DIE, SP_DRUNK, + SP_MERCYACCEPT, SP_PAYWARN, SP_PAYTHREAT, SP_PAYTHANKS, @@ -894,6 +897,7 @@ enum RACE { R_PRIMALSTONEL, R_SATYR, R_SHADOWCAT, + R_SINKMITE, R_SPRITEFIRE, R_SPRITEGRAVE, R_SPRITEICE, @@ -974,6 +978,11 @@ enum RACE { // demons R_DRETCH, R_LURKINGHORROR, + R_NECRONTRAPPER, + R_NECRONREAPER, + R_NECRONSOWER, + R_NECRONEXTERMINATOR, + R_NECRONHARVESTER, R_QUASIT, // undead R_GHAST, @@ -1206,6 +1215,7 @@ enum OBTYPE { // scrolls OT_MAP, OT_GRAPHPAPER, + OT_SCR_AMNESIA, OT_SCR_AWARENESS, OT_SCR_NOTHING, OT_SCR_CREATEMONSTER, @@ -1246,6 +1256,7 @@ enum OBTYPE { OT_S_COMMANDUNDEAD, OT_S_DRAINLIFE, OT_S_FEAR, + OT_S_FLAYFLESH, OT_S_HECTASSERVANT, OT_S_PAIN, OT_S_PARALYZE, @@ -1440,6 +1451,7 @@ enum OBTYPE { OT_A_DISARM, // disarm a trap OT_A_DISARMLF, // disarm an opponent OT_A_DRAGUNDERGROUND, + OT_A_ENHANCEOB, OT_A_FEIGNDEATH, OT_A_FLIP, OT_A_FLURRY, @@ -1463,6 +1475,7 @@ enum OBTYPE { OT_A_SWOOP, OT_A_TRIPLF, // trip an opponent OT_A_EMPLOY, + OT_A_EXPOSEDSTRIKE, OT_A_HEAVYBLOW, OT_A_HIDE, OT_A_INSPECT, @@ -1708,6 +1721,7 @@ enum OBTYPE { // innate / animal weapons OT_BEAK, OT_CLAWS, + OT_DRILL, OT_FISTS, OT_HOOKHAND, // for pirate OT_STING, @@ -1951,7 +1965,7 @@ enum FLAG { F_ROOMEXIT, // there is an exit from room v0 at x=v1,y=v2 F_NEWWATERDEPTH, // temp flag for the spread of f_deepwater obs. // v0+1 are x/y, v2 is new depth. - F_STOMACHOF, // this map is the stomach of f->text + F_STOMACHOF, // this map is the stomach of lf id V0, name = f->text // object flags F_BADOBJECT, // this object is dangerous. ie. potion of poison, // potion of sleep, etc. @@ -2373,6 +2387,9 @@ enum FLAG { F_TOOKACTION, // lf purposely took action in their last turn. F_MOVED, // lf purposely walked/flew/swum/moved in prev turn F_HASBEENMOVED, // an object moved this lf since their last turn. + F_WASROBBED, // your stuff was stolen while you were + // unconscious. announce it when you wake up. + F_TURNED, // lf turned this turn. F_PRAYEDTO, // player has prayed to this god before. F_GAVEMONEY, // v0 tracks how much money we gave away this turn // used for r_godgreed anger effects. @@ -3473,6 +3490,7 @@ typedef struct lifeform_s { int x,y; int facing; // which way are we facing + int turncounter; // keeps track of # direction changes in a row int losdirty; int nlos; // cells which we can see diff --git a/doc/glyphs.txt b/doc/glyphs.txt index 383bb8d..ecc5ab0 100644 --- a/doc/glyphs.txt +++ b/doc/glyphs.txt @@ -25,6 +25,7 @@ j = jelly/ooze/leech k = kobold m = mutant n = small humanoid / nymph / sprite +N = necron o = orc O = ogre p = sPirit diff --git a/flag.c b/flag.c index 3714377..7fb07f6 100644 --- a/flag.c +++ b/flag.c @@ -884,6 +884,7 @@ void killflag(flag_t *f) { flag_t *nextone, *lastone; flagpile_t *pile; lifeform_t *lf; + enum FLAG fid; map_t *redolight = NULL; cell_t *redolos = NULL; int redostat = B_FALSE; @@ -892,6 +893,8 @@ void killflag(flag_t *f) { //checkflagpile(f->pile); + fid = f->id; + for (i = 0; i < ngodlfs; i++) { dopleasegod[i] = 0; } diff --git a/god.c b/god.c index ea0feee..f2955dc 100644 --- a/god.c +++ b/god.c @@ -876,11 +876,12 @@ int prayto(lifeform_t *lf, lifeform_t *god) { msg("\"Behold, the power of death!\""); c = NULL; n = OT_NONE; - switch (rnd(0,3)) { + switch (rnd(0,4)) { case 0: n = OT_S_PAIN; break; case 1: n = OT_S_DRAINLIFE; break; case 2: n = OT_S_BLINDNESS; break; - case 3: n = OT_S_HECTASSERVANT; + case 3: n = OT_S_FLAYFLESH; break; + case 4: n = OT_S_HECTASSERVANT; c = getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND); break; } diff --git a/io.c b/io.c index 8f3f6b3..52fb158 100644 --- a/io.c +++ b/io.c @@ -1793,11 +1793,13 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { } } donesomething = B_TRUE; + needredraw = B_TRUE; } break; case F_XRAYVIS: if (isplayer(lf)) { // don't know if monsters get it msg("The walls around you suddenly turn transparent!"); + needredraw = B_TRUE; donesomething = B_TRUE; } break; @@ -1807,7 +1809,8 @@ int announceflaggain(lifeform_t *lf, flag_t *f) { if (donesomething) statdirty = B_TRUE; - if (statdirty || needredraw) { + //if (statdirty || needredraw) { + if (statdirty) { drawscreen(); } @@ -3697,6 +3700,10 @@ void docomms(lifeform_t *lf) { } else { addchoice(&prompt, 'j', "Join me on my quest!", NULL, NULL, NULL); } + } + + if (areenemies(player, lf)) { + addchoice(&prompt, 'm', "Have mercy!", NULL, NULL, NULL); } // if you are allies, use 'trade items' instead @@ -3714,6 +3721,8 @@ void docomms(lifeform_t *lf) { addchoice(&prompt, 'p', buf, NULL, NULL, NULL); } } + + addchoice(&prompt, 'y', "Yeeeeeaaaargh!", NULL, NULL, NULL); addchoice(&prompt, 'n', "(nothing)", NULL, NULL, NULL); @@ -3935,6 +3944,33 @@ void docomms(lifeform_t *lf) { } recruit(lf); break; + case 'm': // mercy + msg("You say \"Have mercy!\" to %s.", lfname); + if (islowhp(player) && + cantalk(lf) && + canhear(lf, player->cell, SV_SHOUT) && + (getattrbracket(getattr(lf, A_IQ), A_IQ, NULL) > IQ_ANIMAL) && + !isundead(lf)) { + if (skillcheck(player, SC_SPEECH, 30, 0)) { + // passed! + sayphrase(lf, SP_MERCYACCEPT, SV_TALK, NA, player->race->name); + // they knock you out + msg("^%d*WHACK*^n", C_YELLOW); + fallasleep(player, ST_KO, rnd(50,100)); + // they take all your stuff + /* + for (o = player->pack->first ; o ; o = nexto) { + nexto = o->next; + if (canpickup(lf, o, ALL)) { + pickup(lf, o, ALL, B_FALSE, B_FALSE); + } + } + */ + // they stop attacking you + loseaitargets(lf); + } + } + break; case 'p': // can we afford this? if (givemoney(player, lf, moneyowing)) { @@ -9120,7 +9156,7 @@ void drawstatus(void) { unsetcol(statwin, C_CYAN); } else if ((f = lfhasflag(player, F_ASLEEP)) != NULL) { setcol(statwin, C_MAGENTA); - if (f->val[2] == ST_KO) { + if (f->val[1] == ST_KO) { wprintw(statwin, " KO"); } else { wprintw(statwin, " Asleep"); diff --git a/lf.c b/lf.c index 6247bd7..ecb3363 100644 --- a/lf.c +++ b/lf.c @@ -1614,7 +1614,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar } } else { // player can't see them if ((targlf == player) || (targcell == player->cell)) { - if (!lfhasflag(player, F_ASLEEP)) { + if (!lfhasflag(player, F_ASLEEP) && !lfhasflag(lf, F_SPELLCASTTEXT)) { msg("Something casts a spell at you."); } } @@ -2104,6 +2104,7 @@ void debug(lifeform_t *lf) { // returns true if the player pays. int demandbribe(lifeform_t *lf) { + lifeform_t *l; char lfname[BUFLEN]; int amtwanted,amtgiven,totmoney; int hd; @@ -2189,8 +2190,12 @@ int demandbribe(lifeform_t *lf) { } } - // either way, kill bribe flag - killflagsofid(lf->flags, F_DEMANDSBRIBE); + // either way, kill bribe flag for all bandits on the level + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (!isplayer(l) && (l->race->baseid == lf->race->baseid)) { + killflagsofid(l->flags, F_DEMANDSBRIBE); + } + } return satisfied; } @@ -2337,8 +2342,10 @@ void die(lifeform_t *lf) { if (ispetof(lf, player)) { if (cantalk(lf) && canhear(player, lf->cell, 4)) { sayphrase(lf, SP_DIE, SV_SHOUT, NA, NULL); - } else if (cantalk(lf)) { + } else if (!cansee(player, lf)) { warn("You feel a profound sense of loss."); + // redraw since you can "see" the pet even if it's out of sight + needredraw = B_TRUE; more(); //} else { // makenoise(lf, N_DIE); @@ -8568,6 +8575,12 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL); newf->lifetime = FROMSKILL; } + } else if (f->val[1] == PR_MASTER) { + newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); + if (!newf) { + newf = addflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); + newf->lifetime = FROMSKILL; + } } } else if (id == SK_PERCEPTION) { if ((f->val[1] == PR_ADEPT) || (f->val[1] == PR_MASTER)) { @@ -8582,6 +8595,12 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { newf = addflag(lf->flags, F_CANWILL, OT_A_RESIZE, NA, NA, NULL); newf->lifetime = FROMSKILL; } + } else if (f->val[1] == PR_MASTER) { + newf = hasflagval(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); + if (!newf) { + newf = addflag(lf->flags, F_CANWILL, OT_A_ENHANCEOB, NA, NA, NULL); + newf->lifetime = FROMSKILL; + } } } else if (id == SK_SHIELDS) { if (f->val[1] == PR_BEGINNER) { @@ -8637,7 +8656,12 @@ flag_t *giveskill(lifeform_t *lf, enum SKILL id) { } if (isweaponskill(id)) { - if (f->val[1] == PR_ADEPT) { + if (f->val[1] == PR_BEGINNER) { + if (!hasflagval(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL)) { + newf = addflag(lf->flags, F_CANWILL, OT_A_EXPOSEDSTRIKE, NA, NA, NULL); + newf->lifetime = FROMSKILL; + } + } else if (f->val[1] == PR_ADEPT) { if (!hasflagval(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL)) { newf = addflag(lf->flags, F_CANWILL, OT_A_ALTERATTACK, NA, NA, NULL); newf->lifetime = FROMSKILL; @@ -10064,6 +10088,10 @@ int isaquatic(lifeform_t *lf) { return B_FALSE; } +flag_t *isasleep(lifeform_t *lf) { + return lfhasflagval(lf, F_ASLEEP, NA, ST_ASLEEP, NA, NULL); +} + // is lf behind otherlf? int isbehind(lifeform_t *lf, lifeform_t *otherlf) { int dir; @@ -10583,7 +10611,6 @@ flag_t *isresting(lifeform_t *lf) { return NULL; } - int issleepingtimefor(lifeform_t *lf) { if (lfhasflag(lf, F_NOCTURNAL) && !isnighttime()) { return B_TRUE; @@ -10718,6 +10745,7 @@ lifeform_t *real_addlf(cell_t *cell, enum RACE rid, int level, int controller) { // for precalcing line of sight a->facing = rnd(DC_N, DC_NW); + a->turncounter = 0; a->losdirty = B_TRUE; //a->los = malloc( sizeof(cell_t *) * ((MAXVISRANGE*2+1)*(MAXVISRANGE*2+1))); a->los = NULL; // will be alloced in precalclos @@ -12761,10 +12789,16 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, dist = getcelldist(l->cell, c); + + // listen check difficulty is based on sound distance vs max hearing distance if ((nclass == NC_SPEECH) && isplayer(l)) { // you always hear it, as long as you're in range difficulty = 0; + } else if ((nclass == NC_FIGHTING) && isplayer(l) && (dist <= 1)) { + // players never hear fighting unless it's a small distance away + // this prevents "you hear fighting" when you are attacked from behind. + difficulty = 9999; } else { //difficulty = (int) ( ((float)getcelldist(l->cell, c) / (float)gethearingrange(l)) * 20); difficulty = (int) ( ((float)getcelldist(l->cell, c) / ((float)gethearingrange(l) + volume)) * 14); @@ -12949,12 +12983,15 @@ int noise(cell_t *c, lifeform_t *noisemaker, enum NOISECLASS nclass, int volume, if (willrespond) { // turn to face the sound - if (isplayer(noisemaker) && cansee(player, l) && cansee(l, player) && !lfhasflag(l, F_AWARENESS)) { + if (isplayer(noisemaker) && cansee(l, player) && !lfhasflag(l, F_AWARENESS)) { // peaceful things only turn sometimes if (!ispeaceful(l) || onein(6)) { char lfname[BUFLEN]; + int prefacing; + prefacing = l->facing; turntoface(l, c); - if (!lfhasflag(l, F_FEIGNINGDEATH)) { + if (!lfhasflag(l, F_FEIGNINGDEATH) && cansee(player, l) && + (prefacing != l->facing)) { getlfname(l, lfname); msg("%s turns to face you.", lfname); } @@ -13276,8 +13313,10 @@ void precalclos_new(lifeform_t *lf) { //int db = B_FALSE; enum SKILLLEVEL plev = PR_INEPT; flag_t *missingeye; + long visdiameter; long allocamt; + if (gamemode == GM_CLEANUP) return; if (lf->cell->type->id == CT_FAKE) return; @@ -13305,7 +13344,9 @@ void precalclos_new(lifeform_t *lf) { startxray = 0; } - allocamt = ((MAXVISRANGE*2)+1) * ((MAXVISRANGE*2)+1); + // ie. you can see both ways, plus your own cell + visdiameter = (MAXVISRANGE+1)*2; + allocamt = visdiameter * visdiameter; los = malloc( sizeof(cell_t *) * allocamt); losdark = malloc( sizeof(cell_t *) * allocamt); blocker = malloc( sizeof(cell_t *) * allocamt); @@ -13974,6 +14015,7 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t char buf[BUFLEN]; char buf2[BUFLEN]; char *p; + race_t *r; switch (what) { case SP_ALLY_ATTACK: switch (rnd(1,3)) { @@ -14075,6 +14117,18 @@ int sayphrase(lifeform_t *lf, enum SAYPHRASE what, int volume, int val0, char *t } say(lf, buf, volume); break; + case SP_MERCYACCEPT: + switch (rnd(1,2)) { + case 1: + r = findrace(val0); + snprintf(buf, BUFLEN, "Cowardly %s...", text); + break; + case 2: + snprintf(buf, BUFLEN, "Guess I don't need to actually kill you..."); + break; + } + rv = say(lf, buf, volume); + break; case SP_PAYWARN: switch (rnd(1,3)) { case 1: snprintf(buf, BUFLEN, "Hey! Where do you think you're going?"); break; @@ -15201,7 +15255,7 @@ void startlfturn(lifeform_t *lf) { enum ERROR error; object_t *o; flag_t *f; - flag_t *asp; + flag_t *asp, *sf; char buf[BUFLEN]; lifeform_t *l; int i; @@ -15214,6 +15268,50 @@ void startlfturn(lifeform_t *lf) { if (db) dblog("startlfturn for lf id %d %s", lf->id, lf->race->name); + // MOVE OUT OF STOMACHS WHICH DONT EXIST ANYMORE + sf = hasflag(map->flags, F_STOMACHOF); + if (sf) { + lifeform_t *stomachlf; + stomachlf = findlf(NULL, sf->val[0]); + if (!stomachlf || isdead(stomachlf)) { + object_t *exit; + cell_t *exitcell,*c; + map_t *exitmap; + + exitcell = findobinmap(map, OT_STOMACHEXIT); + exit = hasob(exitcell->obpile, OT_STOMACHEXIT); + f = hasflag(exit->flags, F_MAPLINK); + exitmap = findmap(f->val[0]); + c = getcellat(exitmap, f->val[1], f->val[2]); + while (!cellwalkable(lf, c, NULL)) { + c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); + } + // move lf out! + movelf(lf, c); + if (isplayer(lf)) { + msg("You get expelled from %s!", sf->text); + } else if (cansee(player, lf)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("%s gets expelled from %s!", lfname, sf->text); + } + } + } + + + if (!isdead(lf) && !isunconscious(lf) && hasflag(lf->flags, F_WASROBBED)) { + if (isplayer(lf)) { + if (countobs(lf->pack, B_FALSE)) { + msg("Some of your items are missing!"); + } else { + msg("All of your items are missing!"); + } + } else { + say(lf, "Hey! Where are my things?", SV_SHOUT); + } + killflagsofid(lf->flags, F_WASROBBED); + } + if (isplayer(lf) && lfhasflag(lf, F_DRUNK)) statdirty = B_TRUE; // clear one-turn-only flags @@ -15222,6 +15320,10 @@ void startlfturn(lifeform_t *lf) { killflagsofid(lf->flags, F_HASBEENMOVED); killflagsofid(lf->flags, F_MOVED); + // if we didn't turn lsat move, kill our turncounter + if (!killflagsofid(lf->flags, F_TURNED)) { + lf->turncounter = 0; + } // update where player knows // (but without a map you will then slowly forget it) @@ -17218,10 +17320,12 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { // take fall damage. 2d6 per level. losehp(lf, rolldie(howfar*2, 6), DT_FALL, NULL, "falling"); killflagsofid(lf->flags, F_FALLDISTANCE); - // injure legs - injure(lf, BP_LEGS, DT_BASH); - // fall over - fall(lf, NULL, B_FALSE); + if (!isimmuneto(lf->flags, DT_FALL, B_FALSE)) { + // injure legs + injure(lf, BP_LEGS, DT_BASH); + // fall over + fall(lf, NULL, B_FALSE); + } } } else if (dir == D_UP) { if (hasobwithflagval(lf->cell->obpile, F_PIT, D_UP, NA, NA, NULL)) { diff --git a/lf.h b/lf.h index 9c34e36..d7a871a 100644 --- a/lf.h +++ b/lf.h @@ -275,6 +275,7 @@ int haslos_fast(lifeform_t *viewer, cell_t *dest); void interrupt(lifeform_t *lf); enum FLAG isairborne(lifeform_t *lf); int isaquatic(lifeform_t *lf); +flag_t *isasleep(lifeform_t *lf); int isbehind(lifeform_t *lf, lifeform_t *otherlf); int isbleeding(lifeform_t *lf); int isblind(lifeform_t *lf); @@ -417,6 +418,7 @@ int useability(lifeform_t *lf, enum OBTYPE aid, lifeform_t *who, cell_t *where); int useringofmiracles(lifeform_t *lf, int charges); int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb); int validateraces(void); +void wakeup(lifeform_t *lf, int howmuch); int wear(lifeform_t *lf, object_t *o); int weild(lifeform_t *lf, object_t *o); int willbleedfrom(lifeform_t *lf, enum BODYPART bp); diff --git a/map.c b/map.c index 761eb67..3b074f0 100644 --- a/map.c +++ b/map.c @@ -4935,6 +4935,8 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO } } else if (wantempty == WE_NOLF) { if (!new->lf) ok = B_TRUE; + } else if (wantempty == WE_SOLID) { + if (new->type->solid) ok = B_TRUE; } else { // always ok ok = B_TRUE; diff --git a/move.c b/move.c index 0d4e6c3..e4eec51 100644 --- a/move.c +++ b/move.c @@ -2533,6 +2533,14 @@ int trymove(lifeform_t *lf, int dir, int onpurpose, int strafe) { // if the given dir is behind us, just turn. if (!strafe) { setfacing(lf, dir); + if (isplayer(lf)) { + addflagifneeded(lf->flags, F_TURNED, B_TRUE, NA, NA, NULL); + lf->turncounter++; + if (lf->turncounter >= 5) { + // get dizzy for 2 turns + addtempflag(lf->flags, F_CONFUSED, B_TRUE, NA, NA, NULL, 3); + } + } taketime(lf, getturnspeed(lf)); return B_FALSE; } else { @@ -3182,6 +3190,7 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { } // don't attack other monsters + // or non-enemies if (cell->lf) { // if someone is in the way object_t *defenderwep = NULL; if (lf->race->raceclass->id == RC_INSECT) { @@ -3200,8 +3209,8 @@ int willmove(lifeform_t *lf, int dir, enum ERROR *error) { } if (!isplayer(lf)) { // if we are a monster - // if the person in the way isn't our enemy... - if (!areenemies(lf, cell->lf)) { + // if the person in the way isn't our enemy, or is KO'd/dead... + if (!areenemies(lf, cell->lf) || isdead(cell->lf) || isunconscious(cell->lf)) { // if they are an ally... if (canswapwith(lf, cell->lf)) { return B_TRUE; diff --git a/nexus.c b/nexus.c index 5463639..c0619f3 100644 --- a/nexus.c +++ b/nexus.c @@ -647,7 +647,7 @@ void checkendgame(void) { } void cleanup(void) { - int i; + //int i; gamemode = GM_CLEANUP; free(xpposs); @@ -676,11 +676,14 @@ void cleanup(void) { while (firstrace) killrace(firstrace); // free celltypes while (firstcelltype) killcelltype(firstcelltype); + /* for (i = 0; i < numnpcnames; i++) { // free npcnames free(npcname[i].name); free(&npcname[i]); } + */ + free(npcname); // free hidden names while (firsthiddenname) killhiddenname(firsthiddenname); //WriteMemLeak(); diff --git a/objects.c b/objects.c index 301bd59..285ad5b 100644 --- a/objects.c +++ b/objects.c @@ -7323,6 +7323,7 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { int i,preburdened = B_FALSE; int db = B_FALSE; int redrawaftermove = B_FALSE; + lifeform_t *robbedlf = NULL; flag_t *f; reason = E_OK; @@ -7332,6 +7333,12 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { return NULL; } + + // object being taken from an unconscious lf? + if (src->pile->owner && isunconscious(src->pile->owner)) { + robbedlf = src->pile->owner; + } + // adjust destination for pits if (dst->where) { object_t *pit; @@ -7437,6 +7444,10 @@ object_t *real_moveob(object_t *src, obpile_t *dst, int howmany, int stackok) { o->blessknown = B_TRUE; } + if (robbedlf && !lfhasflag(robbedlf, F_WASROBBED)) { + addflag(robbedlf->flags, F_WASROBBED, B_TRUE, NA, NA, NULL); + } + if (hasflag(o->flags, F_DOOR)) { killflagsofid(o->flags, F_LOCKED); killflagsofid(o->flags, F_JAMMED); @@ -10126,6 +10137,15 @@ int readsomething(lifeform_t *lf, object_t *o) { if (isplayer(lf)) msg("The scroll crumbles to dust."); // removeob one of the object removeob(o, 1); + } else if (o->type->id == OT_SCR_AMNESIA) { + // lose all skill points + lf->skillpoints = 0; + lf->skillxp = 0; + if (isplayer(lf)) msg("^%dYou can't seem to remember any of your recent experiences!", C_RED); + if (isplayer(lf)) msg("The scroll crumbles to dust."); + // removeob one of the object + removeob(o, 1); + if (isplayer(lf)) statdirty = B_TRUE; } else if (o->type->id == OT_SCR_NOTHING) { if (isplayer(lf)) { msg("The scroll crumbles to dust."); diff --git a/save.c b/save.c index 1210d42..48487f5 100644 --- a/save.c +++ b/save.c @@ -234,6 +234,8 @@ lifeform_t *loadlf(FILE *f, cell_t *where) { fscanf(f, "polyrevert: %d\n",&l->polyrevert); fscanf(f, "forgettimer: %f\n",&l->forgettimer); fscanf(f, "eyeadj: %d\n",&l->eyeadjustment); + fscanf(f, "facing: %d\n",&l->facing); + fscanf(f, "turncounter: %d\n",&l->turncounter); if (db) dblog("--> Got hp=%d/%d. timespend=%d. sorted=%d. Now loading flags.",l->hp,l->maxhp,l->timespent,l->sorted); @@ -827,6 +829,8 @@ int savelf(FILE *f, lifeform_t *l) { fprintf(f, "polyrevert: %d\n",l->polyrevert); fprintf(f, "forgettimer: %f\n",l->forgettimer); fprintf(f, "eyeadj: %d\n",l->eyeadjustment); + fprintf(f, "facing: %d\n",l->facing); + fprintf(f, "turncounter: %d\n",l->turncounter); // lf flags saveflagpile(f, l->flags); diff --git a/spell.c b/spell.c index 6e85cae..8e4c6cc 100644 --- a/spell.c +++ b/spell.c @@ -2041,7 +2041,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // create stomach map newmap = addmap(); createmap(newmap, 1, r, targcell->map, D_NONE, NULL); - addflag(newmap->flags, F_STOMACHOF, NA, NA, NA, username); + addflag(newmap->flags, F_STOMACHOF, user->id, NA, NA, username); } // find a random empty cell here @@ -2652,7 +2652,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef msg("You need to weild a weapon first!"); return B_TRUE; } - if (slev < PR_SKILLED) { + if (slev < PR_ADEPT) { msg("You are not skilled enough with your weapon to do this!"); return B_TRUE; } @@ -2833,6 +2833,131 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef } } + } else if (abilid == OT_A_ENHANCEOB) { + object_t *o,*o2; + enum MATERIAL repairablemats[MAXCANDIDATES]; + int cutoffpct[MAXCANDIDATES]; + int i,nmats = 0; + char ch,obname[BUFLEN]; + + if (!isplayer(user)) { + return B_TRUE; + } + + // get list of resizable materials + getworkablematerials(user, SK_METALWORK, repairablemats, cutoffpct, &nmats); + getworkablematerials(user, SK_SEWING, repairablemats, cutoffpct, &nmats); + + // 1.compile a list of enhancable objects + initprompt(&prompt, "Enhance which object?"); + addchoice(&prompt, '-', "Cancel", "Cancel", NULL, NULL); + for (o = user->pack->first ; o ; o = o->next) { + int ok = B_FALSE; + for (i = 0; i < nmats; i++) { + if (o->material->id == repairablemats[i]) { + ok = B_TRUE; + break; + } + } + if (ok && (isweapon(o) || isarmour(o)) && !hasflag(o->flags, F_NOQUALITY) && + !hasflag(o->flags, F_MASTERWORK)) { + int gotdupe = B_FALSE; + // do we have another? + for (o2 = user->pack->first ; o2 ; o2 = o2->next) { + if ((o2 != o) && (o2->type->id == o->type->id)) { + gotdupe = B_TRUE; + break; + } + } + if (gotdupe) { + // we can enhance this object + getobname(o, obname, o->amt); + addchoice(&prompt, o->letter, obname, NULL, o, NULL); + } + } + } + + if (prompt.nchoices <= 1) { + msg("You don't have anything which you are able to enhance."); + return B_TRUE; + } + + // 2. ask which ones to enhance + getchoice(&prompt); + o = (object_t *) prompt.result; + getobname(o, obname, 1); + + // ask what size we want. + sprintf(buf, "Destroy which object to enahnce %s?", obname); + initprompt(&prompt, buf); + for (o2 = user->pack->first ; o2 ; o2 = o2->next) { + if ((o2 != o) && (o2->type->id == o->type->id)) { + getobname(o2, obname, o2->amt); + addchoice(&prompt, o2->letter, obname, NULL, o2, NULL); + } + } + addchoice(&prompt, '-', "Cancel", "Cancel", NULL, NULL); + prompt.maycancel = B_TRUE; + + ch = getchoice(&prompt); + if ((ch == '-') || (ch == '\0')) { + msg("Cancelled."); + return B_TRUE; + } + + o2 = (object_t *)prompt.result; + + // in case it's on fire, etc + if (touch(user, o)) { + taketime(user, getactspeed(user)); + return B_FALSE; + } + if (touch(user, o2)) { + taketime(user, getactspeed(user)); + return B_FALSE; + } + + // destroy second ob + removeob(o2, ALL); + // fully repair first ob + f = hasflag(o->flags, F_OBHP); + if (f) f->val[0] = f->val[1]; + // enhance first ob + addflag(o->flags, F_MASTERWORK, B_TRUE, NA, NA, NULL); + + getobname(o, obname, o->amt); + msgnocap("%c - %s", o->letter, obname); + + taketime(user, getactspeed(user)); + } else if (abilid == OT_A_EXPOSEDSTRIKE) { + flag_t *f; + if (getweaponskill(user, getweapon(user)) < PR_BEGINNER) { + if (isplayer(user)) msg("You are not skilled enough to perform an exposed strike.", HEAVYWEPKG); + return B_TRUE; + } + // ask for direction + if (!targcell) { + char dirch; + dirch = askchar("Exposed strike in which direction (- to cancel)", "yuhjklbn.-","-", B_FALSE, B_TRUE); + if (dirch == '.') { + // yourself! + targcell = user->cell; + } else { + int dir; + dir = chartodir(dirch); + if (dir == D_NONE) { + if (isplayer(user)) msg("Cancelled."); + return B_TRUE ; + } else { + targcell = getcellindir(user->cell, dir); + } + } + } + + f = addflag(user->flags, F_ACCURACYMOD, 100, NA, NA, NULL); + attackcell(user, targcell, B_FALSE); + taketime(user, getattackspeed(user)*2); + killflag(f); } else if (abilid == OT_A_HEAVYBLOW) { object_t *wep; char dirch; @@ -3044,6 +3169,7 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef int dir; cell_t *c; flag_t *f,*f2,*f3; + object_t *wep; if (isswimming(user) && !lfhasflag(user, F_AQUATIC)) { if (isplayer(user)) msg("You cannot do that while swimming."); @@ -3061,6 +3187,24 @@ int abilityeffects(lifeform_t *user, enum OBTYPE abilid, cell_t *targcell, lifef // remember we are doing a hurricane attack to avoid lots of // "there is nothing to attack there" messages. f3 = addflag(user->flags, F_HURRICANESTRIKE, B_TRUE, NA, NA, NULL); + + wep = getweapon(user); + if (wep) { + char buf[BUFLEN],wepname[BUFLEN]; + getobname(wep, buf, 1); + sprintf(wepname, "%s", noprefix(buf)); + if (isplayer(user)) { + msg("You swing your %s in a wide arc!", wepname); + } else if (cansee(player, user)) { + msg("%s swings its %s in a wide arc!", username, wepname); + } + } else { + if (isplayer(user)) { + msg("You attack in a wide arc!"); + } else if (cansee(player, user)) { + msg("%s attacks in a wide arc!", username); + } + } // attack all adjacent enemies for (dir = DC_N; dir <= DC_NW; dir++) { c = getcellindir(user->cell, dir); @@ -4795,7 +4939,11 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ int dir; if (targcell) { - dir = getdirtowards(caster->cell, targcell, NULL, B_FALSE, DT_COMPASS); + if (targcell == caster->cell) { + dir = D_DOWN; + } else { + dir = getdirtowards(caster->cell, targcell, NULL, B_FALSE, DT_COMPASS); + } } else { // don't need line of fire OR sight! //if (!validatespellcell(caster, &targcell, TT_NONE, spellid, power, frompot)) return B_TRUE; @@ -4805,15 +4953,21 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ return B_TRUE; } else if (ch == '<') { if (seenbyplayer && haslos(player, caster->cell)) *seenbyplayer = B_TRUE; - return digup(caster, NULL); + dir = D_UP; } else if (ch == '>') { if (seenbyplayer && haslos(player, caster->cell)) *seenbyplayer = B_TRUE; - return digdown(caster, NULL); + dir = D_DOWN; } else { dir = chartodir(ch); } } + if (dir == D_UP) { + return digup(caster, NULL); + } else if (dir == D_DOWN) { + return digdown(caster, NULL); + } + if (dir == DT_NONE) { fizzle(caster); return B_TRUE; @@ -4830,12 +4984,38 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (c->type->solid) { if ((c->type->material->id == MT_STONE) || (c->type->material->id == MT_FLESH)) { - setcelltype(c, c->map->habitat->emptycelltype); - ndigs++; + int d2; if (seenthiscell) { + msg("%s %s collapses!", needan(c->type->name) ? "An" : "A", + c->type->name); numseen++; if (seenbyplayer) *seenbyplayer = B_TRUE; } + setcelltype(c, c->map->habitat->emptycelltype); + ndigs++; + if (c->type->material->id == MT_STONE) { + // debris shower + for (d2 = DC_N; d2 <= DC_NW; d2++) { + cell_t *c2; + c2 = getcellindir(c, d2); + if (c2 && !c2->type->solid && c2->lf) { + if (!isimmuneto(c2->lf->flags, DT_PROJECTILE, B_FALSE)) { + if (cansee(player, c2->lf)) { + char lfname[BUFLEN]; + getlfname(c2->lf, lfname); + msg("%s %s showed with debris!", lfname, isplayer(c2->lf) ? "are" : "is"); + } + losehp(c2->lf, rnd(2,6), DT_PROJECTILE, NULL, "flying debris"); + } + } + } + addobsinradius(c, 1, DT_COMPASS, "5-10 stones", B_TRUE); + addob(c->obpile, "5-10 stones"); + } else if (c->type->material->id == MT_BLOOD) { + addobsinradius(c, 1, DT_COMPASS, "pool of blood", B_TRUE); + addob(c->obpile, "pool of blood"); + } + } else { // stop. break; @@ -4863,7 +5043,9 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ c = getcellindir(c, dir); } + // announce destruction of any walls seen + /* if (numseen) { msg("The wall%s crumble%s to dust!", (numseen == 1) ? "" : "s", @@ -4873,6 +5055,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } else if (ndigs == 0) { if (isplayer(caster)) nothinghappens(); } + */ + if (ndigs == 0) { + if (isplayer(caster)) nothinghappens(); + } } else if (spellid == OT_S_DISORIENT) { target = targcell->lf; @@ -5315,6 +5501,27 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (seenbyplayer) *seenbyplayer = B_TRUE; } brightflash(caster->cell, 2 + (power/4), caster); + } else if (spellid == OT_S_FLAYFLESH) { + char targetname[BUFLEN]; + target = targcell->lf; + if (!target) { + fizzle(caster); + return B_TRUE; + } + if (target->race->material->id != MT_FLESH) { + fizzle(caster); + return B_TRUE; + } + if (isplayer(target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + msg("Unseen forces rip into your flesh!"); + } else if (cansee(player, target)) { + if (seenbyplayer) *seenbyplayer = B_TRUE; + getlfname(target, targetname); + msg("Unseen forces rip into %s%s flesh!", targetname, getpossessive(targetname)); + } + criticalhit(caster, target, getrandomcorebp(target), rnd(1,6), DT_SLASH); + pleasegodmaybe(R_GODDEATH, 3); } else if (spellid == OT_S_GLYPHWARDING) { char buf[BUFLEN]; sprintf(buf, "^g*WARD%d*^n", power/2); @@ -7912,6 +8119,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ race_t *r = NULL; target = targcell->lf; + if (frompot) { + caster = target; + } + if (!target) { fizzle(caster); return B_TRUE; @@ -8050,12 +8261,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ f = hasflag(o->flags, F_OBHP); if (f) { f->val[0] = f->val[1]; - f = hasflagval(o->flags, F_OBHPDRAIN, NA, DT_DECAY, NA, NULL); - if (f) { - killflag(f); - } - + if (f) killflag(f); donesomething = B_TRUE; } @@ -9296,8 +9503,8 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = caster; } // works on all undead in _target's_ sight - for (i = 0; i < caster->nlos; i++) { - targcell = caster->los[i]; + for (i = 0; i < target->nlos; i++) { + targcell = target->los[i]; lf = targcell->lf; if (lf && (lf != caster) && isundead(lf)) { int howlong = 10; @@ -9305,7 +9512,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // TODO: does it work? depends on caster level & intelligence & power worked = B_TRUE; // TODO: how long for? depends on caster level & intelligence & power - howlong = rnd(10,20); + howlong = rnd(10,20)+(power*2); if (worked) { // don't use scare() since it will fail due to them being undead. addtempflag(lf->flags, F_FLEEFROM, target->id, NA, NA, NULL,howlong); @@ -10765,11 +10972,11 @@ int getworkablematerials(lifeform_t *lf, enum SKILL skid , enum MATERIAL *repair slev = getskill(lf, skid); switch (slev) { - case PR_NOVICE: cutoff = 33; break; - case PR_BEGINNER: cutoff = 50; break; - case PR_ADEPT: cutoff = 60; break; - case PR_SKILLED: cutoff = 70; break; - case PR_EXPERT: cutoff = 85; break; + case PR_NOVICE: cutoff = 40; break; + case PR_BEGINNER: cutoff = 60; break; + case PR_ADEPT: cutoff = 80; break; + case PR_SKILLED: cutoff = 80; break; + case PR_EXPERT: cutoff = 100; break; case PR_MASTER: cutoff = 100; break; default: cutoff = 0; break; }