[MOD] MagisterModmod

How long is a while?

Having Revolutions active does make it run slower, but I suspect the main thing that slows things down is running the def unitCannotMoveInto(self,argsList): callback. (I need to use that callback in order to make the Ring of Warding building prevent hostile summons from entering the city, in order to prevent the demon lords from entering non-hell terrain only outside of the own borders, and to prevent bAlwaysHostile units from causing problems by entering rival cities or superforts while not at war.) Those changes aren't all that recent though. If anything, I think the last few versions should have gotten faster.
 
Around 30-40 sec, but only 100 turn in. I do play on a giant map with 14 civs's, and I understand that as the map fills out turn times do increase, however, this is very early with each civ only having one city (playing on edited marathon speed, 3600 turns).

My CPU is quite new, 3.6GHz, and is normally fast on most 'big' mods (MOM, Rise of mankind, RI etc).
 
I don't think it's that unbalanced. Each civ's strong points are emphasized through flavor and it makes the game much more comfortable to play (and hey, that means each civ can use their strong points in multiplayer). I especially like that the rather weak magic system got improved.
 
More annoying than unbalanced. The ai that is supposed to be on my side is sitting outside my city casting spore. There are no enemies nearby I have no idea why the ai would do that. I had cancel open borders to get rid of the unit.

Spore keeps you from moving btw in case your not familiar with the spell
 
I don't think I've ever actually changed anything about Spore.

(That is, unless you count changing spaces to tab just to make the file look nicer, which has no effect on gameplay whatsoever.)


It does not effect teammates, but a master or vassal is not a teammate. They are treated like any other rival with whom you are not at war.

If you want it to only effect hostile units, you need to add the line I put here in red:

Magister Modmod for FfH2\Assets\XML\Units\CIV4SpellInfos.xml:
Code:
		<SpellInfo>
			<Type>SPELL_SPORES</Type>
			<Description>TXT_KEY_SPELL_SPORES</Description>
			<Civilopedia>TXT_KEY_SPELL_PLACEHOLDER_PEDIA</Civilopedia>
			<UnitPrereq>UNIT_MYCONID</UnitPrereq>
			<bAllowAI>1</bAllowAI>
			<bCausesWar>1</bCausesWar>
			<bDisplayWhenDisabled>1</bDisplayWhenDisabled>
			<bHasCasted>1</bHasCasted>
			<bResistable>1</bResistable>
			<iRange>1</iRange>
			<bImmuneTeam>1</bImmuneTeam>
			[COLOR="Red"]<bImmuneNeutral>1</bImmuneNeutral>[/COLOR]
			<bImmuneNotAlive>1</bImmuneNotAlive>
			<iImmobileTurns>3</iImmobileTurns>
			<Effect>EFFECT_SPORES</Effect>
			<Sound>AS3D_SPELL_CONTAGION</Sound>
			<Button>Art/Interface/Buttons/Spells/Spores.dds</Button>
		</SpellInfo>
 
So spore was intended to be able to be used on people you're neutral with? I suppose it could have some uses. But the ai seems to be stupid with it so I'll think I'll add that line of code. Thanks for the reply.
 
Whats the code to make a unit be a national unit? In the base FFH2 Crossbowmen were limited to 4 which I liked. I think I want to put that into my game rather than just reduce the strength of the Crossbowmen.
 
Whats the code to make a unit be a national unit? In the base FFH2 Crossbowmen were limited to 4 which I liked. I think I want to put that into my game rather than just reduce the strength of the Crossbowmen.

Assets/XML/Units/CIV4UnitClassInfos.xml
search for
Code:
<Type>UNITCLASS_CROSSBOWMAN</Type>
and change
Code:
<iMaxPlayerInstances>-1</iMaxPlayerInstances>
below to
Code:
<iMaxPlayerInstances>4</iMaxPlayerInstances>
 
Thanks, I'm guessing that <iMaxPlayerInstances>-1</iMaxPlayerInstances> means unlimited, and anything other than 1 means the limit?
 
Thanks, I'm guessing that <iMaxPlayerInstances>-1</iMaxPlayerInstances> means unlimited, and anything other than 1 means the limit?

Anything other than -1 means limit, yeah :). Same for team and world units. I think if you set it to 0 the unit can never be built.
 
I was just wondering whether anyone would like me to incorporate into Magister Modmod this bit of code that I wrote for someone in the Mod Component Requests Thread.

It would introduce more variety in city names (particularly on smaller maps), and might get rid of the oddity in the Wages of Sin scenario where they refer to Borne the Gleaming as a far away city even though it would already be on that map if Basium ever founded a single city.

I'd like something that would randomize city names when founded. The first city would always be the same (London, Washington, etc), but every other city would have a random name from the given list of city names. I find that I usually only have the first 6 or so cities, and I'd appreciate the variety. Thanks!

That would require DLL modification. Looks like it's handled in the function CvPlayer::getCivilizationCityName()

Modifying the DLL may be cleaner and more efficient, but it is not actually necessary.

It is possible to use python to rename a city as soon as it is founded.

It is even possible to use python to extract a list of city names from CIV4CivilizationInfos.xml and then randomly select a one of those names for a city.


As proof, I offer you this bit of code which I just now wrote and tested. It seems to work exactly as lugialord desires.


CvEventManager.py
Code:
	def onCityBuilt(self, argsList):
		'City Built'
		city = argsList[0]
		if not city.isCapital():
			iCiv = city.getCivilizationType()
			iPlayer = city.getOwner()
			py = PyPlayer(iPlayer)
			listCityNames = []

			CivFile = open("Assets/XML/Civilizations/CIV4CivilizationInfos.xml")
			bCiv = False
			for line in CivFile.readlines():
				if "<Type>" in line:
					sCiv = line[line.find(">") +1 : line.find("</")]
					if iCiv == gc.getInfoTypeForString(sCiv):
						bCiv = True
					else:
						bCiv = False
				elif bCiv:
					if "<City>" in line:
						txtKeyCity = line[line.find(">") +1 : line.find("</")]
						sName = localText.getText(txtKeyCity, ())
						for pyCity in py.getCityList():
							if pyCity.GetCy().getName == sName:
								break
						else:
							listCityNames.append(sName)

			if len(listCityNames) > 0:
				sName = listCityNames.pop(CyGame().getSorenRandNum(len(listCityNames), "Name city"))
				city.setName(sName, False)


		if (city.getOwner() == gc.getGame().getActivePlayer()):
			self.__eventEditCityNameBegin(city, False)
		CvUtil.pyPrint('City Built Event: %s' %(city.getName()))


The first version of this code which I tested required explicitly defining a list of city names for each civ in python, which was a bit of a hassle so I only actually got it working for 2 civs. That way is not very versatile and would require reprogramming for each mod.

I would not have known how to use python to read the files like that had I not come across something similar in the code of Platy World Builder, so Platyping deserves some of the credit.

Note: This code will probably not work well in modular mods where some civs (and thus their city lists) are defined in separate files.

It would also not work great in mods that write the city names directly in the CIV4CivilizationInfos.xml rather than using TXT_KEYs. I believe that would make it possible for some ciities to be given the name "-1."
 
Speaking of crossbowman, Magister, why did you decide to make them an unlimited unit instead of a national one?
 
It never really made sense to be more Crossbowmen to be national units. In the real world, the main advantage of the Crossbow over the Longbow was the fact that it was relatively easy to quickly train large numbers of new recruits to kill with Crossbows. The Longbow remained a superior weapon in the hands of a highly skilled archer, but it took a lot of practice to become really good with it. If anything it would make more sense for the Longbow to be the national unit, but it is a more primitive technology.
 
Well, maybe in a new mod-mod we could make Crossbows not stronger, but just cheaper to build :D

Hmm, if longbows are 5/7 with iweapontier2 ... (for max of 7/9) ... and @ 120 hammers,

Then perhaps Crossbows should be 7/8 @ 80 hammers? (without the city defense bonus)

Would make more sense for something at Machinery imho.


--- Inadvertently, did you know that you have a Game of Thrones Scenario for your momod? ^_^
 
While playing this multiplayer we always get out of sync, is there any way to solve it? This modmod is probably the best while still recieving the original fall from heaven feel, so it's a bit of a shame that it appears unstable on multiplayer. I am not sure if it's only me getting it though.

EDIT: Although I should add that it's always me with the different values during an oos (the host.)
 
I'm afraid I don't know much about multiplayer Civ IV. I've never played a game with someone on a different computer. (I have started some hotseat games against my sister, but she always gave up within a few turns and left me playing against myself.)

If the OOS issues are worse in MagisterModmod than in MNAI, I'd guess that the problems come from those effects that work through python prereqs for dummy spells. They are triggered whenever certain unit are selected. I'd guess that multiplayer games don't share data of when or how often units are selected.

Placing effects in prereqs is probably considered bad form, but it makes possible a lot of things that would otherwise require significant SDK work.


I removed random number generation for the passive spell effects a while back because I figured it was a major cause of OOS issues. (Random numbers are actually only pseudo random, so each time one it used it changes what the next one will be. Having different numbers of random numbers selected on different computers seems to be the main cause of OOS issues.) At least, I thought I removed all the random numbers. I just now realized that the random number generator is used in def findClearPlot(self, pUnit, plot): in CustomFunction.py, and that function is still called by effectDefectLugus(pCaster), effectCultusDraconis(pCaster), effectDefectAuric(pCaster), and effectDefectSelf(pCaster).

That means that the following situations will likely lead to OOS issues:
1. A Calabim unit of The Empyrean religion is on a plot owned by an enemy who has The Empyrean as a state religion.

2. A unit of The Cult of the Dragon religion, whose team does not own a dragon, is on a tile owned by a player who does.

3. A unit of The White Hand religion is on a plot owned by Auric Ulvin, its owner is at war with Auric Ulvin, Auric Ulvin (the unit) is still alive, and The Draw has been completed.

4. A unit which is the avatar of a leader is alive but belongs to a player other than the one of which it is as avatar. (The most common example of this happening is when the minor leader Baron Duin Halfmorn enters the game after someone already has built the werewolf hero, or when a unit with Subdue Beasts captures the hero from the leader.)


I'm not sure if I actually need to call pPlot = cf.findClearPlot(-1, pPlot) in those effects. (I'm almost positive that it is not necessary in the 4th case.) I'm about to test to see if eliminating those lines causes any problems.

In the meantime you may want to play with the "Remove Religion - The Empyrean," "Remove Religion - The Cult of the Dragon," "No Duin," and "Remove Rituals" game options active in your multiplayer games. ("Remove Rituals" should not be necessary unless Auric Ulvin is present in the game. "Remove Religion - The Empyrean" should not be necessary if there are no Calabim players in the game. "No Duin" would not be necessary unless the Revolutions or Puppet States options are active, and even then probably only if the Doviello are in the game.)

Edit: Removing pPlot = cf.findClearPlot(-1, pPlot) from effectDefectLugus(pCaster), effectCultusDraconis(pCaster), or effectDefectAuric(pCaster) can cause weird behavior when large stacks of units contain some of those who will defect. The new unit is initiated on the old unit's current tile, pushing all the others away. This can happen repeatedly, scattering the stack all over the place. It is just too much.

I'm considering commenting out the random portions of def findClearPlot(self, pUnit, plot): instead.
 
can't the defected unit just arrive in a random city of the new owner? Like owner.getcity or something?
 
I believe I had already eliminated the issue by re-writing the function to be def findClearPlot(self, pUnit=-1, plot=-1, bRnd = True):, where passing the value of False to the last parameter (which defaults to True if you do not pass that parameter at all) makes the code skip the 2 lines that involve generating random numbers.


In the case of effectDefectSelf(pCaster), def findClearPlot(self, pUnit, plot): was only ever invoked if the player to which it was defecting has no cities. I've switched it so that even that is not used now.


I do not like the idea of having the units appear in random cities, as a random city could be on the opposite side of the map.

It may however make sense to have the unit appear in the closest city (found using using CyMap().findCity(iX, iY, iPlayerPlot, TeamTypes.NO_TEAM, False, False, TeamTypes.NO_TEAM, DirectionTypes.NO_DIRECTION,pPlayerPlot.getCity(-1)), which would only find a city belonging to the right player if it can be reached by a land route from the location of (iX,iY) ) when it is defecting to the control of a player whose cultural borders it is within.

I'm thinking now that it may actually be best to have such units defect only if the closest city has the right religion present, just as they only defect to the tile of a rival unit if said unit is of the right religion.

That makes the effects less overpowered for the civs who benefit, and encourages spreading the right religions. (Previously those who captured Acheron would still want to eliminate The Cult of the Dragon from all of their cities, to avoid the risk of trouble if and when they loose their dragon.)


-----


I recently given Worldbuilder the ability to set units as avatars of leaders, and to set whether a player has yet accomplished the World Spell, Shrine of Sirona, and Trust feats.

In another thread, platyping recently criticized by use of the for pUnit in py.getUnitList(): style of coding as needlessly inefficient, as it uses a whole loop to search all units before appending them to a list and then uses a for loop to search that list for specific units. I have sense gone through the files that I'd already changed and switched to using just a for loop instead. I cannot be sure since I've been testing on duel size maps, but I think this may be causing significant speed increases.

There are a couple other things I ran across that I've changed to run more efficiently too.

I found and fixed a bug that was causes all scenarios to be treated as if the Control Whole Teams game option was active, even when it is not.


Looking into the Splintered Court code, I think I could make it work so that units infected with Lycanthropy could switch back and forth between the beast and what they were before. Do you think it is worth pursuing such a major change in mechanics?
 
It never really made sense to be more Crossbowmen to be national units. In the real world, the main advantage of the Crossbow over the Longbow was the fact that it was relatively easy to quickly train large numbers of new recruits to kill with Crossbows. The Longbow remained a superior weapon in the hands of a highly skilled archer, but it took a lot of practice to become really good with it. If anything it would make more sense for the Longbow to be the national unit, but it is a more primitive technology.
Makes sense. The crossbow probably needs a bit of a nerf though.

I'm afraid I don't know much about multiplayer Civ IV. I've never played a game with someone on a different computer. (I have started some hotseat games against my sister, but she always gave up within a few turns and left me playing against myself.)

Ah, I know that feeling.
 
Back
Top Bottom