[MOD] MagisterModmod

a note on Sheaim...
currently playing them... and I found that the early game is "a-religious".
I tried a "bee-line" to pyre-zombies. not really a bee-line as I took the time to take hunting, calendar, animal husbandry and a few other to resist the enemies.
however I received religions from other civs during my early game but I couldn't take those.... it was frustrating.
OO gave me -2 fire mana... and pyre zombies need fire mana.
RoK was ok... but brings me to "neutral"... and pyre zombies need "evil".

so I didn't try to get FoL in case it would be science spent for nothing.

I think the Pyre zombie could get less restrictions : maybe remove the "evil" and replace it by "cannot be built by good" ?
 
Do you not build roads to important places? Flying units don't get road bonuses.

I did not know this. But the hawk should at least have the option removed. How do I do that?
 
I think what he meant was, if you live in the US and can download both files maybe you could reupload them somewhere else?

I guess so, if I actually was living in America.
 
Now that lfgr has released a DLL that includes the code Tholal omitted, I can get the PyHelp feature to work properly.

I already have the Drown Spell set up to show how much it will cost. If you have multiple units selected, it adds up the costs of all those units that meet the non-monetary requirements for casting it.

I also made the Steal spell list what equipment can be stolen at that time.

If there are more spells you would like to provide better descriptions before the next release, now is the time to list them.


Glad to see you're still alive and kicking MagisterCultuum. In the meantime did you look for alternative upload solutions? Ever tried http://1339.cf/ or https://maxfile.ro/? No nonsense, no registration needed, simply upload and share the link.

I tried those the evening that you posted this, but the upload went very slowly and never seemed to finish or give me a link to share.

Thanks MagisterCultuum, i wish you good luck with the job!

There's no hurry even though i'm really itching to play, your priorities are sound.
I didn't practice as much as I probably should have and the AutoCAD Civil 3D trial period is officially over now, but that doesn't actually seem to be stop me from using the program so it is probably no big deal.

I emailed the president on Tuesday to see if they had reached a decision about hiring, but have not heard back yet. I called the office less than an hour ago, but the man who answered the phone said that he did not know the decision and would have to ask the president to get back to me after he gets off the phone with a client.

You're right, I also got confused by the oceans and resource placement.

How does the map account for civ placement? Does it go by the map as it is, or the future resource/terrain?
Civ placement is handled before the python code that makes temporary terrain changes ever runs. As such, it is based on the permanent map features which will appear in the future if teraforming spells or events don't change anything.
Did you look at the save?
I looked at it, but did not play many turns or examine carefully enough to get a good sense of was going on.

Generally logs are more useful than saved games, and you did not provide those.
I don't know if that happened. What does the event look like, exactly?
I posted a screen shot for you.

I was thinking that the event caused a diplomatic penalty with everyone, even not just towards the player who got the event, but that does not seem to be the case.
This is the first I'm hearing about it. What are the conditions for it, and is there a way to disable it?

It is code that as been found in CustomFunction.py for a long time
Spoiler :
Code:
	def warScript(self, iPlayer):
		pPlayer = gc.getPlayer(iPlayer)
		eTeam = gc.getTeam(pPlayer.getTeam())
		if not eTeam.isAVassal():
			iCiv = pPlayer.getCivilizationType()
			iDoviello = gc.getInfoTypeForString('CIVILIZATION_DOVIELLO')
			iInfernal = gc.getInfoTypeForString('CIVILIZATION_INFERNAL')
			iLjosalfar = gc.getInfoTypeForString('CIVILIZATION_LJOSALFAR')
			iSvartalfar = gc.getInfoTypeForString('CIVILIZATION_SVARTALFAR')
			iEvil = gc.getInfoTypeForString('ALIGNMENT_EVIL')
			iMastery = gc.getInfoTypeForString('BUILDINGCLASS_TOWER_OF_MASTERY')
			iAltarDivine = gc.getInfoTypeForString('BUILDING_ALTAR_OF_THE_LUONNOTAR_DIVINE')
			iAltarExalted = gc.getInfoTypeForString('BUILDING_ALTAR_OF_THE_LUONNOTAR_EXALTED')
			iEnemy = -1
			for iPlayer2 in range(gc.getMAX_PLAYERS()):
				pPlayer2 = gc.getPlayer(iPlayer2)
				if pPlayer2.isAlive():
					iTeam2 = pPlayer2.getTeam()
					if eTeam.isAtWar(iTeam2):
						if CyGame().getSorenRandNum(100, "War Script") < 5:
							self.dogpile(iPlayer, iPlayer2)
					if self.warScriptAllow(iPlayer, iPlayer2):
						if pPlayer2.getBuildingClassMaking(iMastery) > 0:
							if eTeam.getAtWarCount(True) == 0:
								self.startWar(iPlayer, iPlayer2, WarPlanTypes.WARPLAN_TOTAL)
						iCiv2 = pPlayer2.getCivilizationType()
						if CyGame().getGlobalCounter() > 20:
							if (iCiv == iSvartalfar and iCiv2 == iLjosalfar) or (iCiv2 == iSvartalfar and iCiv == iLjosalfar):
								if CyGame().getPlayerRank(iPlayer) > CyGame().getPlayerRank(iPlayer2):
									self.startWar(iPlayer, iPlayer2, WarPlanTypes.WARPLAN_TOTAL)
						if pPlayer.getAlignment() == iEvil:
							if CyGame().getGlobalCounter() > 40 or iCiv in [iInfernal, iDoviello]:
								if eTeam.getAtWarCount(True) == 0 and CyGame().getPlayerRank(iPlayer2) > CyGame().getPlayerRank(iPlayer):
									if iEnemy == -1 or CyGame().getPlayerRank(iPlayer2) > CyGame().getPlayerRank(iEnemy):
										iEnemy = iPlayer2
							if pPlayer2.getNumBuilding(iAltarDivine) > 0 or pPlayer2.getNumBuilding(iAltarExalted) > 0:
								if eTeam.getAtWarCount(True) == 0:
									self.startWar(iPlayer, iPlayer2, WarPlanTypes.WARPLAN_TOTAL)
			if iEnemy != -1:
				if CyGame().getPlayerRank(iPlayer) > CyGame().getPlayerRank(iEnemy):
					self.startWar(iPlayer, iEnemy, WarPlanTypes.WARPLAN_TOTAL)

	def warScriptAllow(self, iPlayer, iPlayer2):
		if iPlayer == gc.getBARBARIAN_PLAYER():
			return False
		pPlayer = gc.getPlayer(iPlayer)
		iTeam = pPlayer.getTeam()
		eTeam = gc.getTeam(iTeam)
		pPlayer2 = gc.getPlayer(iPlayer2)
		iTeam2 = pPlayer2.getTeam()
		if not eTeam.isHasMet(iTeam2):
			return False
		if eTeam.AI_getAtPeaceCounter(iTeam2) < 20:
			return False
#		if pPlayer.AI_getAttitude(iPlayer2) <= gc.getLeaderHeadInfo(pPlayer.getLeaderType()).getDeclareWarRefuseAttitudeThreshold():
#			return False
		if eTeam.isAtWar(iTeam2):
			return False
		if pPlayer.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_INFERNAL'):
			if pPlayer2.getStateReligion() == gc.getInfoTypeForString('RELIGION_THE_ASHEN_VEIL'):
				return False
		return True

	def dogpile(self, iPlayer, iVictim):
		pPlayer = gc.getPlayer(iPlayer)
		iBal = gc.getInfoTypeForString('CIVILIZATION_BALSERAPHS')
		for iPlayer2 in range(gc.getMAX_PLAYERS()):
			pPlayer2 = gc.getPlayer(iPlayer2)
			iChance = -1
			if pPlayer2.isAlive():
				if self.dogPileAllow(iPlayer, iPlayer2) and self.warScriptAllow(iPlayer2, iVictim):
					iChance = pPlayer2.AI_getAttitude(iPlayer) * 5
					if iChance > 0:
						iChance -= (pPlayer2.AI_getAttitude(iVictim) * 5) - 10
						if not CyGame().isOption(gc.getInfoTypeForString('GAMEOPTION_AGGRESSIVE_AI')):
							iChance -= 10
						if iChance > 0:
							iChance += (CyGame().getGlobalCounter() / 3)
							if pPlayer2.getCivilizationType() == iBal:
								iChance = CyGame().getSorenRandNum(50, "Dogpile")
							if CyGame().getSorenRandNum(100, "Dogpile") < iChance:
								self.startWar(iPlayer2, iVictim, WarPlanTypes.WARPLAN_DOGPILE)

	def dogPileAllow(self, iPlayer, iPlayer2):
		pPlayer = gc.getPlayer(iPlayer)
		pPlayer2 = gc.getPlayer(iPlayer2)
		if pPlayer2.isHuman():
			return False
		if iPlayer == iPlayer2:
			return False
		iTeam = gc.getPlayer(iPlayer).getTeam()
		iTeam2 = gc.getPlayer(iPlayer2).getTeam()
		if iTeam == iTeam2:
			return False
		if pPlayer2.getCivilizationType() == gc.getInfoTypeForString('CIVILIZATION_ELOHIM'):
			return False
		if gc.getTeam(iTeam2).isAVassal():
			return False
		return True
I don't think it can be turned off with game options, but you could of course edit the code to have things Return False before checking the various conditions that could lead to war.

It's annoying for players. How do I remove any 'category' from them completely? Auric Ascended appears to be this way, so I assume it can be done, but I don't want to mess up files I don't understand.

Auric Ascended (like all Golems except Barnaxus) has no UNITCOMBAT. If you don't want Hawks to ever get promotions, then you may edit CIV4UnitInfos.xml so that that the <Type>UNIT_HAWK</Type> entry's <Combat>UNITCOMBAT_ANIMAL</Combat> tag instead says <Combat>NONE</Combat>
Two more questions: Why can flight be turned on and off? It just adds more clutter, and there appears to be no downside to leaving it permanently on. And Decius appears to be evil ingame, though the character menu says he is neutral. Did you intend to make him evil?

Having flight permanently on prevents the use of roads and railroads. That would not matter to hawks anyway, but would matter to the Flesh Golems to which Hawks have been grafted.

Decius's alignment being determined by an event is standard FfH2 behavior designed by Kael and not altered by me at all. Religions changing alignment is also standard, with the only change being that one of my new religions (The White Hand) can also make players evil.


I did not know this. But the hawk should at least have the option removed. How do I do that?
You could remove the "Winged" promotion while leaving the "Flying" promotion in place for any unit you do not want to let toggle flying on and off.

a note on Sheaim...
currently playing them... and I found that the early game is "a-religious".
I tried a "bee-line" to pyre-zombies. not really a bee-line as I took the time to take hunting, calendar, animal husbandry and a few other to resist the enemies.
however I received religions from other civs during my early game but I couldn't take those.... it was frustrating.
OO gave me -2 fire mana... and pyre zombies need fire mana.
RoK was ok... but brings me to "neutral"... and pyre zombies need "evil".

so I didn't try to get FoL in case it would be science spent for nothing.

I think the Pyre zombie could get less restrictions : maybe remove the "evil" and replace it by "cannot be built by good" ?

It requires python instead of the more efficient xml, but ok.

I just changed it so that non-good players can build it, but as banned any member of the Overcouncil from training any undead unit after the resolution to ban death mana.

The unit's Strategy text needed updating anyway, so I included the new restriction descriptions there.
Hey,i can't download from the dl website(can't in my region) in the link you give in the OP.Anyone have a other up to date DL?

Hm, could it be that all those who have problems downloading are outside of the United States? I recall getting a mail some weeks ago that MyFlare discontinues offering its services to people outside the USA. At the time I thought this was only for uploaders, but with all the recent complaints it appears to me that this applies to downloads as well.

You can fix the DL?:confused:




I did not know this. But the hawk should at least have the option removed. How do I do that?

I think what he meant was, if you live in the US and can download both files maybe you could reupload them somewhere else?

I guess so, if I actually was living in America.

I live in the US and I am also getting a blank page when I try to load the download links.
I don't think locations is really relevant here.

I live in the US too (near Atlanta, Georgia) and have not been able to get the links to work either, even though I can download them just fine from my account there.

I did receive a message back from tech support at the website saying that they are working on the problem and should have it fixed soon, but since that has not happened yet I probably will want to host the next version elsewhere.
 

Attachments

  • Civ4ScreenShot0056.JPG
    Civ4ScreenShot0056.JPG
    199.5 KB · Views: 181
  • Civ4ScreenShot0055.JPG
    Civ4ScreenShot0055.JPG
    155.6 KB · Views: 132
  • Civ4ScreenShot0054.JPG
    Civ4ScreenShot0054.JPG
    181.2 KB · Views: 109
  • Civ4ScreenShot0053.JPG
    Civ4ScreenShot0053.JPG
    186.1 KB · Views: 84
  • Civ4ScreenShot0052.JPG
    Civ4ScreenShot0052.JPG
    180 KB · Views: 85
  • Civ4ScreenShot0051.JPG
    Civ4ScreenShot0051.JPG
    178.3 KB · Views: 127
It requires python instead of the more efficient xml, but ok.

I just changed it so that non-good players can build it, but as banned any member of the Overcouncil from training any undead unit after the resolution to ban death mana.

The unit's Strategy text needed updating anyway, so I included the new restriction descriptions there.
I think that it's a perfect solution.
No good, no Overcouncil...
well, in my game I've finally gotten the Ashen Veil, so I've resolved my religion problem :D
 
I have a new version pretty much ready to release. I'm going to test it a bit more first, but will probably release it by the end of the weekend (maybe even by the end of the day) unless I find a major bug or get a suggestion of something worth adding that takes longer to code.


The main changes are the addition of working PyHelp tags for these spells:

Add to Flesh Golem's help string will list all the promotions the Flesh Golem (which is identified by name, in case there are multiple flesh golems on the tile with custom names) will gain from the graft, and identify whether it will boost its combat/defensive strength.

Arcane Lacuna's text says how much xp your arcane units get and how long your enemies cannot cast spells

Destroy Clava Vindex's help string will list the names of all the captured demons that the spell will release, resurrect, and gift to the Infernals. (I considered also making it tell the player how much it would improve diplomacy with each Infernal player, but that is not possible because that depends in part on how the random number generator distributes the units among the different demon lords. Even just checking for their avatars, which give the biggest diplomatic bonus, would make the code far less efficient.)

Destroy Netherblade's help string will list the names of all the Sluaghs (minus the " 's Sluagh" part, which would disappear when resurrected) that the spell will allow to be resurrected.

Drown's help string will tell you if the unit is ineligible (due to being a hero, immortal, etc) or otherwise calculate the cost of the spell. Note that I also changed the formula to make the prices more reasonable. It used to be iGold = 5*strength*defense*level but is now iGold = 5 * (strength*defense + level*tier)

Kidnap's help strings list all the possibilities of great persons who may be targeted. Note that this spell previously chose targets in a set order (a Great Sage took precedent over a Great Engineer, over a Great Merchant, over a Great Artist), but I changed it to randomly select among all the great specialists settled there with the more common types being the more likely targets.

Sacrifice will now tell you how much research it will grant and towards what technology. If it is being cast on a Demon's Altar in an Infernal city (or in Auric's city after his Ascension), it will also tell you how much this will boost diplomatic relations with the city owner (who will gain Manes from the sacrifice).

Steal 's help strings list all the equipment types that the unit has a chance to steal from units or cities on that tile. (It cannot steal the Pieces of Barnaxus/The Mithril Golem/TheWar Machine from those respective units.)

Recruit's help string will tell you whether it requires sacrificing the caster (which it will unless the caster is a world/national/team unit) and will also tell you how many units it will recruit from among a list of unit types. Note that I changed how that list is determined, to be more elegant and hopefully more efficient. Since it can only choose units that may be trained in that city, it cannot be used in Settlements.

River of Blood's help text says how much xp it grants all your vampires.

Sanctuary's text says how many turns the effect will actually last (which is based on the game speed and not always 30 as it once said)

Stasis's text says how long rivals will be unable to research or produce anything.

Take Equipment (Promotion) spells all have their help text changed to identify the name of the specific unit that will be loosing that promotion.



Note that spells whose effects depend on random numbers cannot be predicted perfectly. I could list possible outcomes only, and the code to do so might be very inefficient.

I thought about making spells like Pillar of Fire identify their victims, but a list of units could get so large that it makes everything else in the help mouseover unreadable. I'm not sure how I'd go about identifying a targeted tile in a way the player would understand, as coordinates are not shown in-game.
Edit: I decided it was not so bad anyway, and so made almost all the spells which target specific units in python count how many units they can target and list them by name. (Exceptions include Reveal, as it would kind of be cheating to list units that are invisible before casting the spell. I also did not consider the fortifying/unfortifying effects of treetop defense or earthquake to be worth it. )

Are there any more spells whose effects you think will need a more detailed in-game explanation? Now is the time to suggest them, as well as to suggest hosting sites that work for all of you.
 
- The Radiant Guard scenario seems altogether unplayble. The game crashes after showing the intro/outro screen.

- Are there any quests in the game? I don&#8217;t recall having seen any.

- Could you make the custom game remember the previous settings and civs selection?

- Concering the hawks. Wouldn&#8217;t it be more fitting to use them as a regular summoned unit with the duration of one turn and ignoring terrain(a bit like floating eyes in the original FFH)? Right now the hawks can reveal a ridiculously huge amount of terrain in one flight. My idea is that certain recon units could buy this &#8222;spell&#8220; in hunting lodges.

- Suggestion about cities: Conquered cities would change their cultural appearance as soon as the conquering nation reaches majority on the city&#8216;s nationality bar.
 
I use Moddb, which seems to work fine. I've no idea where the problems are coming from or the advantages/disadvantages are of different sites, though.

- Are there any quests in the game? I don&#8217;t recall having seen any.

The quests tab itself is forever barren, but there are many different events which function as, or in a similar way to, quests.
 
I just wrote up a detailed description of the changes this version would include, but did not save a copy of it before trying to submit and getting a message that my token has expired so I needed to go back and reload. I lost everything I'd written, and don't feel like doing it all over again.

The short version:
I added a lot more PyHelp Tags. I had written out details on everything they would explain, but hopefully they will be self explanatory enough when you see then in the game

I will note that I changed how Teach Golems and Teach Spellcasting work. Students may now include those on adjacent tiles, not only on the same tile as the teacher.

They are really still passive effects, but I added dummy spells which do absolutely nothing but provide PyHelp explanations for them. Those mouseovers will list what promotions the unit can teach, what units can be taught, and the odds of teaching that turn. (Specifying what units can learn what promotions seemed too complicated for me to code, and it cold look really messy in game if Govannon knows enough magic. It also states the odds of the unit teaching lessons that turn. The odds are basically just the unit's xp, or 0 if there is no student able to learn what he can teach. It is still possible for the teacher to pick the wrong lessons to the wrong student though and end up teaching nothing.)


- The Radiant Guard scenario seems altogether unplayble. The game crashes after showing the intro/outro screen.
I tested it and found the same problem, but have not found a solution yet and did not want this rarely-played scenario to hold up the release for everyone
- Are there any quests in the game? I don&#8217;t recall having seen any.
I don't think "quests" are really used in any FfH2 mod. I'm not very familiar with how they work
- Could you make the custom game remember the previous settings and civs selection?
I don't think there is a way to make it remember civs. It could be made to remember game options, but that can cause problems due to options carrying over from other mods where they do different hings. With hidden options, you could get stuck using some game option that was only meant for a specific scenario and would cause massive problems in a random game.
- Concering the hawks. Wouldn&#8217;t it be more fitting to use them as a regular summoned unit with the duration of one turn and ignoring terrain(a bit like floating eyes in the original FFH)? Right now the hawks can reveal a ridiculously huge amount of terrain in one flight. My idea is that certain recon units could buy this &#8222;spell&#8220; in hunting lodges.

I don;t have much to do with how much territory they can reveal. That is a base FfH2 complaint. I just made the Call Animal Spell and added them to he list. I don;t have any plans to change it.
- Suggestion about cities: Conquered cities would change their cultural appearance as soon as the conquering nation reaches majority on the city&#8216;s nationality bar.

This would involve messing with the code I used for the Arrogator/Tolerant trait to make culture matter mroe than original owener while not allowing the Infernals of Mercurian players to preserve the culture of their opposite. That was such a hassle for so long that I don;t want to touch it again.

I use Moddb, which seems to work fine. I've no idea where the problems are coming from or the advantages/disadvantages are of different sites, though.

I think the reason I was not using that site might have been that I made an account a long time ago with an of email address which no longer exists, so I could not access it to make a new one under the MagisterCultuum name.

I just made account under the name Magister343, and just uploaded them. (The upload took long enough to make it a different day as is included in the file name and I realized only after uploading that I forgot to update the mod name as displayed in the game, but I guess that doesn't really matter much.)

Let's see if these links work:

You may download the installer here or the archive here.


Edit: I just found a bug after uploading.

It does not alter gameplay in anyway, but will prevent the Repair spell's PyHelp text from properly displaying what units can be healed by the ability.

In line 7350 of CvSpellInterface.py, [iSiege, iNaval] should be replaced with lCombats.

I had changed def reqRepair(pCaster) and def spellRepair(pCaster, iAmount) since I saw no need to define the two unitcombat variables separately, but in def helpRepair(lpUnits) I changed the defines at the top but forgot to change that line within the loop.

If the latest host doesn't work out, I'll reupload with this bug fix soon. I think it is a minor enough issue you can handle it yourself though.

EDit2: And now I see that in spellBlizzard(pCaster), the pPlot2 in line 2762 should just be pPlot
Edit3: I found another bug in spellBlizzard. Just replace the whole thing with this:
Spoiler :
Code:
def helpCallBlizzard(lpUnits):
szBuffer = ''
pCaster = lpUnits[0]
lDirections = ['North', 'Northeast', 'East', 'Southeast', 'South', 'Southwest', 'West', 'Northwest']
lTargets= []
iBlizzard = gc.getInfoTypeForString('FEATURE_BLIZZARD')
iTundra = gc.getInfoTypeForString('TERRAIN_TUNDRA')
iX = pCaster.getX()
iY = pCaster.getY()
pPlot = pCaster.plot()

for iDirection in range(DirectionTypes.NUM_DIRECTION_TYPES):
pPlot2 = plotDirection(iX, iY, DirectionTypes(iDirection))
if pPlot2.isNone():continue
if pPlot2.getFeatureType() == iBlizzard:
lTargets.append(iDirection)
if len(lTargets) > 0:
sList = ''
while len(lTargets) > 0:
iDirection = lTargets.pop(0)
sList += lDirections[iDirection]
if len(lTargets) > 0:
if len(lTargets) == 1:
sList += " or "
else:
sList += ", "
szBuffer += CyTranslator().getText("TXT_KEY_HELP_SPELL_CALL_BLIZZARD", (sList,))
return szBuffer

def spellCallBlizzard(pCaster):
iBlizzard = gc.getInfoTypeForString('FEATURE_BLIZZARD')
iTundra = gc.getInfoTypeForString('TERRAIN_TUNDRA')
iX = pCaster.getX()
iY = pCaster.getY()
pPlot = pCaster.plot()
lBlizPlots = []
for iDirection in range(DirectionTypes.NUM_DIRECTION_TYPES):
pPlot2 = plotDirection(iX, iY, DirectionTypes(iDirection))
if pPlot2.isNone():continue
if pPlot2.getFeatureType() == iBlizzard:
lBlizPlots.append(pPlot)
if len(lBlizPlots) > 0:
pBlizPlot = lBlizPlots.pop(CyGame().getSorenRandNum(len(lBlizPlots), "Call Blizzard"))
if pBlizPlot.isHasTempFeature():
iTimer = pBlizPlot.getTempFeatureTimer()
iFeature = pBlizPlot.getRealFeatureType()
iVariety = pBlizPlot.getRealFeatureVariety()
pBlizPlot.setFeatureType(iFeature, iVariety)
if not pPlot.isHasTempFeature():
if iTimer >= pPlot.getTempFeatureTimer():
pPlot.setTempFeatureType(iBlizzard, 0, iTimer)
elif pPlot.getFeatureType() == -1:
pPlot.setFeatureType(iBlizzard, 0)
pBlizPlot.setFeatureType(-1, -1)
else:
pPlot.setTempFeatureType(iBlizzard, 0, pCaster.getLevel())

#Changed in Blizzards: TC01
Blizzards.doBlizzard(pPlot)
# Original Code:
# if pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_GRASS'):
# pPlot.setTerrainType(iTundra,True,True)
# if pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_PLAINS'):
# pPlot.setTerrainType(iTundra,True,True)
# if pPlot.getTerrainType() == gc.getInfoTypeForString('TERRAIN_DESERT'):
# pPlot.setTerrainType(iTundra,True,True)
#End of Blizzards
 
So, it looks like there have been 22 downloads so far. Anyone care to offer feedback?

I'll probably release another version within a week, but I want to make sure that all the bugs are fixed and that I can to implement any decent fan suggestions first.

Since the release I have fixed a couple of minor bugs, made a couple things run more efficiently, added a few more PyHelp tags and clarified the text in a couple old ones.

I now have Vitalize, Spring, and Scorch explaining exactly the changes you will see once they are cast. (It won't explain the real terrain changes if there is temp terrain there, as the player shouldn't know about that.)

For Spring, that includes the directions of the Smoke or Flames it removes.


I now have Shape Shift telling you what unit and promotions the changeling will copy, and Assume True Form identifying what that true form is.

I realized that it actually would not be that hard to change the Teach Spellcasting and Teach Golems so that they inform you exactly what promotions may be taught to what units. I think the code is even more efficient this way, so I'm going with it.

I made Teach Golems also list how many units would be taught something that turn.

The odds of a single unit with Govannon's Ethics teaching something can be determined simply by it xp and whether it has anything to teach anyone, but calculating such odds for a whole group of units that know different spells is practically impossible. The odds displayed for groups in my last version are wrong and misleading. I just now changed it so that odds will only be displayed when there is a single selected unit capable of teaching something.


I'm still trying to decide whether the daunting task of explaining Sanctify's exact effects is worth coding.

I may make spells like Ring of Fire also state the direction of where they change the terrain/feature/improvement. I have to loop through directions rather than tiles for this though, and can't do it for spells with more than a one tile range.

I'm still considering the value of adding PyHelp even to xml only spells, to identify exactly what units they can target. Originally I thought it would be way too inefficient, but I think the code would only run if a human mouses over the button. The big inefficiencies come from AI's checking spell prereqs.
 
So, it looks like there have been 22 downloads so far. Anyone care to offer feedback?

I'll probably release another version within a week, but I want to make sure that all the bugs are fixed and that I can to implement any decent fan suggestions first.

Since the release I have fixed a couple of minor bugs, made a couple things run more efficiently, added a few more PyHelp tags and clarified the text in a couple old ones.

I now have Vitalize, Spring, and Scorch explaining exactly the changes you will see once they are cast. (It won't explain the real terrain changes if there is temp terrain there, as the player shouldn't know about that.)

For Spring, that includes the directions of the Smoke or Flames it removes.


I now have Shape Shift telling you what unit and promotions the changeling will copy, and Assume True Form identifying what that true form is.

I realized that it actually would not be that hard to change the Teach Spellcasting and Teach Golems so that they inform you exactly what promotions may be taught to what units. I think the code is even more efficient this way, so I'm going with it.

I made Teach Golems also list how many units would be taught something that turn.

The odds of a single unit with Govannon's Ethics teaching something can be determined simply by it xp and whether it has anything to teach anyone, but calculating such odds for a whole group of units that know different spells is practically impossible. The odds displayed for groups in my last version are wrong and misleading. I just now changed it so that odds will only be displayed when there is a single selected unit capable of teaching something.


I'm still trying to decide whether the daunting task of explaining Sanctify's exact effects is worth coding.

I may make spells like Ring of Fire also state the direction of where they change the terrain/feature/improvement. I have to loop through directions rather than tiles for this though, and can't do it for spells with more than a one tile range.

I'm still considering the value of adding PyHelp even to xml only spells, to identify exactly what units they can target. Originally I thought it would be way too inefficient, but I think the code would only run if a human mouses over the button. The big inefficiencies come from AI's checking spell prereqs.

I have been trying to play the Illians and find them very hard to use in this version. Their econ is very weak, and they struggle to get a foothold. I think it takes them too long to get White hand rolling. White hand is effectively a late game religion in your mod, but it is much weaker than the other religions. Perhaps move this to Mysticism?

Food is a real struggle since we can't free build farms. Perhaps allow camps on Tundra/ice, and change the hunters hall bonus specialists to per deer/fur/penguin instead of per camp?
 
Just uploaded the new version.

I did so as an edit to the previous uploads, as the site complained when I tried to have them host each version separately. That could be a problem for those who still want to access the previous version, but hose who want the latest improvements are free to use the old links again.

----
I ended up including a PyHelp function for pretty much every spell you'd ever be able to cast.

It will tell you what units may be targeted for both python and xml effects, including adding/removing promotions, damaging, healing, converting, etc.

The targeted units will appear listed by name written in the player color of their owners.

Spells that effect diplomacy will list the players who will think better or worse of you, in their respective colors.

It will list promotion details of the promotions to be added or removed and the unit details of units that will be summoned or to which something will convert.

(Edit: I just now realized I put nothing for Revelation. I did not want to make it list what units it would reveal as that would reduce the need to reveal them, but I had intended to make it inform the player of its other effects like damaging any nearby vampires. I guess that can wait for the next version.)

I completely re-wrote "Wonder" and "Read from the Grimoire," so that they may list the various possible effects and so that neither will cause a python error trying to cast an impossible spell.

---
@Sezneg:
It fits the lore well for the Illians to be a backwards and weak civilization in comparison with everyone else.

Moving their religion back so early as Mysticism would be too much, imho, but I agree that waiiting for Priesthood is too long.

At first I tried moving the ritual back to Philosophy, where Kael put in in base FfH2, but then decided that Knowledge of the Ether really makes the most sense. Before completing rituals to claim mastery over the Precept of Winter, Autic Ulvin was basically just a precocious (mostly self-taught) Adept who used his arcane magic to trick others into viewing him as a god. That tech is more thematic and is also directly in the line of research needed for ascension.

(One reason I might have chosen Philosophy is that provides so little compared to more cluttered techs in the tech tree. I decided to move Monks there instead.)

I also made the White Hand ritual a bit cheaper, and reduced the cost of Priests of Winter to be the same as the priests of other religions.

I decided to give Dumannios Command I instead of Bounty Hunter, and to give Auric all the promotions that any of his lieutenants have. (The defrock spell no longer applies to Avatars of leaders, so Auric should not be able to be killed that way.) I also gave Auric +1 Ice affinity.

The Illians' extra yields for Snow should let them build farms as if the now were Grasslands. The Temple of the Hand also gives a large food storage bonus and free food with ice mana, so I don;t think food will be that big of a deal.
 
So, I just found my first bug with today's release.

The problem is with the Nullstone Citadel's effect appling where it should not. It won't matter at all before that late game wonder is built, but afterwards it will stop any unit in any city belonging to a different team from casting, rather than only blocking casting in the vicinity of the Nullstone Citadel itself.


In lines 336 and 375 of CvSpellInterface.py, I forgot to include the lines I just put there in green (and of course indent the next two lines).
Spoiler :
Code:
def helpBlockedByNullstone(lpUnits, eSpell):
	szBuffer = ''
	pCaster = lpUnits[0]
	pPlot = pCaster.plot()
	if pPlot.isCityRadius():
		if CyGame().getBuildingClassCreatedCount(gc.getInfoTypeForString('BUILDINGCLASS_NULLSTONE_CITADEL')) > 0:
			iNullstone = gc.getInfoTypeForString('BUILDING_NULLSTONE_CITADEL')
			iTeam = pCaster.getTeam()
			bBlock = False
[COLOR="Red"]
			if pPlot.isCity():
				pCity = pPlot.getPlotCity()
			[COLOR="Green"]	if pCity.getNumBuilding(iNullstone) > 0:[/COLOR]
					if pCity.getTeam() != iTeam:
						bBlock = True[/COLOR]
			if not bBlock:
				pCity = pPlot.getWorkingCity()
				if not pCity.isNone():
					if pCity.getNumBuilding(iNullstone) > 0:
						if pCity.getTeam() != iTeam:
							bBlock = True
			if not bBlock:
				iX = pCaster.getX()
				iY = pCaster.getY()
				for iiX in range(iX-3, iX+4, 1):
					for iiY in range(iY-3, iY+4, 1):
						pPlot = CyMap().plot(iiX, iiY)
						if pPlot.isNone():continue
						if pPlot.isCity():
							pCity = pPlot.getPlotCity()
							if pCity.getNumBuilding(iNullstone) > 0:
								if pCity.getTeam() != iTeam:
									bBlock = True

			if bBlock:
				pPlayer = gc.getPlayer(pCity.getOwner())
				sName = "<color=%d,%d,%d,%d>%s</color>" %(pPlayer.getPlayerTextColorR(), pPlayer.getPlayerTextColorG(), pPlayer.getPlayerTextColorB(), pPlayer.getPlayerTextColorA(), pCity.getName() )
				szBuffer = CyTranslator().getText("TXT_KEY_SPELL_HELP_NULLSTONE_RAZE", (sName, sName,))

	return szBuffer

def effectBlockedByNullstone(pCaster):
	pPlot = pCaster.plot()
	if pPlot.isCityRadius():
		if CyGame().getBuildingClassCreatedCount(gc.getInfoTypeForString('BUILDINGCLASS_NULLSTONE_CITADEL')) > 0:
			iNullstone = gc.getInfoTypeForString('BUILDING_NULLSTONE_CITADEL')
			iTeam = pCaster.getTeam()
			bBlock = False

		[COLOR="Red"]	if pPlot.isCity():
				pCity = pPlot.getPlotCity()
			[COLOR="Green"]	if pCity.getNumBuilding(iNullstone) > 0:[/COLOR]
					if pCity.getTeam() != iTeam:
						bBlock = True[/COLOR]
			if not bBlock:
				pCity = pPlot.getWorkingCity()
				if not pCity.isNone():
					if pCity.getNumBuilding(iNullstone) > 0:
						if pCity.getTeam() != iTeam:
							bBlock = True
			if not bBlock:
				iX = pCaster.getX()
				iY = pCaster.getY()
				for iiX in range(iX-3, iX+4, 1):
					for iiY in range(iY-3, iY+4, 1):
						pPlot = CyMap().plot(iiX, iiY)
						if pPlot.isNone():continue
						if pPlot.isCity():
							pCity = pPlot.getPlotCity()
							if pCity.getNumBuilding(iNullstone) > 0:
								if pCity.getTeam() != iTeam:
									bBlock = True

			if bBlock:
				pCaster.setHasCasted(True)
				return True
	return False

Actually, it would be probably better just to delete the whole red blocks. There was no good reason for me to add them. I thought that it would be more efficient to check the plot itself for a city first, but now that I check the C++ code for getWorkingCity() I see it does that first anyway and C++ runs much more efficiently.
Edit: Apparently that can still get the city's name wrong. Just use this code instead:
Spoiler :
Code:
def helpBlockedByNullstone(lpUnits, eSpell):
	szBuffer = ''
	pCaster = lpUnits[0]
	pPlot = pCaster.plot()
	if pPlot.isCityRadius():
		if CyGame().getBuildingClassCreatedCount(gc.getInfoTypeForString('BUILDINGCLASS_NULLSTONE_CITADEL')) > 0:
			iNullstone = gc.getInfoTypeForString('BUILDING_NULLSTONE_CITADEL')
			iTeam = pCaster.getTeam()
			pCity = pPlot.getWorkingCity()
			if not pCity.isNone():
				if pCity.getNumBuilding(iNullstone) > 0:
					if pCity.getTeam() != iTeam:
						pPlayer = gc.getPlayer(pCity.getOwner())
						sName = "<color=%d,%d,%d,%d>%s</color>" %(pPlayer.getPlayerTextColorR(), pPlayer.getPlayerTextColorG(), pPlayer.getPlayerTextColorB(), pPlayer.getPlayerTextColorA(), pCity.getName() )
						return CyTranslator().getText("TXT_KEY_SPELL_HELP_NULLSTONE_RAZE", (sName, sName,))

			else:
				iX = pCaster.getX()
				iY = pCaster.getY()
				for iiX in range(iX-3, iX+4, 1):
					for iiY in range(iY-3, iY+4, 1):
						pPlot = CyMap().plot(iiX, iiY)
						if pPlot.isNone():continue
						if pPlot.isCity():
							pCity = pPlot.getPlotCity()
							if pCity.getNumBuilding(iNullstone) > 0:
								if pCity.getTeam() != iTeam:
									pPlayer = gc.getPlayer(pCity.getOwner())
									sName = "<color=%d,%d,%d,%d>%s</color>" %(pPlayer.getPlayerTextColorR(), pPlayer.getPlayerTextColorG(), pPlayer.getPlayerTextColorB(), pPlayer.getPlayerTextColorA(), pCity.getName() )
									return CyTranslator().getText("TXT_KEY_SPELL_HELP_NULLSTONE_RAZE", (sName, sName,))
	return szBuffer

def effectBlockedByNullstone(pCaster):
	pPlot = pCaster.plot()
	if pPlot.isCityRadius():
		if CyGame().getBuildingClassCreatedCount(gc.getInfoTypeForString('BUILDINGCLASS_NULLSTONE_CITADEL')) > 0:
			iNullstone = gc.getInfoTypeForString('BUILDING_NULLSTONE_CITADEL')
			iTeam = pCaster.getTeam()
			pCity = pPlot.getWorkingCity()
			if not pCity.isNone():
				if pCity.getNumBuilding(iNullstone) > 0:
					if pCity.getTeam() != iTeam:
						pCaster.setHasCasted(True)
						return True
			else:
				iX = pCaster.getX()
				iY = pCaster.getY()
				for iiX in range(iX-3, iX+4, 1):
					for iiY in range(iY-3, iY+4, 1):
						pPlot = CyMap().plot(iiX, iiY)
						if pPlot.isNone():continue
						if pPlot.isCity():
							pCity = pPlot.getPlotCity()
							if pCity.getNumBuilding(iNullstone) > 0:
								if pCity.getTeam() != iTeam:
									pCaster.setHasCasted(True)
									return True
	return False
 
Back
Top Bottom