Lair Feedback: The problem with "Or"

Zechnophobe

Strategy Lich
Joined
Sep 1, 2006
Messages
1,867
Location
Goleta, California
So, it occurred to me while playing a game where Lucian grabbed himself a Mithril weapon on turn 30ish from a random lair, that there is a fundamental problem with Lairs.

That problem, is that you have either something good OR something bad. The cost for exploration and getting the 'good' thing is always the Opportunity of something bad happen. Especially early on, I found myself just hitting up every lair I can get my hands on, because there really isn't *any* balance to a given effect. I know I had to restart some games because I got something that killed me.

But that's the thing, if you get something REALLY good, it can make a game too easy and be ruined. If you get something REALLY bad, it can likewise end your game. BOTH of these are ultimately a problem of the current lair system.

So here's my thoughts, instead of having a random Good thing or a random Bad thing, why not have one of each? Or maybe you get a good thing 90% of the time, but also always trigger a bad thing scaled to how good that good thing was (90% still empty, or all bad dungeons).

Hopefully I'm communicating this well, because I think it is very important.

Let's take a look at a few possible scenarios, from the code stand point.

Warrior pillages lair. We roll our rand (range 0 to 100), and get 53. 0 through 4 gives nothing, 5 through 9 give just a random weak bad event. THe higher the roll, the better the good thing.

This warrior got in the middle, so his good thing is probably fairly mediocre, not great. Maybe a treasure map, or 5 Experience or something.

Then we use that 53 and modify it by a random o to 10 value (+ or -). We roll +10, giving us a total of 63 as our roll on the 'bad' table, meaning the bad thing we got is considerably worse than the good thing we got, oh well.


This is an example implementation, which would assume that each possible good thing would have a fairly limited range of bad things that go with it (In that + or - 10 range).
 
Just spawning a good and a bad thing doesnt make the end result equal. If you get an awesome weapon and spawn a major boss one of two things will happen:

1. You will kill the boss with the weapon and have the weapon and the xp from the boss. ++

or

2. The boss will kill your unit and you will lose him and the weapon and still have to contend with the big boss.


You problem is with the RNG, and you absolutely right in stating that to much randomness isnt a good thing, especially in a strategy game.

To counter this we the lair system has conditions on every possible outcome. Some may require you to be a certain tech level, some may require you to be at a certain point of the game. It is impoosible to spawn a boss Balor on turn 10. It is also impossible to rescue a mage from a dungeon on turn 10.

So those are our controls. Could they be better? Are there results ehich may be to good or bad early on? Absolutely, some balancing is in order. I want boss bad guys to be a major threat and they may destroy your civ. But I dont want it to be garunteed that if you spawn x result you automatically lose.

Likewise I want the good results to be good, but they shouldn't win you the game. Early game mithril weapons is a great example of something we should probably consider for blocking until later on (maybe you have to know iron working before its possible to find mithril weapons).

But keep in mind that even if we tweak it dungeons by their very nature (like goody huts and graveyards) are randomization factors and will always push games one one or the other. Thats part of their charm as much as they are dangerous to the games. If that is unwanted then we have the option to play without lairs.

So in short: I don't think that your recommendation would help very much, but I agree with the problem. I think we have to tune the results some. The system is designed to be able to do that.
 
That is interesting Kael, where would I look to find these pre-reqs for the lair events?
 
a game option to double the number of lairs on the map would be awesome. that way you can have some, turn them off entirely, or have lots of them if you like. shouldn't be hard to add and a welcome addition to the game for some people I guess ;) ( game options rox. wildlands, living world, last days, etc... thanx for those :D )
 
How about some predictability, in the way that you will never get a reward before atleast getting 2 bad things? So that you HAVE to fight a few monsters before getting the reward?

Also about the barbarians movement:
I opened a dungeon, spawned a few barbarians just a few hex away from my capital, but the barbarians decided to go for somebody else. In this case I could explore the dungeon again next turn without any fear :)
 
Would it be a nice idea, if the unit type, that explores the dungeon sets the range of events?
So a str2-3 could spawn Orks und get copper weapons. A str 6 unit could spawn Ogres and get Iron weapons.
Perhaps even a str. requirement for more dangerous dungeons would be cool.
 
why not use the "Adventurer" Promotion, that's part of FF, so the best and badest things only happen, if your unit is experienced in exploring a dungeon - an unexperienced unit won't even find the key to the lower levels..
if this is used, there should be more possibilities - maybe an adventeurers guild or something like that, to get this promotion (in FF it is quite hard, to get it, I think only one civ or one event gives it?).
of course the Grigori would get the promotion for every hero unit..
 
I think to balance lairs we need a few small changes.
Boss monster spawns early on, especially powerful ones, are very bad news; there needs to be a "grace" period where these won't happen. This period can be based on difficulty, game speed, and/or maybe just a quick look at the AC (don't spawn big bads if it is 0)
There seems to have been some changes to the AI which are affecting barbarians in some odd way, with more and varied barbarians as a result of the lairs, this becomes more noticable I think. But that means maybe an AI tweak, not a change to lair results. It just looks like a fault with the lairs because that is where the monsters came out of.
The metal results should probably be stepped (if you have bronze, you can get iron; and you need iron before you can get mithril).
Other results; can you really say they are more unbalancing than stepping a scout onto a goody hut and popping a great tech in the first few turns, with little risk? I don't think they are. (Which is why my modmod prefers tribal villages which work differently).
 
[SHORT VERSION]
Anybody got a hint where to start looking for the things that make the lairs tick (in XML / python files)?
[/SHORT VERSION]

[LONG VERSION]
I'd like to see how difficult it'd be to mod the lairs into "mini-roguelikes", of course not with actual maps, just several "levels".
I.e., you start with "explore level I" and then you get either a good or a bad result. Then they switch to "explore level II" and so on.
The "lower" you go, the greater the danger, but also the greater the rewards.
And you'd almost always have a fight of some kind in the first levels, but being the winner would almost always lead to a reward of some kind on a lower level.
Only once you explore the lowest level, the dungeon would disappear.
The typical dungeon would only have an average of three to five levels, but there could be some special ones with many more.
Another idea would be to limit access to "depths" based on unit strength. So a typical Scout could only explore to lvl2 (before being "too afraid" to go on), whilst a Beastmaster could explore down to 7. Some dungeons could be "infinite", i.e. you would have no unit brave enough to explore down to it's lowest levels.
[/LONG VERSION]

Thanks.
_____
rezaf
 
it may be nice to get some low level results which are good and bad though

for example - a self aggrandized Orc warlord (...who's really just an Axeman) with a Healing Salve or some other one-use item. That should lead to a limited XP gain, and the need to kill the Axeman before it uses the salve for itself.

Would perhaps need to have the spawned Barb unit have no move initially too (to avoid it attacking the explorer and (if it wins) just using the salve for itself and that there is at least a chance to get hold of the salve for yourself.
 
I think to balance lairs we need a few small changes.
Boss monster spawns early on, especially powerful ones, are very bad news; there needs to be a "grace" period where these won't happen. This period can be based on difficulty, game speed, and/or maybe just a quick look at the AC (don't spawn big bads if it is 0)
There seems to have been some changes to the AI which are affecting barbarians in some odd way, with more and varied barbarians as a result of the lairs, this becomes more noticable I think. But that means maybe an AI tweak, not a change to lair results. It just looks like a fault with the lairs because that is where the monsters came out of.
The metal results should probably be stepped (if you have bronze, you can get iron; and you need iron before you can get mithril).
Other results; can you really say they are more unbalancing than stepping a scout onto a goody hut and popping a great tech in the first few turns, with little risk? I don't think they are. (Which is why my modmod prefers tribal villages which work differently).

No, its the same issue with goody huts and how unbalancing they can be.

What AI change would you like to see? What would you like the barbs to do differently?

That is interesting Kael, where would I look to find these pre-reqs for the lair events?

[SHORT VERSION]
Anybody got a hint where to start looking for the things that make the lairs tick (in XML / python files)?
[/SHORT VERSION]

[LONG VERSION]
I'd like to see how difficult it'd be to mod the lairs into "mini-roguelikes", of course not with actual maps, just several "levels".
I.e., you start with "explore level I" and then you get either a good or a bad result. Then they switch to "explore level II" and so on.
The "lower" you go, the greater the danger, but also the greater the rewards.
And you'd almost always have a fight of some kind in the first levels, but being the winner would almost always lead to a reward of some kind on a lower level.
Only once you explore the lowest level, the dungeon would disappear.
The typical dungeon would only have an average of three to five levels, but there could be some special ones with many more.
Another idea would be to limit access to "depths" based on unit strength. So a typical Scout could only explore to lvl2 (before being "too afraid" to go on), whilst a Beastmaster could explore down to 7. Some dungeons could be "infinite", i.e. you would have no unit brave enough to explore down to it's lowest levels.
[/LONG VERSION]

Thanks.
_____
rezaf

Yeah, we talked about that. Dungeons, as Marnok designed do often take several attempts to explore. You can call that several levels if you want. Bascially you have to keep going back until you clear it so the mechanic is the same either way.

It typically doesn't take as many as 3-5 tries to clear a dungeon unless you run into a string of bad luck. I prefer that. In FfH we cut down the amount of lair significantly from the amount in Marnok's mod. The reason being is we want explorable lairs to be one small piece of the larger FfH pie. If we added more results form each lair or more lairs that mechanic would dominate the game and their results would determine the game even further. The game would essentially become about exploring lairs instead of the other aspects (which was appropriate when it was a mod about exploring lairs, but not so much in the main game).

Here are the technical specifics. Exploring lairs is a spell that is only available if a unit is standing in a plot with a explorable improvement in it. There is a seperate spell for each improvement type (so exploring a dungeon and a barrow are different spells though they make calls into the same python functions).

Each spell runs a python check in CvSpellInterface.py to see if the unit can do it. This is what keeps fireballs, hawks, summons and catapults from being able to explore lairs.

Code:
def reqExploreLair(caster):
	if caster.isOnlyDefensive():
		return False
	if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_SIEGE'):
		return False
	if caster.isBarbarian():
		return False
	if caster.getDuration() > 0:
		return False
	if caster.getSpecialUnitType() == gc.getInfoTypeForString('SPECIALUNIT_SPELL'):
		return False
	if caster.getSpecialUnitType() == gc.getInfoTypeForString('SPECIALUNIT_BIRD'):
		return False
	pPlot = caster.plot()
	if not pPlot.isWater():
		pPlayer = gc.getPlayer(caster.getOwner())
		iTeam = pPlayer.getTeam()
		eTeam = gc.getTeam(iTeam)
		bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())
		if not eTeam.isAtWar(bPlayer.getTeam()):
			return False
	return True

Assuming the unit explores the lair the following is the spell results. There are two functions, the first is for normal lairs, the second is for epic lairs. For normal lairs the chances are as follows:

10% rare bad result
30% bad result
30% neutral result
20% good result
10% rare good result

For the epic lairs its:

50% rare bad result
50% rare good result

Code:
def spellExploreLair(caster):
	pPlot = caster.plot()
	iRnd = CyGame().getSorenRandNum(100, "Explore Lair")
	iDestroyLair = 0
	if iRnd < 10:
		iDestroyLair = cf.exploreLairBigBad(caster)
	if iRnd >= 10 and iRnd < 40:
		iDestroyLair = cf.exploreLairBad(caster)
	if iRnd >= 40 and iRnd < 70:
		iDestroyLair = cf.exploreLairNeutral(caster)
	if iRnd >= 70 and iRnd < 90:
		iDestroyLair = cf.exploreLairGood(caster)
	if iRnd >= 90:
		iDestroyLair = cf.exploreLairBigGood(caster)
	if iDestroyLair > CyGame().getSorenRandNum(100, "Explore Lair"):
		CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_LAIR_DESTROYED", ()),'AS2D_POSITIVE_DINK',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
		pPlot.setImprovementType(-1)
	caster.finishMoves()

def spellExploreLairEpic(caster):
	pPlot = caster.plot()
	iRnd = CyGame().getSorenRandNum(100, "Explore Lair")
	iDestroyLair = 0
	if iRnd < 50:
		iDestroyLair = cf.exploreLairBigBad(caster)
	if iRnd >= 50:
		iDestroyLair = cf.exploreLairBigGood(caster)
	if iDestroyLair > CyGame().getSorenRandNum(100, "Explore Lair"):
		CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_LAIR_DESTROYED", ()),'AS2D_POSITIVE_DINK',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
		pPlot.setImprovementType(-1)
	caster.finishMoves()

So this only determines the type of result we will get, there are other functions that find the exact result. Those are in CustomFunctions.py as follows:

Code:
	def exploreLairBigBad(self, caster):
		iPlayer = caster.getOwner()
		pPlot = caster.plot()
		pPlayer = gc.getPlayer(caster.getOwner())

		lList = []
		lPromoList = ['PROMOTION_MUTATED', 'PROMOTION_CANNIBALIZE', 'PROMOTION_MOBILITY1', 'PROMOTION_STRONG', 'PROMOTION_BLITZ', 'PROMOTION_COMMAND1', 'PROMOTION_HEROIC_STRENGTH', 'PROMOTION_HEROIC_DEFENSE', 'PROMOTION_MAGIC_IMMUNE', 'PROMOTION_STONESKIN', 'PROMOTION_VALOR', 'PROMOTION_VILE_TOUCH']
		lHenchmanList = ['UNIT_AZER', 'UNIT_GRIFFON']
		if self.grace() == False:
			lList = lList + ['UNIT_AIR_ELEMENTAL']
		if not pPlot.isWater():
			lList = lList + ['UNIT_GIANT_SPIDER', 'UNIT_GARGOYLE', 'UNIT_OGRE']
			lHenchmanList = lHenchmanList + ['UNIT_AXEMAN', 'UNIT_WOLF', 'UNIT_OGRE', 'UNIT_CHAOS_MARAUDER', 'UNIT_WOLF_RIDER', 'UNIT_MISTFORM', 'UNIT_LION']
			if self.grace() == False:
				lList = lList + ['UNIT_EARTH_ELEMENTAL', 'UNIT_FIRE_ELEMENTAL', 'UNIT_CHAMPION', 'UNIT_ASSASSIN', 'UNIT_VAMPIRE', 'UNIT_MYCONID', 'UNIT_EIDOLON', 'UNIT_OGRE_WARCHIEF', 'UNIT_WEREWOLF']
				lPromoList = lPromoList + ['PROMOTION_FIRE2', 'PROMOTION_AIR2', 'PROMOTION_HERO', 'PROMOTION_MARKSMAN', 'PROMOTION_SHADOWWALK']
			if pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_SNOW'):
				lHenchmanList = lHenchmanList + ['UNIT_FROSTLING_ARCHER', 'UNIT_FROSTLING_WOLF_RIDER', 'UNIT_POLAR_BEAR']
			if pPlot.isHills():
				lList = lList + ['UNIT_HILL_GIANT']
				lPromoList = ['PROMOTION_GUERILLA1','PROMOTION_GUERILLA2']
			if pPlot.getFeatureType() == gc.getInfoTypeForString('FEATURE_FOREST'):
				lList = lList + ['UNIT_TREANT','UNIT_SATYR']
				lPromoList = lPromoList + ['PROMOTION_WOODSMAN1', 'PROMOTION_WOODSMAN2']
				lHenchmanList = lHenchmanList + ['UNIT_TIGER', 'UNIT_BABY_SPIDER', 'UNIT_FAWN']
			if pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_BARROW'):
				lList = lList + ['UNIT_SPECTRE']
				lPromoList = lPromoList + ['PROMOTION_DEATH2']
				lHenchmanList = lHenchmanList + ['UNIT_SKELETON', 'UNIT_PYRE_ZOMBIE']
				if self.grace() == False:
					lList = lList + ['UNIT_LICH', 'UNIT_WRAITH']
			if pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_RUINS'):
				lPromoList = lPromoList + ['POISONED_BLADE']
				lHenchmanList = lHenchmanList + ['UNIT_LIZARDMAN', 'UNIT_GORILLA']
				if self.grace() == False:
					lList = lList + ['UNIT_MANTICORE']
			if CyGame().getGlobalCounter() > 40:
				lList = lList + ['UNIT_PIT_BEAST', 'UNIT_DEATH_KNIGHT', 'UNIT_BALOR']
				lPromoList = lPromoList + ['PROMOTION_FEAR']
				lHenchmanList = lHenchmanList + ['UNIT_IMP', 'UNIT_HELLHOUND']
		if pPlot.isWater():
			lList = lList + ['UNIT_SEA_SERPENT', 'UNIT_STYGIAN_GUARD', 'UNIT_PIRATE']
			lHenchmanList = lHenchmanList + ['UNIT_DROWN']
			if self.grace() == False:
				lList = lList + ['UNIT_WATER_ELEMENTAL', 'UNIT_KRAKEN']

		sMonster = lList[CyGame().getSorenRandNum(len(lList), "Pick Monster")-1]
		sHenchman = lHenchmanList[CyGame().getSorenRandNum(len(lHenchmanList), "Pick Henchman")-1]
		sPromo = lPromoList[CyGame().getSorenRandNum(len(lPromoList), "Pick Promotion")-1]
		iUnit = gc.getInfoTypeForString(sMonster)
		iHenchman = gc.getInfoTypeForString(sHenchman)
		newUnit = self.addUnitFixed(caster,iUnit)
		if newUnit != -1:
			newUnit.setHasPromotion(gc.getInfoTypeForString(sPromo), True)
			newUnit.setName(self.MarnokNameGenerator(newUnit))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BIGBAD",()),'',1,gc.getUnitInfo(iUnit).getButton(),ColorTypes(7),newUnit.getX(),newUnit.getY(),True,True)
			bPlayer = gc.getPlayer(gc.getBARBARIAN_PLAYER())
			for i in range (CyGame().getSorenRandNum(5, "Pick Henchmen")):
				bPlayer.initUnit(iHenchman, newUnit.getX(), newUnit.getY(), UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH)
		return 0

	def exploreLairBad(self, caster):
		iPlayer = caster.getOwner()
		pPlot = caster.plot()
		pPlayer = gc.getPlayer(caster.getOwner())

		lList = ['DEATH', 'COLLAPSE']
		if caster.isAlive():
			lList = lList + ['CRAZED', 'DEMONIC_POSSESSION', 'DISEASED', 'ENRAGED', 'PLAGUED', 'POISONED', 'WITHERED']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE'):
			lList = lList + ['RUSTED']
		if pPlot.isWater():
			lList = lList + ['SPAWN_DROWN', 'SPAWN_SEA_SERPENT']
		if not pPlot.isWater():
			lList = lList + ['SPAWN_SPIDER', 'SPAWN_SPECTRE']
		
		sGoody = lList[CyGame().getSorenRandNum(len(lList), "Pick Goody")-1]
		if sGoody == 'DEATH':
			caster.kill(True,0)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_DEATH", ()),'',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 0
		if sGoody == 'COLLAPSE':
			caster.doDamageNoCaster(50, 90, gc.getInfoTypeForString('DAMAGE_PHYSICAL'), false)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_COLLAPSE", ()),'',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'CRAZED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_CRAZED'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_CRAZED", ()),'',1,'Art/Interface/Buttons/Promotions/Crazed.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'DEMONIC_POSSESSION':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_ENRAGED'), True)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_CRAZED'), True)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DEMON'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_POSSESSED", ()),'',1,'Art/Interface/Buttons/Units/UCDemon.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'DISEASED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_DISEASED'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_DISEASED", ()),'',1,'Art/Interface/Buttons/Promotions/Diseased.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'ENRAGED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_ENRAGED'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_ENRAGED", ()),'',1,'Art/Interface/Buttons/Promotions/Enraged.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80		
		if sGoody == 'PLAGUED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_PLAGUED'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_PLAGUED", ()),'',1,'Art/Interface/Buttons/Promotions/Plagued.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'POISONED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_POISONED'), True)
			caster.doDamageNoCaster(25, 90, gc.getInfoTypeForString('DAMAGE_POISON'), false)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_POISONED", ()),'',1,'Art/Interface/Buttons/Promotions/Poisoned.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'WITHERED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_WITHERED'), True)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_WITHERED", ()),'',1,'Art/Interface/Buttons/Promotions/Withered.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'RUSTED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED'), True)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_BRONZE_WEAPONS'), False)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), False)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MITHRIL_WEAPONS'), False)
			CyInterface().addMessage(caster.getOwner(),True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_RUSTED", ()),'',1,'Art/Interface/Buttons/Promotions/Rusted.dds',ColorTypes(7),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'SPAWN_DROWN':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_DROWN'), caster)
			return 50
		if sGoody == 'SPAWN_SEA_SERPENT':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_SEA_SERPENT'), caster)
			return 50
		if sGoody == 'SPAWN_SPECTRE':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_GRAVE_SPECTRE'), caster)
			return 50
		if sGoody == 'SPAWN_SPIDER':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_SPIDER'), caster)
			return 50
		return 100
 
Code:
	def exploreLairNeutral(self, caster):
		iPlayer = caster.getOwner()
		pPlot = caster.plot()
		pPlayer = gc.getPlayer(caster.getOwner())
		lList = ['NOTHING']
		if not pPlot.isWater():
			lList = lList + ['SPAWN_SKELETON', 'SPAWN_LIZARDMAN', 'SPAWN_SPIDER', 'PORTAL', 'DEPTHS', 'DWARF_VS_LIZARDMEN', 'CAGE']
			if pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_SNOW'):
				lList = lList + ['SPAWN_FROSTLING']
			if pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_BARROW'):
				lList = lList + ['SPAWN_SKELETON', 'SPAWN_SKELETON']
			if pPlot.getImprovementType() == gc.getInfoTypeForString('IMPROVEMENT_RUINS'):
				lList = lList + ['SPAWN_LIZARDMAN', 'SPAWN_LIZARDMAN']
		if pPlot.isWater():
			lList = lList + ['SPAWN_DROWN']
		if caster.isAlive():
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_MUTATED')):
				lList = lList + ['MUTATED']
		
		sGoody = lList[CyGame().getSorenRandNum(len(lList), "Pick Goody")-1]
		if sGoody == 'CAGE':
			pPlot.setImprovementType(gc.getInfoTypeForString('IMPROVEMENT_CAGE'))
			for i in range(pPlot.getNumUnits(), -1, -1):
				pUnit = pPlot.getUnit(i)
				pUnit.setHasPromotion(gc.getInfoTypeForString('PROMOTION_HELD'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_CAGE",()),'',1,'Art/Interface/Buttons/Improvements/Cage.dds',ColorTypes(7),caster.getX(),caster.getY(),True,True)
			return 0
		if sGoody == 'DEPTHS':
			iUnitID = self.getUnitPlayerID(caster)
			if iUnitID != -1:
				iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_EXPLORE_LAIR_DEPTHS')
				triggerData = pPlayer.initTriggeredData(iEvent, true, -1, caster.getX(), caster.getY(), caster.getOwner(), -1, -1, -1, iUnitID, -1)
			return 100
		if sGoody == 'DWARF_VS_LIZARDMEN':
			iUnitID = self.getUnitPlayerID(caster)
			if iUnitID != -1:
				iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_EXPLORE_LAIR_DWARF_VS_LIZARDMEN')
				triggerData = pPlayer.initTriggeredData(iEvent, true, -1, caster.getX(), caster.getY(), caster.getOwner(), -1, -1, -1, iUnitID, -1)
			return 100
		if sGoody == 'MUTATED':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MUTATED'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_MUTATED",()),'',1,'Art/Interface/Buttons/Promotions/Mutated.dds',ColorTypes(7),caster.getX(),caster.getY(),True,True)
			return 50
		if sGoody == 'NOTHING':
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_NOTHING",()),'',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'PORTAL':
			iUnitID = self.getUnitPlayerID(caster)
			if iUnitID != -1:
				iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_EXPLORE_LAIR_PORTAL')
				triggerData = pPlayer.initTriggeredData(iEvent, true, -1, caster.getX(), caster.getY(), caster.getOwner(), -1, -1, -1, iUnitID, -1)
			return 0
		if sGoody == 'SPAWN_DROWN':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_DROWN'), caster)
			return 50
		if sGoody == 'SPAWN_FROSTLING':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_FROSTLING'), caster)
			return 50
		if sGoody == 'SPAWN_LIZARDMAN':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_LIZARDMAN'), caster)
			return 50
		if sGoody == 'SPAWN_SKELETON':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_SKELETON'), caster)
			return 50
		if sGoody == 'SPAWN_SPIDER':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_SPAWN_SPIDER'), caster)
			return 50
		return 100

	def exploreLairGood(self, caster):
		iPlayer = caster.getOwner()
		pPlot = caster.plot()
		pPlayer = gc.getPlayer(caster.getOwner())
		lList = ['HIGH_GOLD', 'TREASURE', 'EXPERIENCE']
		if pPlayer.isHasTech(gc.getInfoTypeForString('TECH_MYSTICISM')):
			lList = lList + ['PRISONER_DISCIPLE_ASHEN', 'PRISONER_DISCIPLE_EMPYREAN', 'PRISONER_DISCIPLE_LEAVES', 'PRISONER_DISCIPLE_OVERLORDS', 'PRISONER_DISCIPLE_RUNES', 'PRISONER_DISCIPLE_ORDER']
		if caster.isAlive():
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SPIRIT_GUIDE')):
				lList = lList + ['SPIRIT_GUIDE']
		if not pPlot.isWater():
			lList = lList + ['ITEM_HEALING_SALVE']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_MELEE'):
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_ENCHANTED_BLADE')):
				lList = lList + ['ENCHANTED_BLADE']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ADEPT'):
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SPELLSTAFF')):
				lList = lList + ['SPELLSTAFF']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_RECON'):
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_POISONED_BLADE')):
				lList = lList + ['POISONED_BLADE']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_ARCHER'):
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_FLAMING_ARROWS')):
				lList = lList + ['FLAMING_ARROWS']
		if caster.getUnitCombatType() == gc.getInfoTypeForString('UNITCOMBAT_DISCIPLE'):
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_SHIELD_OF_FAITH')):
				lList = lList + ['SHIELD_OF_FAITH']
		if gc.getUnitInfo(caster.getUnitType()).getWeaponTier() >= 1:
			if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_MITHRIL_WEAPONS')):
				if gc.getUnitInfo(caster.getUnitType()).getWeaponTier() >= 3:
					lList = lList + ['MITHRIL_WEAPONS']
				if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS')):
					if gc.getUnitInfo(caster.getUnitType()).getWeaponTier() >= 2:
						lList = lList + ['IRON_WEAPONS']
					if not caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_BRONZE_WEAPONS')):
						lList = lList + ['BRONZE_WEAPONS']

		sGoody = lList[CyGame().getSorenRandNum(len(lList), "Pick Goody")-1]
		if sGoody == 'HIGH_GOLD':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_HIGH_GOLD'), caster)
			return 90
		if sGoody == 'TREASURE':
			self.placeTreasure(iPlayer, gc.getInfoTypeForString('EQUIPMENT_TREASURE'))
			return 80
		if sGoody == 'EXPERIENCE':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_EXPERIENCE'), caster)
			return 100
		if sGoody == 'SPIRIT_GUIDE':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_SPIRIT_GUIDE'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_SPIRIT_GUIDE",()),'AS2D_POSITIVE_DINK',1,'Art/Interface/Buttons/Promotions/SpiritGuide.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 80
		if sGoody == 'ITEM_HEALING_SALVE':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_HEALING_SALVE'), caster)
			return 100
		if sGoody == 'ITEM_POTION_OF_INVISIBILITY':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_POTION_OF_INVISIBILITY'), caster)
			return 100
		if sGoody == 'ITEM_POTION_OF_RESTORATION':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_POTION_OF_RESTORATION'), caster)
			return 100
		if sGoody == 'ENCHANTED_BLADE':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_ENCHANTED_BLADE'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_ENCHANTED_BLADE",()),'',1,'Art/Interface/Buttons/Promotions/EnchantedBlade.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'SPELLSTAFF':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_SPELLSTAFF'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_SPELLSTAFF",()),'',1,'Art/Interface/Buttons/Promotions/Spellstaff.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'POISONED_BLADE':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_POISONED_BLADE'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_POISONED_BLADE",()),'',1,'Art/Interface/Buttons/Promotions/PoisonedBlade.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'FLAMING_ARROWS':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_FLAMING_ARROWS'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_FLAMING_ARROWS",()),'AS2D_POSITIVE_DINK',1,'Art/Interface/Buttons/Promotions/FlamingArrows.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'PRISONER_DISCIPLE_ASHEN':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_ASHEN'), caster)
			return 100			
		if sGoody == 'PRISONER_DISCIPLE_EMPYREAN':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_EMPYREAN'), caster)
			return 100			
		if sGoody == 'PRISONER_DISCIPLE_LEAVES':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_LEAVES'), caster)
			return 100			
		if sGoody == 'PRISONER_DISCIPLE_OVERLORDS':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_OVERLORDS'), caster)
			return 100			
		if sGoody == 'PRISONER_DISCIPLE_RUNES':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_RUNES'), caster)
			return 100			
		if sGoody == 'PRISONER_DISCIPLE_ORDER':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_DISCIPLE_ORDER'), caster)
			return 100			
		if sGoody == 'SHIELD_OF_FAITH':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_SHIELD_OF_FAITH'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_SHIELD_OF_FAITH",()),'',1,'Art/Interface/Buttons/Promotions/ShieldOfFaith.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BRONZE_WEAPONS':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_BRONZE_WEAPONS'), True)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BRONZE_WEAPONS",()),'',1,'Art/Interface/Buttons/Promotions/BronzeWeapons.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED')) == True:
				caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED'),False)
			return 100
		if sGoody == 'IRON_WEAPONS':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), True)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_BRONZE_WEAPONS'), False)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_IRON_WEAPONS",()),'',1,'Art/Interface/Buttons/Promotions/IronWeapons.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED')) == True:
				caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED'),False)
			return 100
		if sGoody == 'MITHRIL_WEAPONS':
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_MITHRIL_WEAPONS'), True)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_IRON_WEAPONS'), False)
			caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_BRONZE_WEAPONS'), False)
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_MITHRIL_WEAPONS",()),'',1,'Art/Interface/Buttons/Promotions/MithrilWeapons.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			if caster.isHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED')) == True:
				caster.setHasPromotion(gc.getInfoTypeForString('PROMOTION_RUSTED'),False)
			return 100
		return 100

	def exploreLairBigGood(self, caster):
		iPlayer = caster.getOwner()
		pPlot = caster.plot()
		pPlayer = gc.getPlayer(caster.getOwner())

		lList = ['TREASURE_VAULT', 'GOLDEN_AGE']
		if pPlayer.canReceiveGoody(pPlot, gc.getInfoTypeForString('GOODY_GRAVE_TECH'), caster):
			lList = lList + ['TECH']
		if not pPlot.isWater():
			lList = lList + ['ITEM_JADE_TORC', 'ITEM_ROD_OF_WINDS', 'ITEM_TIMOR_MASK', 'PRISONER_ADVENTURER', 'PRISONER_ARTIST', 'PRISONER_COMMANDER', 'PRISONER_ENGINEER', 'PRISONER_MECHANT', 'PRISONER_PROPHET', 'PRISONER_SCIENTIST']
			if pPlot.getBonusType(-1) == -1:
				lList = lList + ['BONUS_MANA']
				if pPlayer.isHasTech(gc.getInfoTypeForString('TECH_MINING')):
					lList = lList + ['BONUS_COPPER', 'BONUS_GEMS', 'BONUS_GOLD']
				if pPlayer.isHasTech(gc.getInfoTypeForString('TECH_SMELTING')):
					lList = lList + ['BONUS_IRON']
		if pPlot.isWater():
			lList = lList + ['PRISONER_SEA_SERPENT']
			if pPlot.getBonusType(-1) == -1:
				lList = lList + ['BONUS_CLAM', 'BONUS_CRAB', 'BONUS_FISH']
		if self.grace() == False:
			lList = lList + ['PRISONER_ANGEL', 'PRISONER_MONK', 'PRISONER_ASSASSIN', 'PRISONER_CHAMPION', 'PRISONER_MAGE']
		sGoody = lList[CyGame().getSorenRandNum(len(lList), "Pick Goody")-1]

		if sGoody == 'TREASURE_VAULT':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_TREASURE_VAULT'), caster)
			return 100	
		if sGoody == 'BONUS_CLAM':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_CLAM'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_CLAM",()),'',1,'Art/Interface/Buttons/WorldBuilder/Clam.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_COPPER':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_COPPER'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_COPPER",()),'',1,'Art/Interface/Buttons/WorldBuilder/Copper.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_CRAB':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_CRAB'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_CRAB",()),'',1,'Art/Interface/Buttons/WorldBuilder/Crab.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_FISH':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_FISH'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_FISH",()),'',1,'Art/Interface/Buttons/WorldBuilder/Fish.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_GOLD':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_GOLD'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_GOLD",()),'',1,'Art/Interface/Buttons/WorldBuilder/Gold.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_GEMS':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_GEMS'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_GEMS",()),'',1,'Art/Interface/Buttons/WorldBuilder/Gems.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_IRON':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_IRON'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_IRON",()),'',1,'Art/Interface/Buttons/WorldBuilder/Iron.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'BONUS_MANA':
			pPlot.setBonusType(gc.getInfoTypeForString('BONUS_MANA'))
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_BONUS_MANA",()),'',1,'Art/Interface/Buttons/WorldBuilder/mana_button.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'GOLDEN_AGE':
			pPlayer.changeGoldenAgeTurns(CyGame().goldenAgeLength())
			CyInterface().addMessage(iPlayer,True,25,CyTranslator().getText("TXT_KEY_MESSAGE_EXPLORE_LAIR_GOLDEN_AGE",()),'',1,'Art/Interface/Buttons/Spells/Explore Lair.dds',ColorTypes(8),pPlot.getX(),pPlot.getY(),True,True)
			return 100
		if sGoody == 'ITEM_JADE_TORC':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_JADE_TORC'), caster)
			return 100
		if sGoody == 'ITEM_ROD_OF_WINDS':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_ROD_OF_WINDS'), caster)
			return 100
		if sGoody == 'ITEM_TIMOR_MASK':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_ITEM_TIMOR_MASK'), caster)
			return 100
		if sGoody == 'PRISONER_ADVENTURER':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_ADVENTURER'), caster)
			return 100			
		if sGoody == 'PRISONER_ANGEL':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_ANGEL'), caster)
			return 100			
		if sGoody == 'PRISONER_ARTIST':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_ARTIST'), caster)
			return 100
		if sGoody == 'PRISONER_ASSASSIN':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_ASSASSIN'), caster)
			return 100
		if sGoody == 'PRISONER_CHAMPION':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_CHAMPION'), caster)
			return 100
		if sGoody == 'PRISONER_COMMANDER':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_COMMANDER'), caster)
			return 100	
		if sGoody == 'PRISONER_ENGINEER':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_ENGINEER'), caster)
			return 100	
		if sGoody == 'PRISONER_MAGE':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_MAGE'), caster)
			return 100
		if sGoody == 'PRISONER_MERCHANT':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_MERCHANT'), caster)
			return 100	
		if sGoody == 'PRISONER_MONK':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_MONK'), caster)
			return 100			
		if sGoody == 'PRISONER_PROPHET':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_PROPHET'), caster)
			return 100	
		if sGoody == 'PRISONER_SEA_SERPENT':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_SEA_SERPENT'), caster)
			return 100	
		if sGoody == 'PRISONER_SCIENTIST':
			pPlayer.receiveGoody(pPlot,gc.getInfoTypeForString('GOODY_EXPLORE_LAIR_PRISONER_SCIENTIST'), caster)
			return 100
		if sGoody == 'TECH':
			pPlayer.receiveGoody(pPlot, gc.getInfoTypeForString('GOODY_GRAVE_TECH'), caster)
			return 100
		return 100

Each of these 4 functions is broken into two parts. The first builds a list of possible results based on any qualifications that are set. Some require a grace period to be expired (ie: it cant happen in the early game) before that result will be added to the list. Others require a certain tech to be known, the AC to be above a certain level, that the exploring unit be of a certain unitcombat, that the improvement being explored be a certain type, that the plot have certain characteristics, etc.

Once the list of the possible results is built we randomly select one. The the second half of the function goes through the work of performing whatever the selected result is supposed to do.
 
What AI change would you like to see? What would you like the barbs to do differently?

I was just remarking on what other people have said, that sometimes the AI seems to beeline a city in a way they hadn't noticed before. Just wondered if that was creating the behaviour the earlier poster commented on.

Might be good if barbarians next to a lair considered attacking a non-barb unit on the lair as a priority.
 
I'd just like to say that I enjoyed the lairs/dungeons in FF and I enjoy them in FFH. It really boils down to a risk/reward decision the player needs to make. You don't have to explore these things (although it is tough not to!).

I have been very lucky in my first two .34 games getting Adventurers, Great Prophets, etc. I've also had Scouts killed, withered and diseased. I haven't released any boss monsters yet though (the worst was 3 Lizardmen and my two Dwarven Axemen killed 2 of them). Again, just good luck, I guess.

My only complaint on this fun new feature is the speed with which the lairs/dungeons get guards on them. It is not possible to kill Skeletons/Lizardmen with Scouts (or Warriors) early on and as the game moves on these lairs/dungeons become unaccessible due to AI expanding, etc. So, I would just ask a bit more time early-game to allow exploration of these things without plopping a tough guard on one.
 
I was just remarking on what other people have said, that sometimes the AI seems to beeline a city in a way they hadn't noticed before. Just wondered if that was creating the behaviour the earlier poster commented on.

Might be good if barbarians next to a lair considered attacking a non-barb unit on the lair as a priority.

Ahh, well you certainly cant fault the AI for being to effective.
 
Ah, thanks for even quoting all relevant code sections, should be very easy to go on from there.

First thing I'm going to experiment on is moving disciple prisoners of a religion not yet founded to the biggood section with the disciples in the good section only available when the religion is already in the game.
I think there's a reference to the API in one of the modding subforums iirc, so it should be rather easy to pull off.

I noticed some lairs taking repeated attempts to "close" them, but I always thought some results would remove the lair and others wouldn't, but I guess it's more like they are removed after x tries of exploring, which is almost what I had in mind.
I agree with the point you raised about too much focus on dungeons in FFH being not ideal, btw. Didn't demand it for the "main game", either.
I think dungeons were a great idea Marnok deserves a lot of credit for, but I also think balancing off loads of potentially cool ideas in a way that allows each (or most) to get a little love, but that allows none to get too much focus is quite tricky and often done wrong, but you did a tremendous job with it in FFH so far (and it isn't even finished). :goodjob:
_____
rezaf
 
I would definitely like to see more in the way of predictability in lair results.

One way to implement this would be to fix the order of every lair; every lair generates a random bad effect when first explored an is not destroyed, and then gets a random good effect when explored a second time (and maybe link these to a player, so the human player can't get good effects off lairs explored by the AI).

If you know you are going to get a bad effect from destroying a lair, you won't be so eager to try exploring them all with your initial scouts, and so the feature will last further into the game.

Super-dungeons like the Well of Bradeline or such could have 2-3 "bad" effects on exploration, and then guarantee a major good effect (free adventurer, great person, etc.)

One could also distinguish between lairs (maybe lairs always have minor effects, and are randomly good or bad) and dungeons (maybe dungeons can have the full range of effects, and guarantee getting a bad effect before getting a good effect).
 
Back
Top Bottom