diff --git a/ai.c b/ai.c index e83fe35..66874ed 100644 --- a/ai.c +++ b/ai.c @@ -586,7 +586,6 @@ int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim break; } } - // aim at an adjacent wall cell if (spellcell) *spellcell = poss[rnd(0,nposs-1)]; } else if (spelltype->id == OT_S_PLANTWALK) { diff --git a/attack.c b/attack.c index ab8fd7c..b63936e 100644 --- a/attack.c +++ b/attack.c @@ -1197,7 +1197,9 @@ int attacklf(lifeform_t *lf, lifeform_t *victim, object_t *wep, flag_t *damflag) addflag(victim->flags, F_BEHEADED, B_TRUE, NA, NA, NULL); addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); } else if (strstr(buf, "bisect")) { - addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); + if (victim->race->id != R_EARTHWYRM) { + addflag(victim->flags, F_MUTILATED, B_TRUE, NA, NA, NULL); + } } if ((isplayer(lf) || cansee(player, victim)) && !hasflag(victim->flags, F_NODEATHANNOUNCE)) { if (!hasflag(victim->flags, F_PHANTASM)) { diff --git a/data.c b/data.c index 1b04f7e..a8db2b3 100644 --- a/data.c +++ b/data.c @@ -1390,9 +1390,11 @@ void initobjects(void) { addocnoun(lastobjectclass, "furniture"); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_RARITY, H_CAVE, RR_RARE, NA, NULL); // override for habitat + addflag(lastobjectclass->flags, F_RARITY, H_ANTNEST, RR_NEVER, NA, NULL); // override for habitat addoc(OC_TERRAIN, "Terrain", "Water, etc.", '\\', C_GREY, RR_NEVER); addoc(OC_TRAP, "Trap", "Fiendish traps.", '^', C_GREY, RR_RARE); addocnoun(lastobjectclass, "trap"); + addflag(lastobjectclass->flags, F_RARITY, H_ANTNEST, RR_NEVER, NA, NULL); // override for habitat addoc(OC_MONEY, "Money", "The standard currency of Nexus.", '$', C_GREY, RR_UNCOMMON); addoc(OC_SCROLL, "Scrolls", "An arcane roll of parchment, inscribed with many magical glyphs.", '?', C_GREY, RR_COMMON); addocnoun(lastobjectclass, "scroll"); @@ -2166,6 +2168,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 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); @@ -2175,6 +2178,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 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); @@ -2184,6 +2188,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); 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); @@ -2193,6 +2198,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); 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); @@ -2202,6 +2208,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 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); @@ -2211,6 +2218,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 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); @@ -2220,6 +2228,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 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); @@ -2229,6 +2238,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_VERYRARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); 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); @@ -2238,6 +2248,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_STOMACH, 100, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_VALUE, 60, NA, NA, NULL); @@ -2424,15 +2435,19 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 40, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addot(OT_BANANA, "banana", "Ba-na-na-na-na-na na-na na-na-na.", MT_FOOD, 0.3, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_YELLOW, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 50, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, ""); addot(OT_BANANASKIN, "banana skin", "A slippery banana skin.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_YELLOW, '%', NA, NULL); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 70, NA, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, NA, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_SLIPPERY, 15, NA, NA, NULL); addflag(lastot->flags, F_SLIPMOVE, 15, NA, NA, NULL); addot(OT_BERRY, "berry", "Juicy, brightly coloured berries.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); @@ -2441,11 +2456,13 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 15, NA, ""); addot(OT_BREADFRESH, "loaf of fresh bread", "A freshly-baked loaf of bread.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 200, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); addot(OT_BREADGARLIC, "loaf of garlic bread", "A pungent loaf of garlic bread. Nauseates those around you and restores some health.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); @@ -2459,10 +2476,12 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_CHOCOLATE, "block of chocolate", "An entire block of chocolate.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 250, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_CLOVER, "four leafed clover", "A rare 4-leafed clover.", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_GREEN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); @@ -2481,6 +2500,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "some bread"); addot(OT_CACFRUIT, "cactus fruit", "The nutritous fruit from a cactus plant.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_RED, '%', NA, NULL); @@ -2491,12 +2511,14 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 85, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_GARLIC, "clove of garlic", "A very pungent clove of raw garlic. ", MT_FOOD, 0.1, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 5, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addot(OT_HOTDOG, "hot dog", "A chunk of meat sandwiched between two pieces of bread. Temporarily increases strength, and provides some healing.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_RED, '%', NA, NULL); @@ -2512,6 +2534,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_RARITY, H_SWAMP, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "mushroom"); addot(OT_MUSHROOMTOAD, "toadstool", "A poisonous variety of mushroom.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); @@ -2521,6 +2544,7 @@ void initobjects(void) { addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_RARITY, H_SWAMP, 100, RR_FREQUENT, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_PURIFIESTO, OT_MUSHROOMSHI, NA, NA, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 3, NA, ""); addflag(lastot->flags, F_HASHIDDENNAME, B_TRUE, NA, NA, "mushroom"); @@ -2531,6 +2555,7 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 22, NA, ""); addflag(lastot->flags, F_RARITY, H_FOREST, 90, NA, NULL); addflag(lastot->flags, F_RARITY, H_DUNGEON, 90, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addflag(lastot->flags, F_NUMAPPEAR, 1, 12, NA, ""); addflag(lastot->flags, F_GROWSTO, OT_TREE, VT_OB, NA, NULL); addot(OT_ONION, "onion", "An edible bulb, known for its irritant effects on the eyes.", MT_FOOD, 0.2, OC_FOOD, SZ_TINY); @@ -2538,11 +2563,13 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 60, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_PASSIONFRUIT, "passionfruit", "A succulent passionfruit.", MT_FOOD, 0.5, OC_FOOD, SZ_TINY); addflag(lastot->flags, F_GLYPH, C_MAGENTA, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_POISONSAC, "venom sac", "A small sac of flesh, filled with potent venom.", MT_FLESH, 0.2, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BLUE, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, ""); @@ -2551,6 +2578,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_MAGENTA, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 250, NA, ""); addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_VERYRARE, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_RARE, NULL); addot(OT_ROASTMEAT, "chunk of roast meat", "A chunk of flame-roasted flesh.", MT_FLESH, 1, OC_FOOD, SZ_TINY); // weight normally comes from corpse type addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 100, NA, ""); @@ -2582,6 +2610,7 @@ void initobjects(void) { addflag(lastot->flags, F_EDIBLE, B_TRUE, 30, NA, ""); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_RARITY, H_FOREST, 100, NA, NULL); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, NA, NULL); // corpses addot(OT_CORPSE, "corpse", "xxx", MT_FLESH, 1, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); // will be overridden @@ -2593,6 +2622,7 @@ void initobjects(void) { addflag(lastot->flags, F_GLYPH, C_BROWN, '%', NA, NULL); addflag(lastot->flags, F_EDIBLE, B_TRUE, 25, NA, NULL); addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); + addflag(lastot->flags, F_RARITY, H_ANTNEST, 100, RR_COMMON, NULL); addot(OT_FINGER, "severed finger", "The severed finger from some kind of creature.", MT_FLESH, 0.02, OC_CORPSE, SZ_TINY); addflag(lastot->flags, F_EDIBLE, B_TRUE, 1, NA, NULL); addflag(lastot->flags, F_ISMEAT, B_TRUE, 80, NA, ""); @@ -4043,6 +4073,7 @@ void initobjects(void) { addflag(lastot->flags, F_EXTRADESC, NA, NA, NA, "Creatures with higher intelligence will take more damage."); addflag(lastot->flags, F_SPELLSCHOOL, SS_MENTAL, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 3, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); addflag(lastot->flags, F_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); @@ -8334,7 +8365,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LTAVERAGE, NA, NULL); - addflag(lastrace->flags, F_STAYINROOM, NA, B_TRUE, NA, NULL); // stay in our room, but we can chase targets out. + addflag(lastrace->flags, F_STAYINROOM, NA, B_MAYCHASE, NA, NULL); // stay in our room, but we can chase targets out. addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "50-100 gold coins"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "+2 halberd"); addflag(lastrace->flags, F_STARTOB, 100, NA, NA, "great armour"); @@ -8392,7 +8423,10 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_ENTANGLE, NA, NA, "pw:10;"); addflag(lastrace->flags, F_CANCAST, OT_S_BLINK, NA, NA, "pw:6;"); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "grins"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "cackles"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_NONE, NA, B_APPENDYOU, "gestures"); addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL); + addflag(lastrace->flags, F_CONSUMESOULS, 50, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "cackles evilly^an evil cackling"); addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); @@ -9805,7 +9839,8 @@ void initrace(void) { addflag(lastrace->flags, F_CASTTYPE, OT_S_CHARM, CT_GAZE, NA, NULL); //addflag(lastrace->flags, F_CANCAST, OT_S_SLEEP, 10, 10, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_PLANTWALK, NA, NA, NULL); - addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "smiles seductively and beckons"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "smiles seductively"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_CHARM, NA, B_APPENDYOU, "blows a kiss"); addflag(lastrace->flags, F_WANTSOBFLAG, F_GEM, B_COVETS, NA, NULL); addflag(lastrace->flags, F_WANTS, OT_GOLD, B_COVETS, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); @@ -10351,7 +10386,7 @@ void initrace(void) { addflag(lastrace->flags, F_RARITY, H_DUNGEON, 87, RR_UNCOMMON, NULL); addflag(lastrace->flags, F_RARITY, H_CAVE, 100, RR_COMMON, NULL); addflag(lastrace->flags, F_RARITY, H_FOREST, 80, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_RARITY, H_ANTNEST, NA, RR_RARE, NULL); addflag(lastrace->flags, F_SIZE, SZ_MEDIUM, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 4, NA, NA, NULL); addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); @@ -10359,7 +10394,7 @@ void initrace(void) { addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); addflag(lastrace->flags, F_ACTIONSPEED, SP_NORMAL, NA, NA, ""); addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 6, NA, NULL); - addflag(lastrace->flags, F_NUMAPPEAR, 2, 4, NA, NULL); + addflag(lastrace->flags, F_NUMAPPEAR, 1, 3, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_STR, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_IQ, AT_LTAVERAGE, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); @@ -10376,7 +10411,7 @@ void initrace(void) { addflag(lastrace->flags, F_CANCAST, OT_S_PASSWALL, NA, NA, "pw:5;"); addflag(lastrace->flags, F_CASTCHANCE, 50, NA, NA, NULL); addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_PASSWALL, NA, NA, NULL); - addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_DIG, NA, NA, "burrows down into the ground"); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_DIG, NA, NA, "burrows into a wall"); addflag(lastrace->flags, F_STABILITY, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 3, NA, "shouts^a shout"); addflag(lastrace->flags, F_DODGES, B_TRUE, NA, NA, NULL); @@ -12820,6 +12855,35 @@ void initrace(void) { addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); addflag(lastrace->flags, F_NOFLEE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_MUTABLE, B_TRUE, NA, "100"); + addrace(R_BATBRAIN, "brain bat", 6, 'B', C_RED, MT_FLESH, RC_ANIMAL, "Rare bats, said to exhibit strange psionic behaviour."); + setbodytype(lastrace, BT_BIRD); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_CAVE, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_RARE, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_RANDOM, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYFAST, NA, NA, ""); + addflag(lastrace->flags, F_NATURALFLIGHT, B_TRUE, NA, NA, ""); + addflag(lastrace->flags, F_CANWILL, OT_S_FLIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_FLIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_CLAWS, 2, NA, NULL); + addflag(lastrace->flags, F_EVASION, -10, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 10, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_FLY, 1, NA, "^flapping wings"); + addflag(lastrace->flags, F_CANCAST, OT_S_STUN, 3, 3, "pw:3;"); + addflag(lastrace->flags, F_CANCAST, OT_S_DISORIENT, 3, 3, "pw:3;"); + addflag(lastrace->flags, F_CANCAST, OT_S_PSIBLAST, 3, 3, "pw:1;"); + addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); + addflag(lastrace->flags, F_NOCTURNAL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL); addrace(R_BATVAMPIRE, "vampire bat", 6, 'B', C_BLUE, MT_FLESH, RC_ANIMAL, "Bats which suck the blood of their victims."); setbodytype(lastrace, BT_BIRD); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); @@ -13169,7 +13233,7 @@ void initrace(void) { addflag(lastrace->flags, F_DEAF, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_ENHANCESMELL, 4, NA, NA, NULL); addflag(lastrace->flags, F_MORALE, 6, NA, NA, NULL); - addrace(R_ANTS, "giant soldier ant", 25, 'a', C_RED, MT_FLESH, RC_ANIMAL, "The fighter of the giant ant family. Giant soldier ants are equipped with a powerful acidic stinger."); + addrace(R_ANTS, "giant soldier ant", 25, 'a', C_ORANGE, MT_FLESH, RC_ANIMAL, "The fighter of the giant ant family. Giant soldier ants are equipped with a powerful acidic stinger."); setbodytype(lastrace, BT_QUADRAPED); lastrace->baseid = R_ANT; addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -14646,7 +14710,10 @@ void initrace(void) { addflag(lastrace->flags, F_CANINE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - addrace(R_WORMGLUT, "glutwyrm", 25, 'W', C_MAGENTA, MT_FLESH, RC_DRAGON, "Gigantic wyrms who have become so obese over the centuries that they have evolved to be wingless. They swallow their prey whole, slowly digesting their still living bodies."); + // end animals + + // dragons / wyrms + addrace(R_WORMGLUT, "glutwyrm", 2500, 'W', C_MAGENTA, MT_FLESH, RC_DRAGON, "Gigantic wyrms who have become so obese over the centuries that they have evolved to be wingless. They swallow their prey whole, slowly digesting their still living bodies."); addbodypart(lastrace, BP_HEAD, NULL); addbodypart(lastrace, BP_TAIL, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); @@ -14674,9 +14741,32 @@ void initrace(void) { addflag(lastrace->flags, F_FLEEONHPPCT, 20, NA, NA, ""); addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); - // end animals - // dragons / wyrms + addrace(R_EARTHWYRM, "earthwyrm", 25, 'w', C_BROWN, MT_FLESH, RC_DRAGON, "Giant scaled wormlike creatures. Their large mouths are ringed with hundreds of sharp teeth."); + addbodypart(lastrace, BP_HEAD, NULL); + addbodypart(lastrace, BP_TAIL, NULL); + addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + //addflag(lastrace->flags, F_HATESALL, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_HIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, IQ_ANIMAL, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_SIZE, SZ_HUMAN, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_NOTALK, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_ENHANCESMELL, 2, NA, NA, NULL); + addflag(lastrace->flags, F_TREMORSENSE, 4, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_TEETH, 8, 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_RARITY, H_ANTNEST, NA, RR_UNCOMMON, NULL); + addflag(lastrace->flags, F_HITDICE, 5, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 6, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_WALK, SV_TALK, NA, "^slithering"); + addflag(lastrace->flags, F_MORALE, 30, NA, NA, NULL); + addflag(lastrace->flags, F_CANEATRAW, B_TRUE, NA, NA, NULL); addrace(R_WYVERN, "wyvern", 150, 'w', C_MAGENTA, MT_FLESH, RC_DRAGON, "Wyverns are smaller, malformed wyrms which were born without their usual breath powers."); setbodytype(lastrace, BT_HUMANOID); @@ -17007,7 +17097,7 @@ void initskills(void) { 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, "^g+2 accuracy.^n", B_FALSE); - addskilldesc(sk->id, PR_ADEPT, "^gYou can now alter your attack style to deal different damage types^n.", B_FALSE); + addskilldesc(sk->id, PR_ADEPT, "^gYou can now alter your attacks' damage types^n.", B_FALSE); addskilldesc(sk->id, PR_SKILLED, "^g+3 accuracy, +20% damage bonus.^n", B_FALSE); addskilldesc(sk->id, PR_SKILLED, "^gYou can now block certain attacks with this kind of weapon.^n", B_FALSE); addskilldesc(sk->id, PR_EXPERT, "^g+4 accuracy, +30% damage bonus.^n", B_FALSE); diff --git a/data/hiscores.db b/data/hiscores.db index 33596d6..0f17288 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/defs.h b/defs.h index ee490d8..b26a467 100644 --- a/defs.h +++ b/defs.h @@ -78,6 +78,7 @@ #define B_TRUE (-1) #define B_MAYBE (-2) +#define B_MAYCHASE (-1) #define B_ONLYEXTERNAL (-1) #define B_FORCE (-2) #define B_ONPURPOSE (-1) @@ -1122,6 +1123,7 @@ enum RACE { R_ANTS, R_ANTLION, R_BAT, + R_BATBRAIN, R_BATMUTATED, R_BATVAMPIRE, R_BEAR, @@ -1185,6 +1187,7 @@ enum RACE { R_DRAGONWHITE, R_DRAGONWHITEY, R_DRAGONWHITEA, + R_EARTHWYRM, R_WYVERN, // insects R_BLASTBUG, @@ -2894,6 +2897,7 @@ enum FLAG { // power. if not given, power comes from depth. F_NOSMELL, // lf can't smell. not affected by stench, and // can't get enhancesmell. + F_NOTALK, // override ability to talk F_RESTINGINMOTEL, // sounds will not wake up this lf. monster won't // see them. // v0 = max time allowed to rest before checkout @@ -2929,6 +2933,8 @@ enum FLAG { F_GAVEMONEY, // v0 tracks how much money we gave away this turn // used for r_godgreed anger effects. F_CLIMBING, // lf is currently climbing a wall + F_CONSUMESOULS, // lf gains hp from those who die nearby. + // up to v0% of their maxhp. F_COUNTER, // generic counter flag for race abilities. F_DEBUG, // debugging enabled F_ACCURACYMOD, // modify your accuracy by val0 @@ -3025,6 +3031,7 @@ enum FLAG { F_STARTHIDDENPCT, // val0 = pct chance auto-generated monster will // start off hidden F_CORPSETYPE, // text field specifies what corpse obtype to leave + // NULL no corpse. F_CORPSEFLAG, // add flag v0 to our corpse. // v1->v0, v2->v1, text->text F_EXTRACORPSE, // text field specifies what additional corpse diff --git a/god.c b/god.c index a9aa620..acea119 100644 --- a/god.c +++ b/god.c @@ -793,7 +793,7 @@ lifeform_t *godappears(enum RACE rid, cell_t *where) { strcpy(killedname, ""); if (!where) { // somewhere next to the player. - where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, player); + where = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, player); if (!where) { where = getrandomadjcell(player->cell, B_FALSE, B_NOEXPAND); } diff --git a/lf.c b/lf.c index ead364b..4a670a3 100644 --- a/lf.c +++ b/lf.c @@ -1584,6 +1584,9 @@ int cantalk(lifeform_t *lf) { if (lfhasflag(lf, F_PHANTASM)) { return B_FALSE; } + if (lfhasflag(lf, F_NOTALK)) { + return B_FALSE; + } // if the lf can't explicitly talk, check its race if (!lfhasflag(lf, F_CANTALK)) { if (!racecantalk(lf->race->id)) { @@ -1834,10 +1837,7 @@ int castspell(lifeform_t *lf, enum OBTYPE sid, lifeform_t *targlf, object_t *tar getlfname(lf, lfname); // special case - f = lfhasflagval(lf, F_SPELLCASTTEXT, sid, NA, NA, NULL); // specific text for this spell - if (!f) { - f = lfhasflagval(lf, F_SPELLCASTTEXT, OT_NONE, NA, NA, NULL); // generic spellcast - } + f = getspellcasttextflag(lf, sid); if (f) { if (strlen(f->text)) { snprintf(whattosay, BUFLEN, "%s %s", lfname, f->text); @@ -2792,6 +2792,13 @@ void die(lifeform_t *lf) { char reanimateas[BUFLEN]; cell_t *where; int thisisplayer = B_FALSE; + // for earthwyrms etc dividing + enum RACE dividerace = R_NONE; + cell_t *dividecell[2] = {NULL, NULL}; + char dividename[BUFLEN]; + int dividetr, dividehp; + int dividelos = B_FALSE; + strcpy(reanimateas, ""); @@ -2913,6 +2920,37 @@ void die(lifeform_t *lf) { } noise(exitcell, NULL, NC_OTHER, SV_TALK, "a loud 'click'.", NULL); } + + + if (lf->race->id == R_EARTHWYRM) { + // remember stats + dividehp = lf->maxhp / 2; + dividetr = gettr(lf) / 2; + + if ((dividehp >= 1) && (dividetr >= 1)) { + dividerace = lf->race->id; + getlfname(lf, dividename); + if (cansee(player, lf)) dividelos = B_TRUE; + + // are there 2 random cells free? + dividecell[0] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); + if (dividecell[0]) { + dividecell[1] = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_NOEXPAND, LOF_WALLSTOP, NULL, dividecell[0], NULL); + } + + if (!dividecell[1]) { + dividecell[1] = lf->cell; + } + if (dividecell[0] && dividecell[1]) { + // don't leave a corpse + killflagsofid(lf->flags, F_CORPSETYPE); + killflagsofid(lf->flags, F_EXTRACORPSE); + killflagsofid(lf->flags, F_NOCORPSE); + addflag(lf->flags, F_CORPSETYPE, NA, NA, NA, NULL); + } + } + } + if ((lf->race->id == R_VAMPIRE) && !hasflag(lf->flags, F_ORIGRACE)) { // if are asleep or killed by running water/sunlight, we will die normally if (lfhasflag(lf, F_ASLEEP) || (lf->lastdamtype == DT_DIRECT)) { @@ -3153,6 +3191,8 @@ void die(lifeform_t *lf) { dropobs = B_FALSE; } + + // drop/kill all objects if (corpsecell && (willbecomeghost || !thisisplayer)) { while (lf->pack->first) { @@ -3174,6 +3214,23 @@ void die(lifeform_t *lf) { // drop corpse/splatter blood if (corpsecell) { + lifeform_t *souleater = NULL; + flag_t *soulflag = NULL; + + // soul consumed? + if (corpsecell) { + lifeform_t *l; + for (l = lf->cell->map->lf ; l ; l = l->next) { + if (haslos(l, lf->cell)) { + soulflag = lfhasflag(l, F_CONSUMESOULS); + if (soulflag) { + souleater = l; + break; + } + } + } + } + if (vaporised) { if (lf->material->id == MT_FLESH) { switch (rnd(1,2)) { @@ -3185,6 +3242,23 @@ void die(lifeform_t *lf) { break; } } + } else if (souleater && soulflag) { + int amt; + if (isplayer(souleater)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + msg("^%cYou consume %s%s soul!", getlfcol(souleater, CC_GOOD), lfname, getpossessive(lfname)); + } else if (cansee(player, souleater)) { + char lfname[BUFLEN]; + getlfname(lf, lfname); + getlfname(souleater, buf); + msg("^%c%s consumes %s%s soul!", getlfcol(souleater, CC_GOOD), buf, lfname, getpossessive(lfname)); + } + amt = pctof( rnd(1,soulflag->val[0]), lf->maxhp); + limit(&amt, 1, NA); + gainhp(souleater, amt); + // drop bones + addob(corpsecell->obpile, "pile of ash"); } else if ((lf->lastdamtype == DT_BASH) && lfhasflag(lf, F_FROZEN)) { // shattered fragments(corpsecell, "chunk of ice", 2, UNLIMITED); @@ -3389,6 +3463,7 @@ void die(lifeform_t *lf) { } } + if (willbecomeghost) { flag_t *f, *nextf; // remove all job flags @@ -3473,6 +3548,31 @@ void die(lifeform_t *lf) { // IMPORTANT: DO NOT REFERENCE lf->xxxx AFTER THIS POINT // UNLESS WE ARE _SURE_ IT IS THE PLAYER (ie. thisisplayer = true) + if (dividerace != R_NONE) { + if (dividelos) { + msg("^w%s divides!", dividename); + } + // add two new worms nearby, with less hp. + for (i = 0;i < 2; i++) { + lifeform_t *newlf; + newlf = addmonster(dividecell[i], dividerace, NULL, B_FALSE, 1, B_FALSE, NULL); + if (newlf) { + // half hp + f = hasflag(newlf->flags, F_HITDICE); + f->val[0] = 0; + f->val[1] = 1; + f->val[2] = dividehp; + newlf->maxhp = dividehp; + newlf->hp = dividehp; + // half TR + f = hasflag(newlf->flags, F_TR); + f->val[0] = dividetr; + // no xp for killing + killflagsofid(newlf->flags, F_XPVAL); + addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); + } + } + } // Note that if we reanimate, the new monster will appear in an @@ -5798,7 +5898,7 @@ int flee(lifeform_t *lf) { if (db) dblog("%s - failed to flee via %s", lfname, stairs->type->name); } // move away from them - if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE, B_NOTONPURPOSE)) { + if (!moveawayfrom(lf, fleefrom->cell, DT_ORTH, B_FALSE, B_FALSE, isplayer(lf) ? B_NOTONPURPOSE : B_ONPURPOSE)) { if (db) dblog("%s - fleeing by moving away", lfname); return B_TRUE; } @@ -8082,6 +8182,28 @@ int getsmellrange(lifeform_t *lf) { return range; } +flag_t *getspellcasttextflag(lifeform_t *lf, enum OBTYPE sid) { + flag_t *f; + flag_t *retflag[MAXCANDIDATES],*genposs[MAXCANDIDATES],*specposs[MAXCANDIDATES]; + int nretflags,i,ngenposs = 0,nspecposs = 0; + getflags(lf->flags, retflag, &nretflags, F_SPELLCASTTEXT, F_NONE); + for (i = 0; i < nretflags; i++) { + if (retflag[i]->val[0] == sid ) { + specposs[nspecposs++] = retflag[i]; + } else if (retflag[i]->val[0] == OT_NONE) { + genposs[ngenposs++] = retflag[i]; + } + } + if (nspecposs) { + f = specposs[rnd(0,nspecposs-1)]; + } else if (ngenposs) { + f = genposs[rnd(0,ngenposs-1)]; + } else { + f = NULL; + } + return f; +} + glyph_t *getlfglyph(lifeform_t *lf) { flag_t *f; @@ -8600,7 +8722,15 @@ char *real_getlfname(lifeform_t *lf, char *buf, lifeform_t *usevis, int showall, if (!lfrace) { if (lfhasflag(lf, F_LYCANTHROPE)) { // lycanthropes appear as human unless you know better - if (getlorelevel(player, RC_HUMANOID) >= PR_ADEPT) { + if ((getlorelevel(player, RC_HUMANOID) >= PR_ADEPT) || + (getlorelevel(player, RC_MAGIC) >= PR_BEGINNER)) { + lfrace = lf->race; + } else { + lfrace = findrace(R_HUMAN); + } + } else if (lf->race->id == R_ANDROID) { + if ((getlorelevel(player, RC_HUMANOID) >= PR_BEGINNER) || + (getlorelevel(player, RC_ROBOT) >= PR_BEGINNER)) { lfrace = lf->race; } else { lfrace = findrace(R_HUMAN); @@ -21614,7 +21744,7 @@ int usestairs(lifeform_t *lf, object_t *o, int onpurpose, int climb) { // straight back down! if (hasflag(o->flags, F_PIT) && (dir == D_UP) && !isairborne(lf)) { cell_t *noholecell; - noholecell = real_getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL); + noholecell = real_getrandomadjcell(newcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, NULL ); if (noholecell) { // go here instead newcell = noholecell; diff --git a/lf.h b/lf.h index 665759c..bceaa86 100644 --- a/lf.h +++ b/lf.h @@ -197,6 +197,7 @@ object_t *getouterequippedob(lifeform_t *lf, enum BODYPART bp); enum LFCONDITION getseenlfconditioncutoff(lifeform_t *lf); char *getseenlfconditionname(lifeform_t *lf, lifeform_t *viewer); int getsmellrange(lifeform_t *lf); +flag_t *getspellcasttextflag(lifeform_t *lf, enum OBTYPE sid); glyph_t *getlfglyph(lifeform_t *lf); enum MATERIAL getlfmaterial(lifeform_t *lf); enum SKILLLEVEL getlorelevel(lifeform_t *lf, enum RACECLASS rcid); diff --git a/map.c b/map.c index 5032650..b964aa5 100644 --- a/map.c +++ b/map.c @@ -132,7 +132,7 @@ void addhomeobs(lifeform_t *lf, int dolevelobs) { cell_t *c; o = addob(homeobloc->obpile, f->text); if (o && (homeobloc == lf->cell) && isimpassableob(o, lf, SZ_ANY)) { - c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL); + c = real_getrandomadjcell(lf->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); if (c) { homeobloc = c; // future obs will go here too. moveob(o, homeobloc->obpile, o->amt); @@ -455,7 +455,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok lifeform_t *newlf; // find an adjacent cell to one of the newly added monsters, // starting with the first one - adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL); + adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); // did we find one? if (!adjcell) break; @@ -505,7 +505,7 @@ lifeform_t *addmonster(cell_t *c, enum RACE rid, char *racename, int randomjobok enum RACE newrid; race_t *newr; - adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL); + adjcell = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_WALLSTOP, NULL, NULL, NULL); if (!adjcell) break; newrid = parserace(f->text, NULL, NULL, NULL, NULL); @@ -1330,8 +1330,10 @@ int cellokforreachability(cell_t *startcell, cell_t *c, int srcroomid, int dir, return B_MAYBE; } +// kill everything in the given cell (lifeforms && objects) +// but DONT remove the cell itself. void clearcell(cell_t *c) { - // kill everything there - (lifeforms && objects) + if (c->lf && !isplayer(c->lf)) { killlf(c->lf); } @@ -2950,13 +2952,6 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t * int numpasses = 50; - // fill entire maze with walls - for (y = 0; y < map->h; y++) { - for (x = 0; x < map->w; x++) { - addcell(map, x, y); - } - } - // is the map lit? /* @@ -2978,10 +2973,21 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t * emptycell = getmapempty(map); solidcell = getmapsolid(map); + // fill entire maze with walls + for (y = 0; y < map->h; y++) { + for (x = 0; x < map->w; x++) { + c = getcellat(map, x, y); + setcelltype(c, solidcell); + } + } + + // pick initial random points for (i = 0; i < numstartpos; i++) { c = getrandomcell(map); - setcelltype(c, emptycell); + if (!c->locked) { + setcelltype(c, emptycell); + } } expand_cave(map, numpasses); @@ -3060,13 +3066,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ enum CELLTYPE emptycell,solidcell; char buf[BUFLEN]; - // fill entire maze with walls - for (y = 0; y < map->h; y++) { - for (x = 0; x < map->w; x++) { - addcell(map, x, y); - } - } - // select dungeon shape. if (onein(3)) { shape = rnd(0,MAXMAPSHAPES-1); @@ -3171,7 +3170,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ } } - // is the map lit? /* @@ -3191,36 +3189,6 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ */ map->illumination = IL_FULLLIT; - // random chance of different wall type - if (onein(6)) { - switch (rnd(1,3)) { - case 1: - addflag(map->flags, F_CELLTYPESOLID, CT_WALLBRICK, NA, NA, NULL); - break; - case 2: - addflag(map->flags, F_CELLTYPESOLID, CT_WALLMETAL, NA, NA, NULL); - break; - case 3: - addflag(map->flags, F_CELLTYPESOLID, CT_WALLWOOD, NA, NA, NULL); - break; - } - } - // random chance of different floor type - if (onein(6)) { - switch (rnd(1,3)) { - case 1: - addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORCARPET, NA, NA, NULL); - break; - case 2: - addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORTILE, NA, NA, NULL); - break; - case 3: - addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORWOOD, NA, NA, NULL); - break; - } - } - - // what kind of cells will 'empty' ones be? emptycell = getmapempty(map); solidcell = getmapsolid(map); @@ -3229,7 +3197,9 @@ void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_ for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); - setcelltype(c, solidcell); + if (!getcellvault(c) && c->type->solid) { + setcelltype(c, solidcell); + } } } @@ -3554,7 +3524,7 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { - c = addcell(map, x, y); + c = getcellat(map, x, y); setcelltype(c, onein(4) ? CT_DIRT : emptycell ); } } @@ -3641,7 +3611,6 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t void createhabitat(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) { - map->nrooms = 0; // reset room counts switch (map->habitat->id) { case H_DUNGEON: createdungeon(map, depth, parentmap, exitdir, entryob); @@ -3750,7 +3719,10 @@ void createheaven(map_t *map, int depth, map_t *parentmap, int exitdir, object_t sparseness = how many times to chop off dead ends looppct = percentage change of turning dead-end into loop maxrooms = max # of rooms + + exitdir = direction you WENT to get to this map. */ + void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int exitdir, object_t *entryob) { lifeform_t *lf; map_t *m; @@ -3759,6 +3731,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex enum HABITAT habitat; regionthing_t *thing[MAXOUTLINETHINGS]; int nthings = 0,failed,nstairslinked = 0; + int nprevaults = 0; int db = B_TRUE; //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging @@ -3979,52 +3952,28 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex if (db) dblog(" %d things remembered for later.",nthings); //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + failed = B_TRUE; while (failed) { failed = B_FALSE; - // build it... - //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging - if (db) dblog(" creating map habitat."); - createhabitat(map, depth, parentmap, exitdir, entryob); - //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + selectcelltypes(map); - // add home objects - if (db) dblog(" adding home objects."); - for (lf = map->lf ; lf ; lf = lf->next) { - addhomeobs(lf, B_TRUE); + // create initial map cells (they will be solid) + for (y = 0; y < map->h; y++) { + for (x = 0; x < map->w; x++) { + addcell(map, x, y); + } } - //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + map->nrooms = 0; // reset room counts + + // place forced vaults. + if (db) dblog(" adding forced vaults first..."); - // add outline things - if (db) dblog(" adding remembered region outline things..."); for (i = 0; i < nthings ;i++) { - vault_t *v; - cell_t *c; - // add this thing + vault_t *v = NULL; + //cell_t *c; switch (thing[i]->whatkind) { - case RT_HABITAT: // already handled above - break; - case RT_OBJECT: - if (db) dblog(" adding forced regionthing object: %s", thing[i]->what); - c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); - if (!c) c = getrandomcell(map); - c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL); - addob(c->obpile, thing[i]->what); - break; - case RT_LF: - if (db) dblog(" adding forced regionthing lifeform: %s", thing[i]->what); - c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); - if (!c) c = getrandomcell(map); - c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL); - addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE, NULL); - break; - case RT_REGIONLINK: - if (db) dblog(" adding regionlink"); - createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region); - // ... don't need to do this since we know there won't be anywhere to link to. - //linkstairs(o); - break; case RT_VAULT: if (db) dblog(" adding vault"); v = findvault(thing[i]->what); @@ -4052,8 +4001,83 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex failed = B_TRUE; } break; + default: + break; + } + + if (failed) break; + + // did we make a vault? + if (v) { + room_t *r; + int x,y; + // lock all vault's cells + r = &map->room[map->nrooms-1]; + for (y = r->y1; y <= r->y2; y++) { + for (x = r->x1; x <= r->x2; x++) { + cell_t *c; + c = getcellat(map, x, y); + c->locked = B_TRUE; + } + } + } + } // for each remembered thing + + if (failed) { + dblog("********* got errors during forced vault placement - restarting map creation. *********"); + unmakemap(map); + continue; + } + + if (db) dblog(" finished forced vault creation (%d placed).", nprevaults); + // build it... + if (db) dblog(" starting map build."); + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + + if (db) dblog(" creating map habitat."); + createhabitat(map, depth, parentmap, exitdir, entryob); + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + + // add home objects + if (db) dblog(" adding home objects."); + for (lf = map->lf ; lf ; lf = lf->next) { + addhomeobs(lf, B_TRUE); + } + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + + // add outline things + if (db) dblog(" adding remembered region outline things..."); + for (i = 0; i < nthings ;i++) { + //vault_t *v; + cell_t *c; + // add this thing + switch (thing[i]->whatkind) { + case RT_HABITAT: // already handled above + break; + case RT_OBJECT: + if (db) dblog(" adding forced regionthing object: %s", thing[i]->what); + c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); + if (!c) c = getrandomcell(map); + c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + addob(c->obpile, thing[i]->what); + break; + case RT_LF: + if (db) dblog(" adding forced regionthing lifeform: %s", thing[i]->what); + c = getrandomroomcell(map, ANYROOM, WE_WALKABLE); + if (!c) c = getrandomcell(map); + c = real_getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); + addmonster(c, R_SPECIFIED, thing[i]->what, B_FALSE, thing[i]->value, B_TRUE, NULL); + break; + case RT_REGIONLINK: + if (db) dblog(" adding regionlink"); + createregionlink(map, NULL, NULL, thing[i]->what, thing[i]->value, map->region); + // ... don't need to do this since we know there won't be anywhere to link to. + //linkstairs(o); + break; case RT_NONE: break; + default: + break; } } //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging @@ -4067,24 +4091,13 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging if (failed) { - region_t *r,*nextr; dblog("********* got errors - restarting map creation. *********"); - // remove map flags added during vault creation. - killflagsofid(map->flags, F_MAPSHAPE); - killflagsofid(map->flags, F_ROOMEXIT); - // unlink stairs on adjacent maps - unlinkstairsto(map); - // remove regions created by regionlinks in this map. - for (r = firstregion ; r ; r = nextr ){ - nextr = r->next; - if (r->createdbymapid == map->id) { - killregion(r); - } - } + unmakemap(map); + continue; } - } - //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging + } // end while failed) + //if (gamemode == GM_GAMESTARTED) checkallflags(player->cell->map); // debugging if (map->habitat->id == H_CAVE) { // expand the cave a little more now that we've fixed reachability. @@ -4093,7 +4106,7 @@ void createmap(map_t *map, int depth, region_t *region, map_t *parentmap, int ex } // add any required stairs - finalisemap(map, entryob); + finalisemap(map, entryob, exitdir); // special cases // village - add town walls and clear it out @@ -4389,7 +4402,8 @@ void createsewer(map_t *map, int depth, map_t *parentmap, int exitdir, object_t // fill entire maze with walls for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { - addcell(map, x, y); + c = getcellat(map, x, y); + setcelltype(c, getcellempty(c)); } } roomon = malloc((roomcountx * roomcounty) * sizeof(int)); @@ -4760,6 +4774,17 @@ int createvault(map_t *map, int roomid, vault_t *v, int *retw, int *reth, int *r linkexits(map, roomid); } + // lock cells if required + if (hasflag(v->flags, F_MAINTAINEDGE)) { + for (y = miny; y <= maxy; y++) { + for (x = minx; x <= maxx; x++) { + cell_t *c; + c = getcellat(map, x, y); + c->locked = B_TRUE; + } + } + } + // remove bones vault files after creation. if (hasflagval(v->flags, F_VAULTTAG, NA, NA, NA, "bones")) { removevaultfile(v->filename); @@ -5723,12 +5748,12 @@ void expand_cave(map_t *map, int numpasses) { for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); - if (!c->type->solid && !c->visited) { // cell is empty and not processed already? + if (!c->type->solid && !c->visited && !c->locked) { // cell is empty and not processed already? cell_t *c2; // check for surrounding solid cells for (dir = DC_N; dir <= DC_NW; dir++) { c2 = getcellindir(c, dir); - if (c2 && c2->type->solid && pctchance(chancetoclear)) { + if (c2 && c2->type->solid && !c2->locked && pctchance(chancetoclear)) { setcelltype(c2, getmapempty(map)); } } @@ -5768,7 +5793,7 @@ void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *c } } -void finalisemap(map_t *map, object_t *entryob) { +void finalisemap(map_t *map, object_t *entryob, int exitdir) { enum OBTYPE upstairtype, downstairtype; int i,d,x,y; int linkedentry = B_FALSE; @@ -5850,7 +5875,7 @@ void finalisemap(map_t *map, object_t *entryob) { } o = addobfast(c->obpile, upstairtype); assert(o); - if (entryob && !linkedentry) { + if (entryob && (exitdir == D_DOWN) && !linkedentry) { linkstairs(o, entryob); linkedentry = B_TRUE; } else { @@ -5864,24 +5889,6 @@ void finalisemap(map_t *map, object_t *entryob) { } } - // if our up stairs were created by a vault, then we now need to link them. - if (entryob && !linkedentry) { - for (y = 0; (y < map->h) && !linkedentry; y++) { - for (x = 0; (x < map->w) && !linkedentry; x++) { - c = getcellat(map, x, y); - o = hasob(c->obpile, upstairtype); - if (o && !hasflag(o->flags, F_MAPLINK)) { - linkstairs(o, entryob); - linkedentry = B_TRUE; - break; - } - } - } - if (!linkedentry) { - dblog("ERROR - couldn't link stairs back to map entry object."); - msg("ERROR - couldn't link stairs back to map entry object."); more(); - } - } // DOWN STAIRS if ((downstairtype != OT_NONE) && (map->depth < map->region->rtype->maxdepth)) { @@ -5897,21 +5904,52 @@ void finalisemap(map_t *map, object_t *entryob) { } o = addobfast(c->obpile, downstairtype); assert(o); - linkstairs(o, NULL); + if (entryob && (exitdir == D_UP) && !linkedentry) { + linkstairs(o, entryob); + linkedentry = B_TRUE; + } else { + linkstairs(o, NULL); + } } } + // if our up/down stairs were created by a vault, then we now need to link them. + if (entryob && !linkedentry) { + enum OBTYPE wantoid; + if (exitdir == D_DOWN) { + wantoid = upstairtype; + } else { + wantoid = downstairtype; + } + for (y = 0; (y < map->h) && !linkedentry; y++) { + for (x = 0; (x < map->w) && !linkedentry; x++) { + c = getcellat(map, x, y); + o = hasob(c->obpile, wantoid); + if (o && !hasflag(o->flags, F_MAPLINK)) { + linkstairs(o, entryob); + linkedentry = B_TRUE; + break; + } + } + } + if (!linkedentry) { + dblog("ERROR - couldn't link stairs back to map entry object."); + msg("ERROR - couldn't link stairs back to map entry object."); more(); + } + } + + + // other finalisation tasks... for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = getcellat(map, x, y); for (o = c->obpile->first ; o ; o = nexto) { nexto = o->next; - if (c->room && c->room->vault) { - } else { - // remove doors which go nowhere + if (!getcellvault(c)) { + // remove doors which go nowhere (internal to rooms) if (isdoor(o, NULL)) { int dir, ok = B_FALSE; - cell_t *c2; + /* // check all directions for a cell which isn't // part of this room. for (dir = DC_N; dir <= DC_NW; dir++) { @@ -5921,6 +5959,18 @@ void finalisemap(map_t *map, object_t *entryob) { break; } } + */ + // doors must be between two solid cells + for (dir = DC_N; dir <= DC_NW; dir++) { + cell_t *c1; + cell_t *c2; + c1 = getcellindir(c, dir); + c2 = getcellindir(c, diropposite(dir)); + if (issolid(c1) && issolid(c2)) { + ok = B_TRUE; + break; + } + } if (!ok) { killob(o); continue; @@ -6618,10 +6668,10 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved) { cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand) { - return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL, NULL); + return real_getrandomadjcell(c, wantempty, allowexpand, LOF_NEED, NULL, NULL, NULL); } -cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, lifeform_t *preferlos) { +cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos) { int radius = 1; int x,y; cell_t *poss[MAXCANDIDATES]; @@ -6638,6 +6688,7 @@ cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LO if (new && (new != c) && (getcelldist(c,new) == radius) && + (new != dontwantcell) && haslof(c, new, needlof, NULL)) { enum OBTYPE *badoid; int ok = B_FALSE; @@ -7499,7 +7550,7 @@ int linkholes(map_t *map) { // this will automatically avoid lifeforms since we're using // we_walkable rather than we_notwall. this saves problems // with someine coming up underneath you! - c2 = real_getrandomadjcell(c2, WE_NOLF, B_ALLOWEXPAND, LOF_DONTNEED, &ot->id, NULL); + c2 = real_getrandomadjcell(c2, WE_NOLF, B_ALLOWEXPAND, LOF_DONTNEED, &ot->id, NULL, NULL); } // clear out the cell if required if (c2->type->solid) { @@ -8104,6 +8155,39 @@ int remove_deadends(map_t *m, int howmuch) { } return count; } + +void selectcelltypes(map_t *map) { + if (map->habitat->id == H_DUNGEON) { + // random chance of different wall type + if (onein(6)) { + switch (rnd(1,3)) { + case 1: + addflag(map->flags, F_CELLTYPESOLID, CT_WALLBRICK, NA, NA, NULL); + break; + case 2: + addflag(map->flags, F_CELLTYPESOLID, CT_WALLMETAL, NA, NA, NULL); + break; + case 3: + addflag(map->flags, F_CELLTYPESOLID, CT_WALLWOOD, NA, NA, NULL); + break; + } + } + // random chance of different floor type + if (onein(6)) { + switch (rnd(1,3)) { + case 1: + addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORCARPET, NA, NA, NULL); + break; + case 2: + addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORTILE, NA, NA, NULL); + break; + case 3: + addflag(map->flags, F_CELLTYPEEMPTY, CT_FLOORWOOD, NA, NA, NULL); + break; + } + } + } +} void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph) { if (targettype == TT_MONSTER) { @@ -8273,7 +8357,7 @@ int unlinkstairsto(map_t *unlinkmap) { int db = B_TRUE; flag_t *retflag[MAXCANDIDATES]; - if (db) dblog("starting unlinkstairsto for unlikmap='%s'",unlinkmap->name); + if (db) dblog(" starting unlinkstairsto for unlinkmap='%s'",unlinkmap->name); // get a list of all stair object ids on this unlinkmap. for (y = 0; y < unlinkmap->h; y++) { for (x = 0; x < unlinkmap->w; x++) { @@ -8285,10 +8369,10 @@ int unlinkstairsto(map_t *unlinkmap) { } } } - if (db) dblog(" found %d stairs on unlinkmap.",nbadids); + if (db) dblog(" found %d stairs on unlinkmap.",nbadids); // go through all maps and remove any stairs which link to unlinkmap - if (db) dblog(" searching other maps for stairs linking to unlinkmap."); + if (db) dblog(" searching other maps for stairs linking TO unlinkmap."); for (m = firstmap ; m ; m = m->next) { for (y = 0; y < m->h; y++) { for (x = 0; x < m->w; x++) { @@ -8299,13 +8383,13 @@ int unlinkstairsto(map_t *unlinkmap) { int killit = B_FALSE,n; if (retflag[i]->val[0] == unlinkmap->id) { - if (db) dblog(" on map '%s': found '%s' linking to unlinkmap's id.", m->name,o->type->name); + if (db) dblog(" on map '%s': found '%s' linking to unlinkmap's id.", m->name,o->type->name); killit = B_TRUE; } else { for (n = 0; n < nbadids; n++) { if (atol(retflag[i]->text) == badid[n]) { killit = B_TRUE; - if (db) dblog(" on map '%s': found '%s' linking to obid of stairs on unlinkmap.", m->name,o->type->name); + if (db) dblog(" on map '%s': found '%s' linking to obid of stairs on unlinkmap.", m->name,o->type->name); break; } } @@ -8320,7 +8404,7 @@ int unlinkstairsto(map_t *unlinkmap) { } // now remove all links from stairs on unlinkmap - if (db) dblog(" removing maplinks from stairs on unlinkmap."); + if (db) dblog(" removing maplinks FROM stairs on unlinkmap."); for (y = 0; y < unlinkmap->h; y++) { for (x = 0; x < unlinkmap->w; x++) { c = getcellat(unlinkmap, x,y); @@ -8329,10 +8413,43 @@ int unlinkstairsto(map_t *unlinkmap) { } } } - if (db) dblog("finished unlinkstairsto for unlikmap='%s'",unlinkmap->name); + if (db) dblog(" finished unlinkstairsto for unlinkmap='%s'",unlinkmap->name); return B_FALSE; } +void unmakemap(map_t *map) { + region_t *r,*nextr; + int i; + int db = B_TRUE; + int nlf = 0,nreg = 0; + if (db) dblog("unmaking map."); + // remove map lifeforms + while (map->lf) { + killlf(map->lf); + nlf++; + } + if (db) dblog(" %d lifeforms removed.", nlf); + // remove map flags added during vault creation. + killflagsofid(map->flags, F_MAPSHAPE); + killflagsofid(map->flags, F_ROOMEXIT); + // unlink stairs on adjacent maps + unlinkstairsto(map); + // remove regions created by regionlinks in this map. + for (r = firstregion ; r ; r = nextr ){ + nextr = r->next; + if (r->createdbymapid == map->id) { + killregion(r); + nreg++; + } + } + if (db) dblog(" %d linked regions removed.", nreg); + // free cells on this map + for (i = 0; i < (map->w*map->h); i++){ + killcell(map->cell[i]); + free(map->cell[i]); + map->cell[i] = NULL; + } +} void updateknowncells(void) { //int x,y; diff --git a/map.h b/map.h index 6165952..93ab8fb 100644 --- a/map.h +++ b/map.h @@ -96,7 +96,7 @@ void dumpmap(map_t *map, int showrooms); void expand_cave(map_t *map, int numpasses); void explodesinglecell(cell_t *c, int dam, int killwalls, object_t *o, cell_t *centre); void explodecells(cell_t *c, int dam, int killwalls, object_t *o, int range, int dirtype, int wantannounce); -void finalisemap(map_t *map, object_t *entryob); +void finalisemap(map_t *map, object_t *entryob, int exitdir); void finalisemonster(lifeform_t *lf, lifeform_t *leader, flagpile_t *wantflags, enum BEHAVIOUR wantbehaviour, int idx); celltype_t *findcelltype(enum CELLTYPE cid); celltype_t *findcelltypebyname(char *name); @@ -128,7 +128,7 @@ int getnewdigdir(cell_t *cell, int lastdir, int turnpct, int *moved); int getobchance(int habitat); int getthingchance(int habitat); cell_t *getrandomadjcell(cell_t *c, int wantempty, int allowexpand); -cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, lifeform_t *preferlos); +cell_t *real_getrandomadjcell(cell_t *c, int wantempty, int allowexpand, enum LOFTYPE needlof, enum OBTYPE *dontwantob, cell_t *dontwantcell, lifeform_t *preferlos); cell_t *getrandomcell(map_t *map); cell_t *getrandomcelloftype(map_t *map, enum CELLTYPE id); int getrandomdir(int dirtype); @@ -180,12 +180,14 @@ void moveobtoclearcell(object_t *o); int orthdir(int compassdir); enum RACE parserace(char *name, flagpile_t *wantflags, enum JOB *wantjob, enum SUBJOB *wantsubjob, enum BEHAVIOUR *wantbehaviour); int remove_deadends(map_t *m, int howmuch); +void selectcelltypes(map_t *map); void set_scanned_glyph(int targettype, void *what, char *descappend, char *desc, glyph_t *glyph); void setcellknown(cell_t *cell, int forcelev); void setcellknownradius(cell_t *centre, int forcelev, int radius, int dirtype); void setcelltype(cell_t *cell, enum CELLTYPE id); int shattercell(cell_t *c, lifeform_t *fromlf, char *damstring); int unlinkstairsto(map_t *unlinkmap); +void unmakemap(map_t *map); void updateknowncells(void); int validateregions(void); int validateregionthing(regionthing_t *thing); diff --git a/nexus.c b/nexus.c index ad34919..2ec1d91 100644 --- a/nexus.c +++ b/nexus.c @@ -377,7 +377,7 @@ int main(int argc, char **argv) { assert(r); // create pet, in view of player if possible. - c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, player); + c = real_getrandomadjcell(player->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, &avoidob, NULL, player); assert(c); pet = addlf(c, r->id, 1); // mark us as its master diff --git a/save.c b/save.c index 03c1379..adb1cf4 100644 --- a/save.c +++ b/save.c @@ -359,7 +359,11 @@ map_t *loadmap(FILE *f) { // load room defs fscanf(f, "nrooms:%d\n",&m->nrooms); for (i = 0; i < m->nrooms; i++) { - fscanf(f, "%d,%d,%d,%d,%d,%s\n",&m->room[i].id, + char line[BUFLEN]; + fgets(line, BUFLEN, f); + //if (line[strlen(line)-1] == '\n') line[strlen(line)-1] = '\0'; + + sscanf(line, "%d,%d,%d,%d,%d,%[ a-xA-Z_0-9+'*/-]\n",&m->room[i].id, &m->room[i].x1, &m->room[i].y1, &m->room[i].x2, &m->room[i].y2, buf); m->room[i].vault = findvault(buf); @@ -630,6 +634,7 @@ int loadregions(FILE *f) { if (db) dblog("Found %d region outlines.\n",numoutlines); for (n = 0; n < numoutlines; n++) { regionthing_t *thing; + if (db) dblog(" loading regionoutline #%d / %d",n+1, numoutlines); fscanf(f, "startro\n"); fscanf(f, "rtypeid:%d\n",&rtid); // region type id addregionoutline(rtid); @@ -638,19 +643,25 @@ int loadregions(FILE *f) { for (i = 0; i < nthings; i++) { int depth,x,y,val,id; enum REGIONTHING whatkind; - char buf[BUFLEN],*p; + char buf[BUFLEN]; + fscanf(f, "startthing\n"); fscanf(f, " thingid:%d\n",&id); fscanf(f, " thingdepth:%d,%d,%d\n",&depth, &x, &y); fscanf(f, " thingkind:%d\n",(int *)&whatkind); fscanf(f, " thingval:%d\n",&val); - fscanf(f, " thingwhat:%s\n",buf); + fscanf(f, " thingwhat:%[ a-xA-Z_0-9+'*/-]\n",buf); fscanf(f, "endthing\n"); // replace ^ with ' ' in thingwhat + /* for (p = buf ; *p; p++) { if (*p == '^') *p = ' '; } + */ + + if (db) dblog(" got regionthing: [%s]", buf); + thing = addregionthing(lastregionoutline, depth, x, y, whatkind, val, streq(buf, "NULL") ? NULL : buf); thing->id = id; } @@ -1216,11 +1227,13 @@ int saveregions(FILE *f) { fprintf(f, " thingkind:%d\n",(int)ro->thing[i].whatkind); fprintf(f, " thingval:%d\n",(int)ro->thing[i].value); if (strlen(ro->thing[i].what)) { - char localwhat[BUFLEN],*p; + char localwhat[BUFLEN]; strcpy(localwhat,ro->thing[i].what); + /* for (p = localwhat ; *p; p++) { if (*p == ' ') *p = '^'; } + */ fprintf(f, " thingwhat:%s\n",localwhat); } else { fprintf(f, " thingwhat:NULL\n"); diff --git a/spell.c b/spell.c index 33ae75b..1463ab3 100644 --- a/spell.c +++ b/spell.c @@ -6207,7 +6207,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ badoid[1] = OT_NONE; for (i = 0; i < amt; i++) { cell_t *c; - c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, badoid, NULL); + c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_WALLSTOP, badoid, NULL, NULL); if (c) { object_t *water; water = addob(c->obpile, "water"); @@ -7691,7 +7691,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ job_t *j; object_t *o; // create a mirror image - targcell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, caster); + targcell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); if (!targcell) break; lf = clonelf(caster, targcell); if (!lf) break; @@ -8193,7 +8193,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (dstcell && !cellwalkable(caster, dstcell, NULL)) { - dstcell = real_getrandomadjcell(dstcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL); + dstcell = real_getrandomadjcell(dstcell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, NULL); } if (dstcell) { @@ -8316,7 +8316,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } if (!cellwalkable(caster, targcell, NULL)) { - targcell = real_getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND, LOF_DONTNEED, NULL, NULL); + targcell = real_getrandomadjcell(targcell, WE_WALKABLE, B_NOEXPAND, LOF_DONTNEED, NULL, NULL, NULL); if (!targcell) { fizzle(caster); return B_FALSE; @@ -8713,7 +8713,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ object_t *srcportal,*dstportal; // find adjacent cell for portal - srccell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, caster); + srccell = real_getrandomadjcell(caster->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); if (!srccell) { fizzle(caster); return B_TRUE; @@ -10684,7 +10684,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ badoid[0] = OT_MUDPOOL; badoid[1] = OT_NONE; for (i = 0; i < powerleft; i++) { - c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, badoid, NULL); + c = real_getrandomadjcell(targcell, WE_NOTWALL, B_ALLOWEXPAND, LOF_DONTNEED, badoid, NULL, NULL); if (c) { o = addob(c->obpile, "pool of mud"); if (o) { @@ -12494,7 +12494,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (hasflag(o->flags, F_IMPASSABLE)) { cell_t *newloc; // if so, don't put it where the player is! - newloc = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, target); + newloc = real_getrandomadjcell(target->cell, WE_WALKABLE, B_ALLOWEXPAND, LOF_DONTNEED, NULL, NULL, target); o = relinkob(o, newloc->obpile); } if (o) { @@ -13739,7 +13739,7 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACE wantrace, enum RACECL for (i = 0; i < howmany; i++) { // get random adjacent cell // (prefer cells in sight of caster) - c = real_getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND, LOF_NEED, NULL, caster); + c = real_getrandomadjcell(where, WE_EMPTY, B_ALLOWEXPAND, LOF_NEED, NULL, NULL, caster); if (!c) { return ncreated; } diff --git a/text.c b/text.c index 0fa8498..76c3797 100644 --- a/text.c +++ b/text.c @@ -1134,6 +1134,7 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d if (damtype == DT_SLASH) { skill_t *sk; int canbehead = B_TRUE; + if (wep) { sk = getobskill(wep->flags); if (sk && (sk->id != SK_LONGBLADES) && (sk->id != SK_EXOTICWEPS)) { @@ -1142,7 +1143,9 @@ char *getkillverb(lifeform_t *victim, object_t *wep, enum DAMTYPE damtype, int d } } if (canbehead) { - if (!hasbp(victim, BP_HEAD)) { + if (victim && (victim->race->id == R_EARTHWYRM)) { + return "bisect"; + } else if (!hasbp(victim, BP_HEAD)) { return "bisect"; } else { if ((getlfsize(victim) >= SZ_MEDIUM) && onein(3)) { diff --git a/vault.c b/vault.c index 2dbde62..2a2754e 100644 --- a/vault.c +++ b/vault.c @@ -1346,7 +1346,7 @@ int handleline(vault_t *v, char *line) { dblog("invalid goesin() definition: '%s'", line); } } else if (streq(line, "keepmonsinroom")) { - addflag(v->flags, F_STAYINROOM, NA, B_TRUE, NA, NULL); + addflag(v->flags, F_STAYINROOM, NA, B_MAYCHASE, NA, NULL); ok = B_TRUE; } else if (streq(line, "maintainedge")) { addflag(v->flags, F_MAINTAINEDGE, B_TRUE, NA, NA, NULL);