diff --git a/ai.c b/ai.c index 751ecd1..25c3db3 100644 --- a/ai.c +++ b/ai.c @@ -500,6 +500,33 @@ int aigetspelltarget(lifeform_t *lf, objecttype_t *spelltype, lifeform_t *victim } if (spelllf) *spelllf = NULL; if (spellob) *spellob = NULL; + } else if ((spelltype->id == OT_S_ANIMATESTATUE) || (spelltype->id == OT_S_ANIMATETREE)) { + cell_t *cell[MAXCANDIDATES],*poss[MAXCANDIDATES]; + int ncells,i,nposs = 0; + enum OBTYPE oid; + if (spelltype->id == OT_S_ANIMATESTATUE) { + oid = OT_STATUE; + } else { + oid = OT_TREE; + } + + if (spelllf) *spelllf = NULL; + if (spellob) *spellob = NULL; + // adjacent cell with a tree? + getradiuscells(lf->cell, 1, DT_COMPASS, B_TRUE, LOF_DONTNEED, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + if (hasob(cell[i]->obpile, oid)) { + poss[nposs++] = cell[i]; + } + } + if (!nposs) { + if (spellcell) spellcell = NULL; + return B_TRUE; + } + + if (spellcell) { + *spellcell = poss[rnd(0,nposs-1)]; + } } else if (spelltype->id == OT_A_JUMP) { cell_t *cell[MAXCANDIDATES],*c; cell_t *poss[MAXCANDIDATES]; @@ -2304,6 +2331,28 @@ int aispellok(lifeform_t *lf, enum OBTYPE spellid, lifeform_t *victim, enum FLAG } } } + } else if (ot->id == OT_S_ANIMATESTATUE) { + cell_t *cell[MAXCANDIDATES]; + int ncells,i; + // adjacent cell with a tree? + getradiuscells(lf->cell, 1, DT_COMPASS, B_TRUE, LOF_DONTNEED, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + if (hasob(cell[i]->obpile, OT_STATUE)) { + ok = B_TRUE; + break; + } + } + } else if (ot->id == OT_S_ANIMATETREE) { + cell_t *cell[MAXCANDIDATES]; + int ncells,i; + // adjacent cell with a tree? + getradiuscells(lf->cell, 1, DT_COMPASS, B_TRUE, LOF_DONTNEED, B_FALSE, cell, &ncells, 0); + for (i = 0; i < ncells; i++) { + if (hasob(cell[i]->obpile, OT_TREE)) { + ok = B_TRUE; + break; + } + } } else if (ot->id == OT_S_DIG) { cell_t *cell[MAXCANDIDATES]; int ncells,i; diff --git a/attack.c b/attack.c index a838971..ada1143 100644 --- a/attack.c +++ b/attack.c @@ -225,8 +225,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { real_warnabout(TEXT_WARN_NOXP_GOODVSPEACEFUL, PERMENANT, B_FALSE); } } - // above average wisdom will prvent you from annoying your god - if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_GTAVERAGE) { + // average wisdom will prvent you from annoying your god + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_AVERAGE) { enum HELPLESSTYPE how; if (ishelplessvictim(c->lf, lf, &how)) { int dowarning = B_FALSE; @@ -255,8 +255,8 @@ int attackcell(lifeform_t *lf, cell_t *c, int force) { } } } - // high wisdom will prevent you from starting fires - if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_HIGH) { + // above average wisdom will prevent you from starting fires + if (getattrbracket(getattr(lf, A_WIS), A_WIS, NULL) >= AT_GTAVERAGE) { if (hasflag(c->type->material->flags, F_FLAMMABLE)) { if (getlorelevel(player, c->lf->race->raceclass->id) >= PR_BEGINNER) { if (c->lf->race->id == R_FIREBUG) { diff --git a/data.c b/data.c index 2109dda..1d0ec6e 100644 --- a/data.c +++ b/data.c @@ -1433,6 +1433,7 @@ void initobjects(void) { addflag(lastobjectclass->flags, F_OPERABLE, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_OPERWITHOUTID, B_TRUE, NA, NA, NULL); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastobjectclass->flags, F_GODSTONE, B_TRUE, NA, B_TRUE, NULL); addoc(OC_CORPSE, "Corpses", "Dead flesh which was once living.", '%', C_GREY, RR_NEVER); addflag(lastobjectclass->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); @@ -1581,6 +1582,7 @@ void initobjects(void) { addot(OT_HOLEINGROUND, "hole in the ground", "A gaping hole in the ground.", MT_NOTHING, 0, OC_DFEATURE, SZ_LARGE); addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, 100, RR_UNCOMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, 100, RR_UNCOMMON, NULL); addflag(lastot->flags, F_GLYPH, C_BLUE, '^', NA, NULL); addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, "hole"); addflag(lastot->flags, F_DONTSHOWDEST, B_TRUE, NA, NA, NULL); @@ -1601,6 +1603,21 @@ void initobjects(void) { addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_ONEPERCELL, B_TRUE, NA, NA, NULL); + addot(OT_TREEDOWN, "hollow tree leading down", "A huge hollow tree containing an ascending staircase.", MT_DRAGONWOOD, 3000, OC_DFEATURE, SZ_HUGE); + addflag(lastot->flags, F_GLYPH, C_BROWN, '>', NA, NULL); + addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, "hollow tree"); + addflag(lastot->flags, F_OPPOSITESTAIRS, OT_TREEUP, NA, NA, NULL); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "rustling leaves."); + addflag(lastot->flags, F_MAKESNOISE, 33, 1, NA, "birds chirping."); + addot(OT_TREEUP, "hollow tree leading up", "A huge hollow tree containing an ascending staircase.", MT_DRAGONWOOD, 3000, OC_DFEATURE, SZ_HUGE); + addflag(lastot->flags, F_GLYPH, C_BROWN, '<', NA, NULL); + addflag(lastot->flags, F_CLIMBABLE, D_UP, NA, NA, "hollow tree"); + addflag(lastot->flags, F_OPPOSITESTAIRS, OT_TREEDOWN, NA, NA, NULL); + addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); + addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); + addot(OT_TUNNELDOWN, "tunnel leading down", "A wide tunnel leading downwards.", MT_STONE, 3000, OC_DFEATURE, SZ_HUGE); addflag(lastot->flags, F_GLYPH, C_BROWN, '>', NA, NULL); addflag(lastot->flags, F_CLIMBABLE, D_DOWN, NA, NA, "tunnel"); @@ -1982,6 +1999,7 @@ void initobjects(void) { // rocks addot(OT_BOULDER, "boulder", "A massive stone boulder.", MT_STONE, 80, OC_ROCK, SZ_HUGE); addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_COMMON, NULL); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_GLYPH, NA, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); @@ -2005,8 +2023,9 @@ void initobjects(void) { addflag(lastot->flags, F_OBHP, 80, 80, NA, NULL); addot(OT_STATUE, "statue", "A stone statue of a monster.", MT_STONE, 80, OC_ROCK, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 75, NA, ""); - addflag(lastot->flags, F_RARITY, H_VILLAGE, 80, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, ""); + addflag(lastot->flags, F_RARITY, H_VILLAGE, NA, RR_COMMON, ""); + addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_RARE, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); addflag(lastot->flags, F_GLYPH, NA, '\'', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_LARGE, NA, NULL); // will be overridden @@ -2019,8 +2038,9 @@ void initobjects(void) { addflag(lastot->flags, F_FEELTEXT, NA, NA, NA, "a statue"); addot(OT_STONE, "stone", "A medium-sized roundish stone.", MT_STONE, 0.5, OC_ROCK, SZ_TINY); addflag(lastot->flags, F_STACKABLE, B_TRUE, NA, NA, ""); - addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, NA, ""); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, ""); addflag(lastot->flags, F_RARITY, H_CAVE, NA, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_FOREST, NA, RR_COMMON, ""); addflag(lastot->flags, F_NUMAPPEAR, 1, 10, NA, ""); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_DAMAGABLE, B_TRUE, NA, NA, NULL); @@ -3689,6 +3709,17 @@ void initobjects(void) { addflag(lastot->flags, F_CASTINGTIME, 2, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_PLEASESGOD, R_GODNATURE, 5, NA, NULL); + // l6 + addot(OT_S_ANIMATETREE, "animate tree", "Imbues a nearby tree with the power of life, turning it into a powerful treant.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_NATURE, NA, NA, NULL); + addflag(lastot->flags, F_TARGETTEDSPELL, TT_OBJECT, NA, NA, NULL); + addflag(lastot->flags, F_RANGE, 1, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 6, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); + addflag(lastot->flags, F_AICASTTOATTACK, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_AICASTTOFLEE, ST_SPECIAL, NA, NA, NULL); + addflag(lastot->flags, F_PLEASESGOD, R_GODNATURE, 25, NA, NULL); /////////////////// // life spells / cleric spells /////////////////// @@ -4165,10 +4196,15 @@ void initobjects(void) { addflag(lastot->flags, F_AICASTTOFLEE, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_AICASTTOATTACK, ST_VICTIM, NA, NA, NULL); addflag(lastot->flags, F_LOSLOF, B_TRUE, LOF_DONTNEED, NA, NULL); - // l5 addot(OT_S_GATE, "gate", "Creates a portal to a different dungeon level (within ^bpower^n*2 levels).", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); + addflag(lastot->flags, F_SPELLLEVEL, 4, NA, NA, NULL); + // l5 + addot(OT_S_TRAVEL, "travel", "Instantly teleports the caster to the start of a given dungeon branch.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); + addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); addflag(lastot->flags, F_SPELLLEVEL, 5, NA, NA, NULL); + addflag(lastot->flags, F_MAXPOWER, 1, NA, NA, NULL); + addflag(lastot->flags, F_LOSLOF, B_FALSE, LOF_DONTNEED, NA, NULL); // l6 addot(OT_S_PLANESHIFT, "planeshift", "Instantly transports the caster to a different plane of existence.", MT_NOTHING, 0, OC_SPELL, SZ_TINY); addflag(lastot->flags, F_SPELLSCHOOL, SS_TRANSLOCATION, NA, NA, NULL); @@ -5429,7 +5465,7 @@ void initobjects(void) { addflag(lastot->flags, F_HELPSREST, 15, 1, NA, NULL); addot(OT_BOOKSHELF, "bookshelf", "A set of wooden shelves, sized for book storage.", MT_WOOD, 150, OC_FURNITURE, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_ALL, 100, RR_RARE, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, 100, RR_RARE, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, '\\', NA, NULL); addflag(lastot->flags, F_NOBLESS, B_TRUE, NA, NA, NULL); addflag(lastot->flags, F_NOPICKUP, B_TRUE, NA, NA, NULL); @@ -5526,7 +5562,7 @@ void initobjects(void) { addflag(lastot->flags, F_STARTOBCLASS, 50, OC_FOOD, NA, NULL); addot(OT_WOODENTABLE, "wooden table", "A waist-height wooden table.", MT_WOOD, 25, OC_FURNITURE, SZ_HUMAN); - addflag(lastot->flags, F_RARITY, H_ALL, 70, RR_COMMON, NULL); + addflag(lastot->flags, F_RARITY, H_DUNGEON, NA, RR_COMMON, NULL); addflag(lastot->flags, F_GLYPH, C_BROWN, '\\', NA, NULL); addflag(lastot->flags, F_IMPASSABLE, SZ_MIN, SZ_HUMAN, NA, NULL); addflag(lastot->flags, F_CRUSHABLE, SZ_LARGE, NA, NA, NULL); @@ -8394,7 +8430,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_WIS, AT_VLOW, NA, NULL); addflag(lastrace->flags, F_STARTATT, A_CHA, AT_LOW, NA, NULL); addflag(lastrace->flags, F_HITDICE, 0, 1, NA, NULL); - addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 4, NA, NA, NULL); addflag(lastrace->flags, F_DOESNTMOVE, B_TRUE, NA, B_TRUE, NULL); addflag(lastrace->flags, F_NOPRINTS, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_MOVESPEED, SP_NORMAL, NA, NA, NULL); @@ -9453,6 +9489,124 @@ void initrace(void) { addflag(lastrace->flags, F_MORALE, 10, NA, NA, NULL); addflag(lastrace->flags, F_EATCONFER, F_VISRANGEMOD, 1, NA, "50"); + addrace(R_TREANTYOUNG, "treant youngling", 500, 'T', C_BROWN, MT_WOOD, RC_HUMANOID, "Treants are huge living trees, with humanoid facial features visible on their trunks."); + setbodytype(lastrace, BT_HUMANOID); + setbodypartname(lastrace, BP_HEAD, "face"); + setbodypartname(lastrace, BP_BODY, "trunk"); + setbodypartname(lastrace, BP_NECK, "trunk"); + setbodypartname(lastrace, BP_SHOULDERS, "trunk"); + setbodypartname(lastrace, BP_HANDS, "branches"); + setbodypartname(lastrace, BP_RIGHTFINGER, "right branch"); + setbodypartname(lastrace, BP_LEFTFINGER, "left branch"); + setbodypartname(lastrace, BP_LEGS, "roots"); + setbodypartname(lastrace, BP_FEET, "roots"); + addflag(lastrace->flags, F_CORPSETYPE, NA, NA, NA, "tree"); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_SIZE, SZ_LARGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 7, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 7, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_SLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 12, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_LIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); + + addrace(R_TREANT, "treant", 700, 'T', C_GREEN, MT_WOOD, RC_HUMANOID, "Treants are huge living trees, with humanoid facial features visible on their trunks."); + setbodytype(lastrace, BT_HUMANOID); + setbodypartname(lastrace, BP_HEAD, "face"); + setbodypartname(lastrace, BP_BODY, "trunk"); + setbodypartname(lastrace, BP_NECK, "trunk"); + setbodypartname(lastrace, BP_SHOULDERS, "trunk"); + setbodypartname(lastrace, BP_HANDS, "branches"); + setbodypartname(lastrace, BP_RIGHTFINGER, "right branch"); + setbodypartname(lastrace, BP_LEFTFINGER, "left branch"); + setbodypartname(lastrace, BP_LEGS, "roots"); + setbodypartname(lastrace, BP_FEET, "roots"); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_SIZE, SZ_HUGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 9, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 9, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_VERYSLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 16, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_LIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); + + addrace(R_TREANTOLD, "treant elder", 900, 'T', C_BOLDGREEN, MT_WOOD, RC_HUMANOID, "Treants are huge living trees, with humanoid facial features visible on their trunks."); + setbodytype(lastrace, BT_HUMANOID); + setbodypartname(lastrace, BP_HEAD, "face"); + setbodypartname(lastrace, BP_BODY, "trunk"); + setbodypartname(lastrace, BP_NECK, "trunk"); + setbodypartname(lastrace, BP_SHOULDERS, "trunk"); + setbodypartname(lastrace, BP_HANDS, "branches"); + setbodypartname(lastrace, BP_RIGHTFINGER, "right branch"); + setbodypartname(lastrace, BP_LEFTFINGER, "left branch"); + setbodypartname(lastrace, BP_LEGS, "roots"); + setbodypartname(lastrace, BP_FEET, "roots"); + addflag(lastrace->flags, F_ALIGNMENT, AL_GOOD, NA, NA, NULL); + addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_VERYRARE, 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_SIZE, SZ_HUGE, NA, NA, NULL); + addflag(lastrace->flags, F_HITDICE, 9, NA, NA, NULL); + addflag(lastrace->flags, F_TR, 11, NA, NA, NULL); + addflag(lastrace->flags, F_EVASION, -20, NA, NA, NULL); + addflag(lastrace->flags, F_MOVESPEED, SP_ULTRASLOW, NA, NA, NULL); + addflag(lastrace->flags, F_ACTIONSPEED, SP_ULTRASLOW, NA, NA, NULL); + addflag(lastrace->flags, F_HASATTACK, OT_FISTS, 20, NA, NULL); + addflag(lastrace->flags, F_NOSLEEP, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOINJURIES, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_WATER, NA, NA, NULL); + addflag(lastrace->flags, F_DTIMMUNE, DT_LIGHT, NA, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_STR, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_IQ, AT_GTAVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_AGI, AT_LOW, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CON, AT_VHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_WIS, AT_EXHIGH, NA, NULL); + addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); + addflag(lastrace->flags, F_STARTSKILL, SK_PERCEPTION, PR_MASTER, NA, NULL); + addflag(lastrace->flags, F_CANCAST, OT_S_ANIMATETREE, 25, 25, "pw:1;"); + addflag(lastrace->flags, F_CASTCHANCE, 40, NA, NA, NULL); + addflag(lastrace->flags, F_SPELLCASTTEXT, OT_S_ANIMATETREE, NA, NA, "waves its branches"); + addflag(lastrace->flags, F_AWARENESS, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_NOISETEXT, N_GETANGRY, 4, NA, "bellows^a bellow"); + addflag(lastrace->flags, F_HUMANOID, B_TRUE, NA, NA, NULL); + addflag(lastrace->flags, F_MORALE, 20, NA, NA, NULL); + addrace(R_GIANTHILL, "mountain giant", 160, 'H', C_GREY, MT_FLESH, RC_HUMANOID, "Enormous humanoids who dwell in the mountains, using their grat strength to leap between valleys and pelt their prey with enormous boulders."); setbodytype(lastrace, BT_HUMANOID); addflag(lastrace->flags, F_ALIGNMENT, AL_EVIL, NA, NA, NULL); @@ -11269,7 +11423,7 @@ void initrace(void) { addflag(lastrace->flags, F_STARTATT, A_CHA, AT_AVERAGE, NA, NULL); addflag(lastrace->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); addflag(lastrace->flags, F_RARITY, H_DUNGEON, NA, RR_UNCOMMON, NULL); - addflag(lastrace->flags, F_RARITY, H_FOREST, NA, RR_FREQUENT, NULL); + addflag(lastrace->flags, F_RARITY, H_SWAMP, NA, RR_RARE, NULL); addflag(lastrace->flags, F_SIZE, SZ_SMALL, NA, NA, NULL); addflag(lastrace->flags, F_HITDICE, 2, NA, NA, NULL); addflag(lastrace->flags, F_TR, 2, NA, NA, NULL); @@ -15574,6 +15728,7 @@ void initrace(void) { addflag(r->flags, F_RESISTMAG, 15, NA, NA, NULL); addflag(r->flags, F_MEDITATES, B_TRUE, NA, NA, NULL); addflag(r->flags, F_SEEINDARK, 10, NA, NA, NULL); + addflag(r->flags, F_SEEINVIS, B_TRUE, NA, NA, NULL); addflag(r->flags, F_CANWILL, OT_S_PLANESHIFT, NA, NA, "pw:1;"); } else if (r->raceclass->id == RC_MAGIC) { addflag(r->flags, F_DISEASEIMMUNE, B_TRUE, NA, NA, NULL); diff --git a/data/hiscores.db b/data/hiscores.db index 9c8fdc0..5478c6b 100644 Binary files a/data/hiscores.db and b/data/hiscores.db differ diff --git a/data/vaults/antnest.vlt b/data/vaults/antnest.vlt index 8ae6968..f12b3f9 100644 --- a/data/vaults/antnest.vlt +++ b/data/vaults/antnest.vlt @@ -21,6 +21,7 @@ scatter(3,1,-4,-2) ob:random food:7-10 scatter(3,1,-4,-2) mon:queen ant:1:100 scatter(2,1,-2,-2) cell:dirt wall:5-6 goesin:dungeon +goesin:forest goesin:cave mayrotate rarity:uncommon diff --git a/data/vaults/bazaar.vlt b/data/vaults/bazaar.vlt index 3c64650..4454249 100644 --- a/data/vaults/bazaar.vlt +++ b/data/vaults/bazaar.vlt @@ -19,6 +19,7 @@ X:exit @flags goesin:dungeon +goesin:forest mayrotate rarity:vrare maintainedge diff --git a/data/vaults/cave_bear.vlt b/data/vaults/cave_bear.vlt index 095ed75..9658520 100644 --- a/data/vaults/cave_bear.vlt +++ b/data/vaults/cave_bear.vlt @@ -10,7 +10,7 @@ @end @legend -#:cell:SOLID +#:cell:dirt wall O:ob:boulder O:exit B:mon:grizzly bear @@ -21,6 +21,7 @@ scatter(3,1,-4,-2) ob:random food:5-10 scatter(3,1,-4,-2) mon:bear cub:1-3:50 goesin:dungeon goesin:cave +goesin:forest mayrotate rarity:uncommon maintainedge diff --git a/data/vaults/cave_troll.vlt b/data/vaults/cave_troll.vlt index 216786d..5314fb0 100644 --- a/data/vaults/cave_troll.vlt +++ b/data/vaults/cave_troll.vlt @@ -21,6 +21,7 @@ scatter(3,1,-4,-2) ob:bone:3-5 scatter(3,1,-4,-2) mon:random troll:2-4:100 goesin:dungeon goesin:cave +goesin:forest mayrotate rarity:veryrare maintainedge diff --git a/data/vaults/cell.vlt b/data/vaults/cell.vlt index b79db60..c9d91b8 100644 --- a/data/vaults/cell.vlt +++ b/data/vaults/cell.vlt @@ -7,13 +7,14 @@ @end @legend -#:cell:SOLID +#:cell:brick wall m:mon:sleeping random +:ob:locked iron gate @end @flags goesin:dungeon +goesin:forest mayrotate rarity:uncommon maintainedge diff --git a/data/vaults/chasm.vlt b/data/vaults/chasm.vlt index e4227f9..9c09f2f 100644 --- a/data/vaults/chasm.vlt +++ b/data/vaults/chasm.vlt @@ -14,6 +14,7 @@ @flags goesin:dungeon +goesin:forest mayrotate autopop rarity:uncommon diff --git a/data/vaults/grove.vlt b/data/vaults/grove.vlt index 3b31866..87a4478 100644 --- a/data/vaults/grove.vlt +++ b/data/vaults/grove.vlt @@ -9,6 +9,7 @@ random(5,5) @flags goesin:dungeon +goesin:forest autodoors:25 autopop entertext:You enter a small shrubbery. diff --git a/data/vaults/island.vlt b/data/vaults/island.vlt index 88309a9..de24ec9 100644 --- a/data/vaults/island.vlt +++ b/data/vaults/island.vlt @@ -19,6 +19,7 @@ c:ob:chest @flags goesin:dungeon +goesin:forest autodoors:50 autopop rarity:uncommon diff --git a/data/vaults/smalllake.vlt b/data/vaults/smalllake.vlt index 430d269..f0f29fd 100644 --- a/data/vaults/smalllake.vlt +++ b/data/vaults/smalllake.vlt @@ -13,6 +13,7 @@ w:ob:very deep water @flags goesin:cave +goesin:forest autopop rarity:common @end diff --git a/data/vaults/supplycloset.vlt b/data/vaults/supplycloset.vlt index 8290047..674ef7d 100644 --- a/data/vaults/supplycloset.vlt +++ b/data/vaults/supplycloset.vlt @@ -20,5 +20,6 @@ o:ob:random tool:50 goesin:dungeon rarity:uncommon maintainedge +mayrotate @end diff --git a/data/vaults/supplycloset_tech.vlt b/data/vaults/supplycloset_tech.vlt index 98026e9..5fa58ea 100644 --- a/data/vaults/supplycloset_tech.vlt +++ b/data/vaults/supplycloset_tech.vlt @@ -20,5 +20,6 @@ o:ob:random technology:50 goesin:dungeon rarity:uncommon maintainedge +mayrotate @end diff --git a/data/vaults/woodhut.vlt b/data/vaults/woodhut.vlt index e4705bc..a82c40c 100644 --- a/data/vaults/woodhut.vlt +++ b/data/vaults/woodhut.vlt @@ -21,6 +21,7 @@ scatter(2,1,-2,-2) mon:random:1 scatter(2,1,-2,-2) ob:furniture:1-2 mayrotate goesin:cave +goesin:forest rarity:common @end diff --git a/defs.h b/defs.h index 700f11f..cb272ed 100644 --- a/defs.h +++ b/defs.h @@ -198,14 +198,18 @@ #define MAXVISLIMIT (MAXVISRANGE*20) #define MAX_EYEADJ 20 -#define MINCLEARINGRADIUS 2 -#define MAXCLEARINGRADIUS 5 - +#define MINCLEARINGRADIUS 4 +#define MAXCLEARINGRADIUS 7 #define MAX_ATTRIBVAL 100 #define MAXMAPROOMS 80 + +// note: -1 is treated as zero +#define MINROOMS_WOODS -1 +#define MAXROOMS_WOODS 3 + #define MINROOMS 5 #define MAXROOMS 10 #define MIN_ROOMH 4 @@ -776,6 +780,7 @@ enum CELLTYPE { CT_WALLFLESH, CT_WALLGLASS, CT_WALLMETAL, + CT_WALLTREE, CT_WALLWOOD, // empty CT_CORRIDOR, @@ -1045,6 +1050,9 @@ enum RACE { R_SPRITEFIRE, R_SPRITEGRAVE, R_SPRITEICE, + R_TREANTYOUNG, + R_TREANT, + R_TREANTOLD, R_TRICLOPS, R_TROGLODYTE, R_TROLL, @@ -1293,6 +1301,8 @@ enum OBTYPE { OT_HOLEINROOF, OT_STAIRSDOWN, OT_STAIRSUP, + OT_TREEDOWN, + OT_TREEUP, OT_TUNNELDOWN, OT_TUNNELUP, OT_PORTAL, @@ -1621,6 +1631,7 @@ enum OBTYPE { OT_S_SIZEUP, OT_S_SIZEDOWN, // nature / enviromancy + OT_S_ANIMATETREE, OT_S_BARKSKIN, OT_S_CALLLIGHTNING, OT_S_CALLWIND, @@ -1675,6 +1686,7 @@ enum OBTYPE { OT_S_PLANESHIFT, OT_S_SUCK, OT_S_TELEPORT, + OT_S_TRAVEL, OT_S_TWIDDLE, // -- wild OT_S_ALARM, @@ -2276,6 +2288,7 @@ enum ANIMALTYPE { enum FLAG { F_NONE = 0, // dummy flag // map flags + F_FIRSTINBRANCH, // this map is the first level in its branch F_MAPCOORDS, // v0+v1 are x/y coords for this map area F_MAPSHAPE, // v0 = enum MAPSHAPE F_ROOMEXIT, // there is an exit from room v0 at x=v1,y=v2 @@ -2285,6 +2298,8 @@ enum FLAG { F_CELLTYPESOLID, // use celltype v0 for solid cells (walls) F_CELLTYPEEMPTY, // use celltype v0 for empty cells (corridors/rooms) // object flags + F_GODSTONE, // this is a godstone. + // if v2 = TRUE, means we need to warn when we walk onto it. F_BADOBJECT, // this object is dangerous. ie. potion of poison, // potion of sleep, etc. F_BATTLESPOILS, // this obejct was dropped by a monster which the @@ -2562,7 +2577,7 @@ enum FLAG { // stairs / teleporters / portals F_CLIMBABLE, // this is a stiarcase, v0 = up/down/in // also use this for portals - // text = you climb down XXXX + // text = you climb down a/an XXXX // OPTIONAL v1 = id of region to link to. F_PIT, // this is a pit which we can fall down. // v0 = up/down @@ -3818,6 +3833,7 @@ enum REGIONTYPE { RG_PIT, RG_SEWER, RG_STOMACH, + RG_WOODS, }; enum HABITAT { diff --git a/doc/add_regiontype.txt b/doc/add_regiontype.txt index f8368a2..eaf9964 100644 --- a/doc/add_regiontype.txt +++ b/doc/add_regiontype.txt @@ -7,4 +7,5 @@ map.c: create new habitats if required. +text.c: update getregionname() diff --git a/god.c b/god.c index 781a885..c4d32e7 100644 --- a/god.c +++ b/god.c @@ -468,7 +468,7 @@ void angergod(enum RACE rid, int amt, enum GODANGERREASON why) { // damage it getobname(o, obname, o->amt); msg("Your %s %s struck by divine force!", OB1(o, "is", "are"), noprefix(obname)); - takedamage(o, roll("2d4"), DT_DIRECT); + takedamage(o, rnd(10,40), DT_DIRECT); } break; case 2: diff --git a/io.c b/io.c index e9b5c62..1f1120a 100644 --- a/io.c +++ b/io.c @@ -4234,6 +4234,10 @@ void docomms(lifeform_t *lf) { getobname(o, buf, count); givemoney(player, lf, count); msg("You give %s to %s.", buf, lfname); + } else if (isgod(lf) && (o->type->obclass->id == OC_GODSTONE)) { + getobname(o, buf, o->amt); + msg("You offer %s to %s.", buf, lfname); + givenob = o; } else { givenob = moveob(o, lf->pack, count); if (givenob) { @@ -6365,7 +6369,7 @@ char *makedesc_ob(object_t *o, char *retbuf) { // if known, show what it confers for (f = o->flags->first ; f ; f = f->next) { if ((f->id == F_HOLDCONFER) || (f->id == F_EQUIPCONFER) || (f->id == F_ACTIVATECONFER)) { - if (obknown) { + if (obknown && f->known) { objecttype_t *ot; if (f->id == F_HOLDCONFER) strcpy(buf, "When held, it"); else if (f->id == F_ACTIVATECONFER) strcpy(buf, "When activated, it"); diff --git a/lf.c b/lf.c index dcebb8e..535dd50 100644 --- a/lf.c +++ b/lf.c @@ -18644,13 +18644,18 @@ void startlfturn(lifeform_t *lf) { int dir,chance; if (piety < 100) { dir = 1; + chance = piety; + limit(&chance, 10, 100); } else { dir = -1; + chance = 100 - (piety-200); // ie. 100 max + limit(&chance, 10, 50); } - chance = abs(piety) / 100; - if (onein(chance)) { - // slowly move towards zero - modpiety(godlf[i]->race->id, (piety < 0) ? 1 : -1); + // the further away from neutral you are, the less chance + // piety/anger has of 'expiring' + if (pctchance(chance)) { + // slowly move towards normal + modpiety(godlf[i]->race->id, dir); } } } @@ -19344,6 +19349,17 @@ void startlfturn(lifeform_t *lf) { continue; } + f = hasflag(o->flags, F_GODSTONE); + if (f && (f->val[2] == B_TRUE)) { + flag_t *f2; + lifeform_t *god; + // warn! + f2 = hasflag(o->flags, F_LINKGOD); + god = findgod(f2->val[0]); + godsay(god->id, B_TRUE, "Mortal! Do not touch that!"); more(); + f->val[2] = B_FALSE; + } + f = hasflag(o->flags, F_WALKDAM); if (f) { applywalkdam(lf, roll(f->text), f->val[0], o); diff --git a/map.c b/map.c index a2a7233..944a061 100644 --- a/map.c +++ b/map.c @@ -666,6 +666,7 @@ int getmapmaxvisrange(map_t *m) { } else if (m->habitat->id == H_DUNGEON) { // in dungeon, reduce distance based on depth (ie. ambient light) maxrange -= m->depth; + limit(&maxrange, 1, NA); } limit(&maxrange, 0, MAXVISRANGE); @@ -1667,6 +1668,34 @@ void floodfill(cell_t *startcell) { } } +// populates thing & nthings with all "regionthings" with +// whatkind == RT_REGIONLINK. +// ie. links to all the map branches. +// returns # found +int getbranchlinks(regionthing_t **thing, int *nthings) { + int i; + region_t *r; + regionthing_t *temp; + + *nthings = 0; + for (r = firstregion ; r ; r = r->next) { + if (!r->outline) continue; + for (i = 0; i < r->outline->nthings; i++ ){ + // pick a random regionlink thing. + temp = &r->outline->thing[i]; + if (temp->whatkind == RT_REGIONLINK) { + regiontype_t *rtype; + rtype = findregiontype(temp->value); + if ( (rtype->id != RG_MAINDUNGEON) && + (rtype->id != RG_WORLDMAP)) { + thing[(*nthings)++] = temp; + } + } + } + } + return *nthings; +} + cell_t *getcellat(map_t *map, int x, int y) { if (!isonmap(map, x, y)) return NULL; return map->cell[y*map->w + x]; @@ -1987,6 +2016,7 @@ void calclight(map_t *map) { int radius; object_t *o; + /* // lit based on depth if (isoutdoors(map)) { int hours,mins,secs; @@ -1997,11 +2027,11 @@ void calclight(map_t *map) { // ie. daytime makelit(c, L_PERMLIGHT, -1); } - } else { + } + */ //if ((map->depth <= 5) && (c->lit != L_PERMDARK)) { - if ((map->illumination == IL_FULLLIT) && (c->lit != L_PERMDARK)) { - makelit(c, L_PERMLIGHT, -1); - } + if ((map->illumination == IL_FULLLIT) && (c->lit != L_PERMDARK)) { + makelit(c, L_PERMLIGHT, -1); } // TODO: has dark producing lf? @@ -2369,6 +2399,37 @@ int countstairs(map_t *m, int dir) { return count; } +void createborder(map_t *map, enum CELLTYPE solidtype) { + int x,y; + cell_t *c; + // now do a border + y = 0; + for (x = 0; x < map->w; x++) { + // n + c = getcellat(map, x, 0); + clearcell(c); + setcelltype(c,solidtype); + c->locked = B_TRUE; + // s + c = getcellat(map, x, map->h-1); + clearcell(c); + setcelltype(c,solidtype); + c->locked = B_TRUE; + } + for (y = 1; y < map->h-1; y++) { + // w + c = getcellat(map, 0, y); + clearcell(c); + setcelltype(c,solidtype); + c->locked = B_TRUE; + // e + c = getcellat(map, map->w-1, y); + clearcell(c); + setcelltype(c,solidtype); + c->locked = B_TRUE; + } +} + void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) { int wantrooms = B_TRUE; int x,y,i; @@ -2462,31 +2523,7 @@ void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t * */ // now do a border - y = 0; - for (x = 0; x < map->w; x++) { - // n - c = getcellat(map, x, 0); - clearcell(c); - setcelltype(c,solidcell); - c->locked = B_TRUE; - // s - c = getcellat(map, x, map->h-1); - clearcell(c); - setcelltype(c,solidcell); - c->locked = B_TRUE; - } - for (y = 1; y < map->h-1; y++) { - // w - c = getcellat(map, 0, y); - clearcell(c); - setcelltype(c,solidcell); - c->locked = B_TRUE; - // e - c = getcellat(map, map->w-1, y); - clearcell(c); - setcelltype(c,solidcell); - c->locked = B_TRUE; - } + createborder(map, solidcell); } // void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob) { @@ -3019,6 +3056,7 @@ void createfakes(map_t *map, cell_t *cell) { void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob, int nclearings) { int x,y; enum CELLTYPE emptycell; + enum CELLTYPE solidcell; int i; int ntrees; int density; @@ -3026,14 +3064,17 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t char buf[BUFLEN]; cell_t *retcell[MAXCANDIDATES]; int nretcells; + int numrooms = 0; //object_t *o; // fill entire maze with emptiness emptycell = getmapempty(map); + solidcell = getmapsolid(map); + for (y = 0; y < map->h; y++) { for (x = 0; x < map->w; x++) { c = addcell(map, x, y); - setcelltype(c, emptycell); + setcelltype(c, onein(4) ? CT_DIRT : emptycell ); } } @@ -3047,11 +3088,17 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t for (i = 0; i < ntrees; i++) { c = getrandomcell(map); while (c->lf) c = getrandomcell(map); - switch (rnd(0,1)) { - default: case 0: strcpy(buf, "tree"); break; - case 1: strcpy(buf, "shrub"); break; + if (onein(2)) { + killallobs(c->obpile); + setcelltype(c, solidcell); + } else { + setcelltype(c, onein(2) ? emptycell : CT_DIRT); + switch (rnd(0,1)) { + default: case 0: strcpy(buf, "tree"); break; + case 1: strcpy(buf, "shrub"); break; + } + addob(c->obpile, buf); } - addob(c->obpile, buf); } // clearings for (i = 0; i < nclearings; i++) { @@ -3061,6 +3108,7 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t // clear obs in all clearing cells getradiuscells(c, w, DT_ORTH, B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, B_FALSE); for (n = 0; n < nretcells; n++) { + setcelltype(c, emptycell); // kill all obs here while (retcell[n]->obpile->first) killob(retcell[n]->obpile->first); } @@ -3073,7 +3121,7 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t } break; case 2: // add clusters of trees - nclearings = rnd(5,10); + nclearings = rnd(10,15); for (i = 0; i < nclearings; i++) { int w,n; c = getrandomcell(map); @@ -3083,15 +3131,31 @@ void createforest(map_t *map, int depth, map_t *parentmap, int exitdir, object_t getradiuscells(c, w, DT_ORTH, B_FALSE, LOF_DONTNEED, B_TRUE, retcell, &nretcells, 80); for (n = 0; n < nretcells; n++) { - switch (rnd(0,1)) { - default: case 0: strcpy(buf, "tree"); break; - case 1: strcpy(buf, "shrub"); break; + if (onein(2)) { + killallobs(retcell[n]->obpile); + setcelltype(retcell[n], solidcell); + } else { + setcelltype(retcell[n], onein(2) ? emptycell : CT_DIRT); + switch (rnd(0,1)) { + default: case 0: strcpy(buf, "tree"); break; + case 1: strcpy(buf, "shrub"); break; + } + addob(retcell[n]->obpile, buf); } - addob(retcell[n]->obpile, buf); } } break; } + + // random vaults + numrooms = rnd(MINROOMS_WOODS, MAXROOMS_WOODS); + for (i = 0; i < numrooms; i++) { + vault_t *v; + v = getvaulttype(map); + createvault(map, map->nrooms, v, NULL, NULL, NULL, NULL); + } + + createborder(map, CT_WALLTREE); } @@ -5220,6 +5284,12 @@ void finalisemap(map_t *map, object_t *entryob) { nupstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, upstairtype); ndownstairsneeded = map->region->rtype->stairsperlev - countmapobs(map, downstairtype); + // override # up stairs for first level of a branch. + if (hasflag(map->flags, F_FIRSTINBRANCH)) { + nupstairsneeded = 1; + } + + if ( (nupstairsneeded && (upstairtype == OT_NONE)) || (ndownstairsneeded && (downstairtype == OT_NONE)) ) { dblog("ERROR - need up/down stairs, but no stairtype defined for habitat %s!", map->habitat->name); @@ -5266,6 +5336,7 @@ void finalisemap(map_t *map, object_t *entryob) { if (!c) { // ANY cell at all, doesn't have to be a room. c = getrandomcell(map); + c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); } } o = addobfast(c->obpile, upstairtype); @@ -5279,7 +5350,9 @@ void finalisemap(map_t *map, object_t *entryob) { } } // make sure we have at least one up stairs - assert(findobinmap(map, upstairtype)); + if (map->region->rtype->id != RG_WORLDMAP) { + assert(findobinmap(map, upstairtype)); + } } // DOWN STAIRS @@ -5291,6 +5364,7 @@ void finalisemap(map_t *map, object_t *entryob) { if (!c) { // ANY cell at all, doesn't have to be a room. c = getrandomcell(map); + c = getrandomadjcell(c, WE_WALKABLE, B_ALLOWEXPAND); } } o = addobfast(c->obpile, downstairtype); @@ -6337,6 +6411,7 @@ cell_t *getstairdestination(object_t *o, int *madenewmap) { // first map of a newly created region? if (newregion->id != curmap->region->id) { newdepth = 1; + addflag(newmap->flags, F_FIRSTINBRANCH, B_TRUE, NA, NA, NULL); } createmap(newmap, newdepth, newregion, curmap, dir, o); // at this point, stairs should have a destination (map creation will @@ -6430,7 +6505,7 @@ void initmap(void) { // thingchance, obchance, vaultchance, maxvisrange, upstiartype, downstairtype addhabitat(H_DUNGEON, "dungeon", CT_CORRIDOR, CT_WALL, 3, 50, 30, 6, OT_STAIRSUP, OT_STAIRSDOWN); addhabitat(H_CAVE, "cave", CT_DIRT, CT_WALLDIRT, 5, 65, 10, 6, OT_TUNNELUP, OT_TUNNELDOWN); - addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALL, 3, 75, 0, MAXVISRANGE, OT_NONE, OT_NONE); + addhabitat(H_FOREST, "forest", CT_GRASS, CT_WALLTREE, 3, 75, 0, MAXVISRANGE, OT_TREEUP, OT_TREEDOWN); addhabitat(H_HEAVEN, "heaven", CT_CORRIDOR, CT_WALLGLASS, 5, 0, 0, MAXVISRANGE, OT_NONE, OT_NONE); addhabitat(H_PIT, "pit", CT_CORRIDOR, CT_WALL, 0, 0, 0, 5, OT_NONE, OT_NONE); addhabitat(H_VILLAGE, "village", CT_GRASS, CT_WALL, 3, 70, 0, MAXVISRANGE, OT_NONE, OT_NONE); @@ -6446,6 +6521,7 @@ void initmap(void) { addcelltype(CT_WALLWOOD, "wooden wall", UNI_SOLID, C_BROWN, B_SOLID, B_OPAQUE, MT_WOOD, 0, 30); addcelltype(CT_WALLFLESH, "flesh wall", UNI_SOLID, C_RED, B_SOLID, B_OPAQUE, MT_FLESH, 0, 25); addcelltype(CT_WALLGLASS, "glass wall", UNI_SOLID, C_CYAN, B_SOLID, B_TRANS, MT_GLASS, 0, 20); + addcelltype(CT_WALLTREE, "dense bushland", UNI_SHADEDARK, C_GREEN, B_SOLID, B_OPAQUE, MT_PLANT, 0, 100); addcelltype(CT_WALLMETAL, "metal wall", UNI_SOLID, C_WHITE, B_SOLID, B_OPAQUE, MT_METAL, 0, 75); // cell types - non-solid addcelltype(CT_FAKE, "fake cell", '.', C_GREEN, B_EMPTY, B_TRANS, MT_STONE, 0, -1); @@ -6462,12 +6538,15 @@ void initmap(void) { addcelltype(CT_VLOWFLOOR, "very low rock floor", '.', C_GREY, B_EMPTY, B_TRANS, MT_STONE, -2, -1); // region types - // maxdepth stairs stair major? depthmod + // name, pluralname?, defaulthab, maxdepth stairs stair major? depthmod // perlev dir addregiontype(RG_WORLDMAP, "The Surface", B_FALSE, H_FOREST, 10, 0, D_NONE, B_TRUE, 0); + addregiontype(RG_HEAVEN, "The Realm of Gods", B_FALSE, H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0); + // main branches addregiontype(RG_MAINDUNGEON, "The Main Dungeon", B_FALSE, H_DUNGEON, 25, 3, D_DOWN, B_TRUE, 0); addregiontype(RG_CAVE, "The Goblin Caves", B_TRUE, H_CAVE, 5, 1, D_DOWN, B_TRUE, 2); - addregiontype(RG_HEAVEN, "The Realm of Gods", B_FALSE, H_HEAVEN, 1, 0, D_NONE, B_FALSE, 0); + addregiontype(RG_WOODS, "The Sylvan Woods", B_TRUE, H_FOREST, 5, 3, D_DOWN, B_TRUE, 1); + // minor branches addregiontype(RG_PIT, "A Pit", B_FALSE, H_PIT, 1, 1, D_DOWN, B_FALSE, 0); addregiontype(RG_SEWER, "A Sewer", B_FALSE, H_SEWER, 1, 0, D_NONE, B_FALSE, 2); addregiontype(RG_STOMACH, "A Stomach", B_FALSE, H_STOMACH, 1, 0, D_NONE, B_FALSE, 0); @@ -6512,7 +6591,9 @@ void initmaplayout(void) { addregionoutline(RG_MAINDUNGEON); addregionthing(lastregionoutline, 1, NA, NA, RT_RNDVAULTWITHFLAG, F_VAULTISPLAYERSTART, NULL); - // l2-4: goblin caves + // l2-4: sylvan woods + addregionthing(lastregionoutline, rnd(2,4), NA, NA, RT_REGIONLINK, RG_WOODS, "hollow tree leading down"); + // l2-5: goblin caves addregionthing(lastregionoutline, rnd(2,4), NA, NA, RT_REGIONLINK, RG_CAVE, "tunnel leading down"); // l6: jimbo's lair addregionthing(lastregionoutline, 6, NA, NA, RT_VAULT, NA, "jimbos_lair"); diff --git a/map.h b/map.h index c25f1a5..4752891 100644 --- a/map.h +++ b/map.h @@ -25,6 +25,7 @@ int doelementspread(cell_t *c); int fix_reachability(map_t *m); int fix_unreachable_cell(cell_t *badcell); void floodfill(cell_t *startcell); +int getbranchlinks(regionthing_t **thing, int *nthings); cell_t *getcellat(map_t *map, int x, int y); int getcellclimbdifficulty(cell_t *c); int getcellclimbdifficultyavg(cell_t *c); @@ -61,6 +62,7 @@ int countmapobs(map_t *m, enum OBTYPE oid); int countmapobswithflag(map_t *m, enum FLAG flagid); int countmapobswithflagval(map_t *m, enum FLAG flagid, int val0, int val1, int val2, char *text); int countstairs(map_t *m, int dir); +void createborder(map_t *map, enum CELLTYPE solidtype); void createcave(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createdungeon(map_t *map, int depth, map_t *parentmap, int exitdir, object_t *entryob); void createfakes(map_t *map, cell_t *cell); diff --git a/nexus.c b/nexus.c index b4aa88e..c5b3b23 100644 --- a/nexus.c +++ b/nexus.c @@ -1813,6 +1813,7 @@ void timeeffectsworld(map_t *map, int updategametime) { } } + /* // if it's the player's turn, announce sun set/rise if (isplayer(map->lf) && isoutdoors(map)) { int h,m,s; @@ -1823,6 +1824,7 @@ void timeeffectsworld(map_t *map, int updategametime) { msg("The sun is setting."); } } + */ if (db) dblog("cur time is %ld\n",curtime); } diff --git a/objects.c b/objects.c index ba87092..1ab2e0d 100644 --- a/objects.c +++ b/objects.c @@ -1647,25 +1647,11 @@ object_t *addobject(obpile_t *where, char *name, int canstack, int dolinks, enum char buf[BUFLEN]; // fill in map destination. if (!wantregionthing) { - region_t *r; - regionthing_t *rthing,*poss[MAXCANDIDATES]; - int nposs = 0,i; + regionthing_t *poss[MAXCANDIDATES]; + int nposs = 0; + + getbranchlinks(poss, &nposs); - for (r = firstregion ; r ; r = r->next) { - if (!r->outline) continue; - for (i = 0; i < r->outline->nthings; i++ ){ - // pick a random regionlink thing. - rthing = &r->outline->thing[i]; - if (rthing->whatkind == RT_REGIONLINK) { - regiontype_t *rtype; - rtype = findregiontype(rthing->value); - if ( (rtype->id != RG_MAINDUNGEON) && - (rtype->id != RG_WORLDMAP)) { - poss[nposs++] = rthing; - } - } - } - } if (nposs) { wantregionthing = poss[rnd(0,nposs-1)]; } @@ -6975,7 +6961,6 @@ int isknown(object_t *o) { return B_FALSE; } - return isknownot(o->type); } diff --git a/spell.c b/spell.c index c894a44..6506241 100644 --- a/spell.c +++ b/spell.c @@ -3534,7 +3534,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ if (haslos(player, caster->cell)) { msg("The pentagram pulses red."); } - if (summonlfs(caster, caster->cell, R_NONE, RC_DEMON, SZ_ANY, AL_NONE, 1, PERMENANT, B_FALSE)) { + if (summonlfs(caster, caster->cell, R_NONE, RC_DEMON, SZ_ANY, AL_NONE, 1, PERMENANT, B_MAYBE)) { if (isplayer(caster) || cansee(player, caster)) { msg("An other-worldly demon appears!"); } @@ -3873,8 +3873,10 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ msg("%s comes to life!",obname); if (seenbyplayer) *seenbyplayer = B_TRUE; } + addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL); if (caster) { petify(lf, caster); + addflag(lf->flags, F_SUMMONEDBY, caster->id, rnd(50,100), NA, NULL); } // no corpse after death (so you can't keep reanimating it) addflag(lf->flags, F_NOCORPSE, NA, NA, NA, NULL); @@ -3886,6 +3888,48 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ fizzle(caster); return B_TRUE; } + } else if (spellid == OT_S_ANIMATETREE) { + object_t *o; + + o = hasob(targcell->obpile, OT_TREE); + if (o) { + lifeform_t *lf = NULL; + char obname[BUFLEN]; + enum RACE rid; + // determine new race + switch (rnd(1,6)) { + case 1: + case 2: + case 3: + rid = R_TREANTYOUNG; + break; + case 4: + case 5: + rid = R_TREANT; + break; + case 6: + rid = R_TREANTOLD; + break; + } + getobname(o, obname, 1); + removeob(o, ALL); + lf = addmonster(targcell, rid, NULL, B_FALSE, 1, B_FALSE, NULL); + if (cansee(player, lf)) { + msg("%s comes to life!",obname); + if (seenbyplayer) *seenbyplayer = B_TRUE; + } + addflag(lf->flags, F_XPVAL, 0, NA, NA, NULL); + if (caster) { + petify(lf, caster); + addflag(lf->flags, F_SUMMONEDBY, caster->id, rnd(50,100), NA, NULL); + } + if (isplayer(caster)) { + angergodmaybe(R_GODFIRE, 50, GA_HERESY); + } + } else { + fizzle(caster); + return B_TRUE; + } } else if (spellid == OT_S_ANTICIPATE) { if (!target) target = targcell->lf; if (!target) { @@ -4285,7 +4329,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // outdoors? if (caster && (getraceclass(caster) == RC_GOD)) { losehp(target, rolldie(5,6), DT_ELECTRIC, caster, "a heavenly bolt of lightning"); - } else if (isoutdoors(target->cell->map)) { + } else if (target->cell->map->habitat->id == H_FOREST) { losehp(target, rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning"); } else { losehp(target, rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); @@ -6596,7 +6640,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_HAILSTORM) { int failed = B_FALSE; - if (caster && isoutdoors(caster->cell->map)) { + if (caster && (caster->cell->map->habitat->id == H_FOREST)) { power += 3; limit(&power, NA, 10); } @@ -7702,6 +7746,70 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ // 5 is the same as AT_VHIGH strength real_fireat(caster, targob, 1, targcell, 5, NULL, B_TRUE, spellid); + } else if (spellid == OT_S_TRAVEL) { + regionthing_t *poss[MAXCANDIDATES],*rt; + region_t *srcregion = NULL; + int nposs,i,depth; + char ch = 'a'; + cell_t *dstcell = NULL; + if (!isplayer(caster)) return B_TRUE; + // ask which region to go to + getbranchlinks(poss, &nposs); + if (!nposs) { + fizzle(caster); + return B_TRUE; + } + initprompt(&prompt, "Where do you wish to travel?"); + prompt.maycancel = B_TRUE; + + for (i = 0; i < nposs; i++) { + regiontype_t *destregiontype; + destregiontype = findregiontype(poss[i]->value); + + addchoice(&prompt, ch++, destregiontype->name, NULL, poss[i], NULL); + } + + ch = getchoice(&prompt); + rt = (regionthing_t *)prompt.result; + depth = rt->depth; + + // find region containing this link. + findregionthing(rt->id, &srcregion); + + if (srcregion) { + object_t *dstob = NULL; + region_t *destregion = NULL; + map_t *srcmap; + + if (isplayer(caster)) { + msg("There is a blinding flash of light..."); + wrefresh(msgwin); + } + + // does the map contining the link exist? + srcmap = findregionmap(srcregion->id, depth); + if (!srcmap) { + // we'll need to create the map. + srcmap = addmap(); + createmap(srcmap, depth, srcregion, NULL, D_NONE, NULL); + } + // find the regionlink object. ie. the stairs/portal which goes to + // the given region. + destregion = findregionbytype(rt->value); + + dstob = findmapobwithflagval(srcmap, F_CLIMBABLE, NA, destregion->id, NA, NULL); + assert(dstob); + dstcell = getoblocation(dstob); + } else { + msg("srcregion doesnt exist!"); + } + + if (dstcell) { + teleportto(caster, dstcell, B_FALSE); + } else { + fizzle(caster); + return B_TRUE; + } } else if (spellid == OT_S_PLANESHIFT) { map_t *m; target = caster; @@ -8596,7 +8704,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ getlfname(targ[i],targname); msg("%s %s struck by a bolt of lightning!",targname, is(targ[i])); } - if (isoutdoors(targ[i]->cell->map)) { + if (caster && (targ[i]->cell->map->habitat->id == H_FOREST)) { losehp(targ[i], rolldie(4,6), DT_ELECTRIC, caster, "a bolt of lightning"); } else { losehp(targ[i], rolldie(3,6), DT_ELECTRIC, caster, "a bolt of lightning"); @@ -8807,7 +8915,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ target = targcell->lf; - if (isoutdoors(targcell->map)) { + if (targcell->map->habitat->id == H_FOREST) { power += 5; limit(&power, NA, 10); } @@ -9878,7 +9986,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ } } else if (spellid == OT_S_SLEETSTORM) { int failed = B_FALSE; - if (isoutdoors(caster->cell->map)) { + if (caster && caster->cell->map->habitat->id == H_FOREST) { power += 3; limit(&power, NA, 10); } @@ -10874,7 +10982,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ enum LFSIZE wantsize; enum RACECLASS wantrc; enum RACE wantrace = R_NONE; - int friendly; + int friendly = B_MAYBE; char racename[BUFLEN]; lifeform_t *summoner = NULL; @@ -10894,7 +11002,7 @@ int dospelleffects(lifeform_t *caster, enum OBTYPE spellid, int power, lifeform_ wantsize = SZ_ANY; nwant = 8; successrate = 100; - friendly = B_FALSE; + friendly = B_MAYBE; break; case OT_S_HECTASSERVANT: wantrace = R_HECTASSERVANT; @@ -12999,6 +13107,11 @@ int stopspell(lifeform_t *caster, enum OBTYPE spellid) { // returns # created // pass EITHER wantrace OR wantrc + wantsize + wantalign +// +// friendly can be: +// b_true - force summoned lfs to be peaceful +// b_maybe - leave hostility as set by race +// b_false - force summoned lfs to be hostile int summonlfs(lifeform_t *caster, cell_t *where, enum RACE wantrace, enum RACECLASS wantrc, enum LFSIZE wantsize, enum ALIGNMENT wantalign, int howmany, int lifetime, int friendly) { lifeform_t *newlf; race_t *r = NULL; @@ -13065,11 +13178,15 @@ int summonlfs(lifeform_t *caster, cell_t *where, enum RACE wantrace, enum RACECL addflag(newlf->flags, F_XPVAL, 0, NA, NA, NULL); // summoned addflag(newlf->flags, F_SUMMONEDBY, caster->id, lifetime, NA, NULL); - if (friendly) { + if (friendly == B_TRUE) { addflag(newlf->flags, F_PETOF, caster->id, NA, NA, NULL); if (areallies(player, caster)) { makefriendly(newlf, PERMENANT); } + } else if (friendly == B_FALSE) { + if (!lfhasflag(newlf, F_HOSTILE)) { + addflag(newlf->flags, F_HOSTILE, B_TRUE, NA, NA, NULL); + } } ncreated++; } diff --git a/text.c b/text.c index a1fd051..4f1f8bd 100644 --- a/text.c +++ b/text.c @@ -466,13 +466,13 @@ char *getattackverb(lifeform_t *lf, object_t *wep, enum DAMTYPE damtype, int dam return "bash"; } } else if (dam <= 12) { + return "pound"; + } else if (dam <= 16) { + return "slam"; + } else if (dam <= 20) { return "pummel"; - } else if (dam <= 18) { - if (onein(2)) { - return "slam"; - } else { - return "clobber"; - } + } else { + return "clobber"; } } else if (damtype == DT_BITE) { if (lf && (ownersize <= SZ_SMALL)) { @@ -1373,6 +1373,9 @@ char *getregionname(char *buf, map_t *m, region_t *r, enum REGIONNAMEFORMAT how) case RG_CAVE: snprintf(buf, BUFLEN, "goblin caves L%d", m->depth); break; + case RG_WOODS: + snprintf(buf, BUFLEN, "syvan woods L%d", m->depth); + break; case RG_WORLDMAP: snprintf(buf, BUFLEN, "the surface(%d,%d)",x,y); break; @@ -1397,6 +1400,9 @@ char *getregionname(char *buf, map_t *m, region_t *r, enum REGIONNAMEFORMAT how) case RG_CAVE: snprintf(buf, BUFLEN, "on level %d of the goblin caves", m->depth); break; + case RG_WOODS: + snprintf(buf, BUFLEN, "on level %d of the sylvan woods", m->depth); + break; case RG_WORLDMAP: snprintf(buf, BUFLEN, "on the surface(%d,%d)",x,y); break; @@ -1421,6 +1427,9 @@ char *getregionname(char *buf, map_t *m, region_t *r, enum REGIONNAMEFORMAT how) case RG_CAVE: strcpy(buf, "the goblin caves"); break; + case RG_WOODS: + strcpy(buf, "the sylvan woods"); + break; case RG_WORLDMAP: strcpy(buf, "the surface"); break; diff --git a/vault.c b/vault.c index d801c01..9bc732f 100644 --- a/vault.c +++ b/vault.c @@ -781,7 +781,7 @@ vault_t *getvaulttype(map_t *m) { return poss[rnd(0,nposs-1)]; } // if we have no possibilities, lower rarity and try again - if (rr == RR_COMMON) { + if (rr == RR_FREQUENT) { // give up. break; } else {