Teg_Navanis
King
- Joined
- Jan 21, 2006
- Messages
- 737
I wrote a little python script to convert MaxRiga's Mod to Beyond the Sword, and I thought I might as well publish it here in case someone else can use it for his/her mod. It converts the following files:
CIV4UnitInfos,
CIV4ArtDefines_Unit,
CIV4UnitClassInfos,
CIV4TechInfos,
CIV4BuildingClassInfos,
CIV4BuildingInfos,
CIV4ArtDefines_Building,
CIV4CivilizationInfos.xml,
CIV4LeaderHeadInfos.xml
If you don't need all of those, simply remove/ignore those you don't. CIV4UnitInfos and CIV4ArtDefines_Unit should be done together though, since data (the button) will be transferred from one file to the other
Sorry about the lack of commenting and some patchy bits, but I didn't write it for publishing.
In order to use it, you need to know how to run a python script, which is explained in the Python Tutorial. I used Linux since I find it more convenient, but it should also be possible in Windows (don't ask me for help though). Simply define all the source and target files (lines 44-61) and run the script.
Regarding some of the issues I had to resolve manually:
1. Unsurprisingly, all new attributes start with a default value (defined in the script), which might be wrong for the unit/building. I'm especially thinking of <LSystem>LSYSTEM_3x2</LSystem> here.
2. The script assumes that each attribute starts on a new line. If this is not the case, data might be erased or put in the wrong order. I had around 3 of those, but for 40'000 lines of XML code that's not too bad.
3. bSuicide, bHiddenNationality and bAlwaysHostile are inserted after bMechanized.
bRenderBelowWater, which is only needed for ships, is thus pushed back and needs to be moved back to its original place manually.
4. If a unit in UnitInfos has no corresponding tag in CIV4ArtDefines_Unit, or, which is more likely, there is some art in CIV4ArtDefines_Unit without corresponding unit, the script will run fine, but you'll have to remove these entries manually afterwards, since they will cause an error.
5. There will most certainly be problems when trying to convert a mod with non-vanilla schemata. Perhaps the script could be adjusted accordingly. In my case, I had a handful of custom attributes and other data that got me an error message on startup and were accordingly removed by hand.
Furthermore, I suggest to use the new modular XML loading, since I didn't get the whole thing to run otherwise (too many cross-references that point nowhere). One would probably have to change a whole bunch of other files, such as CIV4EventInfos, CIV4DiplomacyInfos, CIV4PromotionInfos, CIV4ProjectInfos etc. to fix all those non-working cross-references. If you do this, you will probably have a lot of double entries (occurring both in the standard files and in your mod), which you could remove.
I don't think there are too many people who will need this, but it really speeds up conversion and could theoretically save someone hours of monotonous work.
CIV4UnitInfos,
CIV4ArtDefines_Unit,
CIV4UnitClassInfos,
CIV4TechInfos,
CIV4BuildingClassInfos,
CIV4BuildingInfos,
CIV4ArtDefines_Building,
CIV4CivilizationInfos.xml,
CIV4LeaderHeadInfos.xml
If you don't need all of those, simply remove/ignore those you don't. CIV4UnitInfos and CIV4ArtDefines_Unit should be done together though, since data (the button) will be transferred from one file to the other
Code:
#! /usr/bin/env python
ArtVar = []
ButtonData = ""
class ConvertUnits():
def InsertData(self,line,input):
space, text = line.split("<",1)
newline = (line+space+input+"\n")
return newline
def ReplaceData(self,line,input):
global ButtonData
space, text = line.split("<",1)
before, after = line.split(">",1)
before, after = after.split("<",1)
ButtonData = before
newline = (space+input+"\n")
return newline
def SaveData(self,line):
global ArtVar
before, after = line.split(">",1)
before, after = after.split("<",1)
ArtVar.append(before)
# print ArtVar
return
def CopyButton(self):
global ArtVar
global ButtonData
for line in linelistb[:]:
for art in ArtVar:
if line.find(">"+art+"<") != -1 and line.find("<Button>") == -1:
space, text = line.split("<",1)
newline = (line+space+"<Button>"+ButtonData+"</Button>"+"\n")
linelistb[linelistb.index(line)] = newline
ArtVar.remove(art)
elif line.find(">"+art+"<") != -1 and line.find("<Button>") != -1:
ArtVar.remove(art)
source=open('/home/teg/temp/CIV4UnitInfos.xml', 'r')
target=open('/home/teg/temp/CIV4UnitInfos2.xml', 'w')
sourceb=open('/home/teg/temp/CIV4ArtDefines_Unit.xml', 'r')
targetb=open('/home/teg/temp/CIV4ArtDefines_Unit2.xml', 'w')
sourcec=open('/home/teg/temp/CIV4UnitClassInfos.xml', 'r')
targetc=open('/home/teg/temp/CIV4UnitClassInfos2.xml', 'w')
sourced=open('/home/teg/temp/CIV4TechInfos.xml', 'r')
targetd=open('/home/teg/temp/CIV4TechInfos2.xml', 'w')
sourcee=open('/home/teg/temp/CIV4BuildingClassInfos.xml', 'r')
targete=open('/home/teg/temp/CIV4BuildingClassInfos2.xml', 'w')
sourcef=open('/home/teg/temp/CIV4BuildingInfos.xml', 'r')
targetf=open('/home/teg/temp/CIV4BuildingInfos2.xml', 'w')
sourceg=open('/home/teg/temp/CIV4ArtDefines_Building.xml', 'r')
targetg=open('/home/teg/temp/CIV4ArtDefines_Building2.xml', 'w')
sourceh=open('/home/teg/temp/CIV4CivilizationInfos.xml', 'r')
targeth=open('/home/teg/temp/CIV4CivilizationInfos2.xml', 'w')
sourcei=open('/home/teg/temp/CIV4LeaderHeadInfos.xml', 'r')
targeti=open('/home/teg/temp/CIV4LeaderHeadInfos2.xml', 'w')
linelist = source.readlines()
linelistb = sourceb.readlines()
linelistc = sourcec.readlines()
linelistd = sourced.readlines()
lineliste = sourcee.readlines()
linelistf = sourcef.readlines()
linelistg = sourceg.readlines()
linelisth = sourceh.readlines()
linelisti = sourcei.readlines()
print 1
for line in linelist:
if line.find("<bNoCapture>") != -1:
line = ConvertUnits().InsertData(line,"<bQuickCombat>0</bQuickCombat>")
elif line.find("<bPillage>") != -1:
line = ConvertUnits().InsertData(line,"<bSpy>0</bSpy>")
elif line.find("<bCanMoveImpassable>") != -1:
line = ConvertUnits().InsertData(line,"<bCanMoveAllTerrain>0</bCanMoveAllTerrain>")
elif line.find("<bMechanized>") != -1:
line = ConvertUnits().InsertData(line,"<bSuicide>0</bSuicide>")
line = ConvertUnits().InsertData(line,"<bHiddenNationality>0</bHiddenNationality>")
line = ConvertUnits().InsertData(line,"<bAlwaysHostile>0</bAlwaysHostile>")
elif line.find("</UnitClassUpgrades>") != -1 or line.find("<UnitClassUpgrades/>") != -1:
line = ConvertUnits().InsertData(line,"<UnitClassTargets/>")
line = ConvertUnits().InsertData(line,"<UnitCombatTargets/>")
line = ConvertUnits().InsertData(line,"<UnitClassDefenders/>")
line = ConvertUnits().InsertData(line,"<UnitCombatDefenders/>")
line = ConvertUnits().InsertData(line,"<FlankingStrikes/>")
elif line.find("</ReligionSpreads>") != -1 or line.find("<ReligionSpreads/>") != -1:
line = ConvertUnits().InsertData(line,"<CorporationSpreads/>")
elif line.find("<PrereqReligion>") != -1:
line = ConvertUnits().InsertData(line,"<PrereqCorporation>NONE</PrereqCorporation>")
elif line.find("<iHurryCostModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iAdvancedStartCost>100</iAdvancedStartCost>")
line = ConvertUnits().InsertData(line,"<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>")
elif line.find("<iMoves>") != -1:
line = ConvertUnits().InsertData(line,"<bNoRevealMap>0</bNoRevealMap>")
elif line.find("<iAirRange>") != -1:
line = ConvertUnits().InsertData(line,"<iAirUnitCap>0</iAirUnitCap>")
line = ConvertUnits().InsertData(line,"<iDropRange>0</iDropRange>")
elif line.find("<iGreatWorkCulture>") != -1:
line = ConvertUnits().InsertData(line,"<iEspionagePoints>0</iEspionagePoints>")
elif line.find("</FeatureImpassables>") != -1 or line.find("<FeatureImpassables/>") != -1:
line = ConvertUnits().InsertData(line,"<TerrainPassableTechs/>")
line = ConvertUnits().InsertData(line,"<FeaturePassableTechs/>")
elif line.find("<iCombat>") != -1:
line = ConvertUnits().InsertData(line,"<iCombatLimit>100</iCombatLimit>")
elif line.find("<iAnimalCombat>") != -1:
line = ConvertUnits().InsertData(line,"<iHillsAttack>0</iHillsAttack>")
elif line.find("</FeatureNatives>") != -1 or line.find("<FeatureNatives/>") != -1:
line = ConvertUnits().InsertData(line,"<TerrainAttacks/>")
elif line.find("</TerrainDefenses>") != -1 or line.find("<TerrainDefenses/>") != -1:
line = ConvertUnits().InsertData(line,"<FeatureAttacks/>")
elif line.find("</UnitCombatMods>") != -1 or line.find("<UnitCombatMods/>") != -1:
line = ConvertUnits().InsertData(line,"<UnitCombatCollateralImmunes/>")
elif line.find("<fMaxSpeed>") != -1:
line = ConvertUnits().InsertData(line,"<fPadTime>1</fPadTime>")
elif line.find("</FreePromotions>") != -1 or line.find("<FreePromotions/>") != -1:
line = ConvertUnits().InsertData(line,"<LeaderPromotion>NONE</LeaderPromotion>")
line = ConvertUnits().InsertData(line,"<iLeaderExperience>0</iLeaderExperience>")
elif line.find("<EarlyArtDefineTag>") != -1:
ConvertUnits().SaveData(line)
elif line.find("<Button>") != -1:
line = ConvertUnits().ReplaceData(line,"<FormationType>FORMATION_TYPE_DEFAULT</FormationType>")
ConvertUnits().CopyButton()
elif line.find("<bReligionSpread>") != -1:
space, text = line.split("<",1)
before, after = text.split(">",1)
data, after = after.split("<",1)
line = (space+"<iReligionSpread>"+data+"</iReligionSpread>"+"\n")
# print line
target.write(line)
print 2
for line in linelistb:
if line.find("<fInterfaceScale>") != -1:
line = ConvertUnits().InsertData(line,"<bActAsLand>0</bActAsLand>")
line = ConvertUnits().InsertData(line,"<bActAsAir>0</bActAsAir>")
targetb.write(line)
for line in linelistc:
if line.find("<iMaxPlayerInstances>") != -1:
line = ConvertUnits().InsertData(line,"<iInstanceCostModifier>0</iInstanceCostModifier>")
targetc.write(line)
print 3
for line in linelistd:
if line.find("<iCost>") != -1:
line = ConvertUnits().InsertData(line,"<iAdvancedStartCost>100</iAdvancedStartCost>")
line = ConvertUnits().InsertData(line,"<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>")
elif line.find("<FirstFreeUnitClass>") != -1:
line = ConvertUnits().InsertData(line,"<iFeatureProductionModifier>0</iFeatureProductionModifier>")
elif line.find("<bPermanentAllianceTrading>") != -1:
line = ConvertUnits().InsertData(line,"<bVassalTrading>0</bVassalTrading>")
elif line.find("</TerrainTrades>") != -1 or line.find("<TerrainTrades/>") != -1:
line = ConvertUnits().InsertData(line,"<bRiverTrade>0</bRiverTrade>")
targetd.write(line)
print 4
for line in lineliste:
if line.find("<bNoLimit>") != -1:
line = ConvertUnits().InsertData(line,"<bMonument>0</bMonument>")
targete.write(line)
print 5
for line in linelistf:
if line.find("<StateReligion>") != -1:
line = ConvertUnits().InsertData(line,"<bStateReligion>0</bStateReligion>")
elif line.find("<PrereqReligion>") != -1:
line = ConvertUnits().InsertData(line,"<PrereqCorporation>NONE</PrereqCorporation>")
line = ConvertUnits().InsertData(line,"<FoundsCorporation>NONE</FoundsCorporation>")
elif line.find("<GlobalReligionCommerce>") != -1:
line = ConvertUnits().InsertData(line,"<GlobalCorporationCommerce>NONE</GlobalCorporationCommerce>")
elif line.find("</ProductionTraits>") != -1 or line.find("<ProductionTraits/>") != -1:
line = ConvertUnits().InsertData(line,"<HappinessTraits/>")
line = ConvertUnits().InsertData(line,"<NoBonus>NONE</NoBonus>")
elif line.find("<iGreatPeopleRateChange>") != -1:
line = ConvertUnits().InsertData(line,"<iHurryAngerModifier>0</iHurryAngerModifier>")
line = ConvertUnits().InsertData(line,"<bBorderObstacle>0</bBorderObstacle>")
elif line.find("<bDiploVote>") != -1:
space, text = line.split("<",1)
before, after = text.split(">",1)
data, after = after.split("<",1)
if data == 1:
data = "DIPLOVOTE_UN"
else:
data = "NONE"
line = (space+"<DiploVoteType>"+data+"</DiploVoteType>"+"\n")
elif line.find("<bGoldenAge>") != -1:
line = ConvertUnits().InsertData(line,"<bAllowsNukes>0</bAllowsNukes>")
elif line.find("<iHurryCostModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iAdvancedStartCost>100</iAdvancedStartCost>")
line = ConvertUnits().InsertData(line,"<iAdvancedStartCostIncrease>0</iAdvancedStartCostIncrease>")
elif line.find("<iGreatPeopleRateModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iGreatGeneralRateModifier>0</iGreatGeneralRateModifier>")
line = ConvertUnits().InsertData(line,"<iDomesticGreatGeneralRateModifier>0</iDomesticGreatGeneralRateModifier>")
elif line.find("<iAnarchyModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iGoldenAgeModifier>0</iGoldenAgeModifier>")
elif line.find("<iAirModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iAirUnitCapacity>0</iAirUnitCapacity>")
elif line.find("<iGlobalWarWearinessModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iEnemyWarWearinessModifier>0</iEnemyWarWearinessModifier>")
elif line.find("<iTradeRouteModifier>") != -1:
line = ConvertUnits().InsertData(line,"<iForeignTradeRouteModifier>0</iForeignTradeRouteModifier>")
elif line.find("<iDefense>") != -1:
line = ConvertUnits().InsertData(line,"<iBombardDefense>0</iBombardDefense>")
elif line.find("<iAllCityDefense>") != -1:
line = ConvertUnits().InsertData(line,"<iEspionageDefense>0</iEspionageDefense>")
elif line.find("</SeaPlotYieldChanges>") != -1 or line.find("<SeaPlotYieldChanges/>") != -1:
line = ConvertUnits().InsertData(line,"<RiverPlotYieldChanges/>")
elif line.find("</BonusYieldModifiers>") != -1 or line.find("<BonusYieldModifiers/>") != -1:
line = ConvertUnits().InsertData(line,"<ImprovementFreeSpecialists/>")
targetf.write(line)
print 6
for line in linelistg:
if line.find("<Type>") != -1:
line = ConvertUnits().InsertData(line,"<LSystem>LSYSTEM_3x2</LSystem>")
targetg.write(line)
print 7
for line in linelisth:
if line.find("<ArtStyleType>") != -1:
line = ConvertUnits().InsertData(line,"<UnitArtStyleType>UNIT_ARTSTYLE_EUROPEAN</UnitArtStyleType>")
starterase = 0
elif line.find("<AnarchyCivics>") != -1 or line.find("</AnarchyCivics>") != -1 or line.find("<AnarchyCivics/>") != -1:
starterase = 1
line = ""
elif line.find("<CivicType>") != -1 and starterase == 1:
line = ""
elif line.find("</Leaders>") != -1 or line.find("<Leaders/>") != -1:
line = ConvertUnits().InsertData(line,"<DerivativeCiv>NONE</DerivativeCiv>")
targeth.write(line)
print 8
for line in linelisti:
if line.find("<iWarmongerRespect>") != -1:
line = ConvertUnits().InsertData(line,"<iEspionageWeight>0</iEspionageWeight>")
elif line.find("<PermanentAllianceRefuseAttitudeThreshold>") != -1:
line = ConvertUnits().InsertData(line,"<VassalRefuseAttitudeThreshold>NONE</VassalRefuseAttitudeThreshold>")
line = ConvertUnits().InsertData(line,"<iVassalPowerModifier>0</iVassalPowerModifier>")
line = ConvertUnits().InsertData(line,"<iFreedomAppreciation>0</iFreedomAppreciation>")
elif line.find("<FavoriteCivic>") != -1:
line = ConvertUnits().InsertData(line,"<FavoriteReligion>NONE</FavoriteReligion>")
targeti.write(line)
Sorry about the lack of commenting and some patchy bits, but I didn't write it for publishing.
In order to use it, you need to know how to run a python script, which is explained in the Python Tutorial. I used Linux since I find it more convenient, but it should also be possible in Windows (don't ask me for help though). Simply define all the source and target files (lines 44-61) and run the script.
Regarding some of the issues I had to resolve manually:
1. Unsurprisingly, all new attributes start with a default value (defined in the script), which might be wrong for the unit/building. I'm especially thinking of <LSystem>LSYSTEM_3x2</LSystem> here.
2. The script assumes that each attribute starts on a new line. If this is not the case, data might be erased or put in the wrong order. I had around 3 of those, but for 40'000 lines of XML code that's not too bad.
3. bSuicide, bHiddenNationality and bAlwaysHostile are inserted after bMechanized.
bRenderBelowWater, which is only needed for ships, is thus pushed back and needs to be moved back to its original place manually.
4. If a unit in UnitInfos has no corresponding tag in CIV4ArtDefines_Unit, or, which is more likely, there is some art in CIV4ArtDefines_Unit without corresponding unit, the script will run fine, but you'll have to remove these entries manually afterwards, since they will cause an error.
5. There will most certainly be problems when trying to convert a mod with non-vanilla schemata. Perhaps the script could be adjusted accordingly. In my case, I had a handful of custom attributes and other data that got me an error message on startup and were accordingly removed by hand.
Furthermore, I suggest to use the new modular XML loading, since I didn't get the whole thing to run otherwise (too many cross-references that point nowhere). One would probably have to change a whole bunch of other files, such as CIV4EventInfos, CIV4DiplomacyInfos, CIV4PromotionInfos, CIV4ProjectInfos etc. to fix all those non-working cross-references. If you do this, you will probably have a lot of double entries (occurring both in the standard files and in your mod), which you could remove.
I don't think there are too many people who will need this, but it really speeds up conversion and could theoretically save someone hours of monotonous work.