Modmodding Q&A Thread

I couldn't find Victoria, presumably because she is a vanilla leader and thus doesn't have any files in DoC. I did find, fix and (I hope) pull request the Mohawk entry though. Let me know if it got through to you like it was supposed to.
If you want to fix something about Victoria, just locate her vanilla files and copy the tag into DoC, then fix it. It will overwrite whatever is in vanilla.

Edit: oh and it's already merged.
 
[*]RFC specific world builder features: display and edit tile stability, output stability maps. Hopefully this will allow us to edit stability/settler maps in world builder

I'm currently working on this. But I have some questions.

Is it currently possible to assign tiles to the list of core tiles? IIRC, it isn't. I have the following idea to make it possible, but maybe you have a better/more efficient idea.

My idea is to create 2 lists in the storeddata, each list containing a list for each civ. 1 List contains all the "additional tiles", the other one contains all "exception tiles". The default core consists of the rectangular core defined in consts.py minus the exceptions. These exceptions will be stored in the 2nd list in the storeddata.
If you add a tile tile the core, it will be added to the "additional tiles" list if it is outside of the rectangle. If it is in the rectangle, it will be removed for the "exception tiles" list. If you remove a tile from the core, it will be removed from the "additional tiles" list if it is outside of the rectangle (ass the tile is stored into that list). And if you remove a tile that is in the rectangle, it will be added to the "exception tile" list.
So the list of coreplots will be defined by the rectangle minus the tiles in the "exception tiles list" plus the tiles from the "additional tiles" list.

I hope it's clear what I mean. Do you think that is a good way to do this, or do you have a better idea? The same thing could be done for the flipzone plots.

Also, is there a method to change the settlervalue of a plot for a civ? For this, I have no idea how to do this, but it's required for obvious reasons.
 
It's good that you're working at this already, but I think I need to lay some implementation groundwork first so that this actually works.

In any case, you should not be using StoredData for this, I'd like to keep this map as small as possible because pickle isn't really efficient compared to plain DLL storage.

Personally, I think it is enough if you can edit core tiles or tile stability in the WB and then have it create the new core tiles and stability maps for you to paste into the code. I will move settler/stability maps to Python for that purpose. Fully automating it is probably not worth it because that requires making all that information editable and persistent.

For core areas, there already is a separate CvPlot::isCore(PlayerTypes) method which is initialized from the original core information in Consts.py (because this information is required in the DLL and Python callbacks are inefficient). I want to do the same for settler map values.

Having that editable in WB is alright I guess, but it would always only apply to the current game and what I really want is a way to edit the initial starting values as a way to speed up the modding process.

What you can do already:
- a button that toggles a tile stability overlay for the current player over the entire map (see SoI)
- editing core status of a tile for the current player
- editing settler map value for the current player
- buttons that output the settler map / a list of core tiles

If you have integrated the buttons for triggering those actions most of the work is already done. I will provide the endpoints to actually make this happen later.
 
This is what I already have.

Spoiler :
attachment.php


My idea is that you can select a certain tile (currently the Egyptian spawning plot in the image). You can move that tile with the buttons in the bottom right corner. The table on the left displays the info of that tile for all civs. (can be done without groundwork)

If you click on the civ in the civilization column, you will view the stabilitymap of that player in particular, similar to my current stability map viewer. You can still move the selected tile and edit all parameters. (requires groundwork first)

If you click on the green wink of red cross in the core column, you can add/remove the selected tile to/from the core for a particular civ.

If you click on the integer in the settlervalue column, you can increase/decrease the settlervalue of the selected tile for a particular civ. You can also define a set value and set the settlervalue to that value for faster editing. (requires groundwork first)

The result column only shows the effect of that tile for a particular civ. (no groundwork required)

The extended map column switches the vanilla map with the extended map with the setReborn function. As can be seen, it only applies to certain civs. (no groundwork required, already implemented)

The spawn map (which is on a different page) works similar to the core column.

Even if the groundwork for what I have in my won't be done, I think this will still be a nice viewer of the total map. It might be possible to temporarily store the edited maps when you are editing them with this tool, and hit an export button which creates a file which only has to be copy-pasted in the code like you suggested.
 
This looks great and is already very detailed.

But isn't that a little bit redundant because we already have the main map view in the world builder to edit specific tiles?

That is, for editing a plot settler value, I would select the settler map editing mode and then click on the tile I want to edit (similar to how editing cities works). If only stability is relevant, there probably should also be something like a paint tool where the world map gets a stability overlay and you can "paint" tiles in the stability type you want.
 
Where did you remove the happiness you get from the culture slider even without buildings? I want to reverse this change.
 
Where did you remove the happiness you get from the culture slider even without buildings? I want to reverse this change.
Commerce infos or CommerceFlexibles or something? Where the commerce types themselves are defined.
 
Yes; you define the amount of happiness and all in GameInfo/CIV4CommerceInfo.xml.
 
Am I correct to assume that if all I wanted to change for a given UHV is the deadline (e.g. 1730 for England's first UHV) I can do so in Victory.py? I still would have to update some other file for it to be displayed that way in the victory and civ selection screens and the Civilopedia, right?
 
That's correct. The text in the civilopedia is just a plain text file. (GameText_VictorySOMETHING.xml) It depends on the civ you want the change the victory date of which file you exactly need, but it isn't hard to find.
 
I made both Caravels and Galleons require Gunpowder in my modmod in order to give the poor Native Americans some breathing space, and yet I suddenly see Isabella flaunt her Galleons in her war against the Moors even though she doesn't have Gunpowder. I assume Spain or indeed most western Europeans get some Galleons for free upon researching Astronomy, correct?
 
Okay I have managed to make all buildinginfos tags optional (see below) and have made it work in game.
Code:
		<BuildingInfo>
			<BuildingClass>BUILDINGCLASS_WALLS</BuildingClass>
			<Type>BUILDING_WALLS</Type>
			<Description>TXT_KEY_BUILDING_WALLS</Description>
			<Civilopedia>TXT_KEY_BUILDING_WALLS_PEDIA</Civilopedia>
			<Strategy>TXT_KEY_BUILDING_WALLS_STRATEGY</Strategy>
			<Advisor>ADVISOR_MILITARY</Advisor>
			<ArtDefineTag>ART_DEF_BUILDING_WALLS</ArtDefineTag>
			<ObsoleteTech>TECH_RIFLING</ObsoleteTech>
			<PrereqTech>TECH_MASONRY</PrereqTech>
			<bNeverCapture>1</bNeverCapture>
			<bCenterInCity>1</bCenterInCity>
			<iCost>50</iCost>
			<iDefense>50</iDefense>
			<iBombardDefense>50</iBombardDefense>
			<iAsset>1</iAsset>
			<iPower>2</iPower>
			<ConstructSound>AS2D_BUILD_WALLS</ConstructSound>
			<BonusProductionModifiers>
				<BonusProductionModifier>
					<BonusType>BONUS_STONE</BonusType>
					<iProductonModifier>100</iProductonModifier>
				</BonusProductionModifier>
			</BonusProductionModifiers>
			<Flavors>
				<Flavor>
					<FlavorType>FLAVOR_MILITARY</FlavorType>
					<iFlavor>10</iFlavor>
				</Flavor>
			</Flavors>
		</BuildingInfo>

However when I try to set the default tag state in CvInfos for when the tag is missing (see below). Even though MaxLatitude works correctly even when missing, ProductionCost does not and is treated as if the building had a production cost of 1. Why would this be?
Code:
m_iProductionCost(-1),
m_iHurryCostModifier(0),
m_iHurryAngerModifier(0),
m_iAdvancedStartCost(-1),
m_iAdvancedStartCostIncrease(0),
m_iMinAreaSize(-1),
m_iNumCitiesPrereq(0),
m_iNumColoniesPrereq(0),
m_iNumTeamsPrereq(0),
m_iUnitLevelPrereq(0),
m_iMinLatitude(0),
m_iMaxLatitude(90),
.........
m_fVisibilityPriority(1.0f),


m_iMaxLatitude(90), is unchanged code so this code might have nothing to do with optional tags.

I also have no idea if iAdvancedStartCost, iMinAreaSize or fVisibilityPriority work but I don't believe it matters if they don't since advanced starts don't appear ingame, minareasize doesn't have an effect on non-water buildings (and water buildings have a defined minareasize) and building art still appears correctly in game.
 
Where do you see the cost as 1? I think it is a general game rule that building costs must be positive, which is enforced in one of the getter methods in the DLL.

Iirc the meaning of -1 means that the building cannot be constructed, does that still work?
 
Where do you see the cost as 1? I think it is a general game rule that building costs must be positive, which is enforced in one of the getter methods in the DLL.

Iirc the meaning of -1 means that the building cannot be constructed, does that still work?

When I try to construct a building ingame that doesn't have the building cost tag. i.e. I want the game to treat it as unconstructable (-1). It shows up in the building queue and has a cost of 1 hammer. I just have no idea why it would do that.
 
Okay, I will look into the code if I have time tomorrow.
 
Hey Leoreth. This may be an elementary question, but I am hoping to discover what I may be missing.

To start out prep for the 1900 AD scenario I intend to do, I started by creating duplicate functions within the Python scripts that relate to 1700AD, and renamed the copied ones to 1900AD. Among some other changes, I also added an extra line within RFCUtils.py:

if gc.getPlayer(con.iMughals).isPlayable(): return con.i1700AD

Now, when I play any scenario, the game loads all the way until the start of the game but then the interface never loads and units are never created. I presume this may indicate a Python error had occurred, but I describe it just in case you have seen it before and would suggest it is caused by something else (I made no DLL changes).

So the ultimate question: how do I turn on Python logs so I can look into the errors?
 
You can configure that in RFC Dawn of Civilization.ini, set logging to true and hide Python exceptions to false. But your approach is exactly how it works.
 
Where in the code is a civilization's current era coded? For some reason, when I run my code, which includes updated starting technologies, I get both a notification for entering the Renaissance Era and for entering the Industrial Era, rather than just the Industrial Era. Is this stored outside Python?

The main problem I am experiencing is that I can pick whatever earlier technologies I want for civs, but I get the following errors when I execute when I include con.iAssemblyLine and con.iArtillery within starting techs. What handles the C++ so I can narrow what may be going wrong?

Traceback (most recent call last):
File "BugEventManager", line 400, in _handleDefaultEvent
File "CvRFCEventHandler", line 148, in onGameStart
File "RiseAndFall", line 627, in setup
File "RiseAndFall", line 678, in initScenario
File "RiseAndFall", line 4515, in assign1900ADTechs
RuntimeError: unidentifiable C++ exception

File "RiseAndFall", line 4510-4515, in assign1900ADTechs =
lFrenchTechs = [con.iScientificMethod, con.iBiology, con.iPhysics, con.iNationalism, con.iSteel, con.iSteamPower, con.iRailroad,
con.iElectricity, con.iCombustion, con.iDemocracy,
con.iAssemblyLine, con.iArtillery]
lFrenchTechs.extend(lRenaissanceTechs)
for iTech in lFrenchTechs:
teamFrance.setHasTech(iTech, True, iFrance, False, False)
 
Where in the code is a civilization's current era coded? For some reason, when I run my code, which includes updated starting technologies, I get both a notification for entering the Renaissance Era and for entering the Industrial Era, rather than just the Industrial Era. Is this stored outside Python?
Yes, the DLL sets what era you start in and suppresses the notifications for earlier eras.

The main problem I am experiencing is that I can pick whatever earlier technologies I want for civs, but I get the following errors when I execute when I include con.iAssemblyLine and con.iArtillery within starting techs. What handles the C++ so I can narrow what may be going wrong?
You can follow into the CvTeam::setHasTech method.
 
Yes, the DLL sets what era you start in and suppresses the notifications for earlier eras.


You can follow into the CvTeam::setHasTech method.

It looks like the problem is with iArtillery, because iArtillery is an object used twice in Consts.py, first initialized as a unit and then as a tech. I presume the reason it is failing is that it is loading the unit variable by mistake, and attempting to run the getEra method within setHasTech and is not finding the Era variable defined for iArtillery (the unit).

Do you know how I could access a specific version of con.iArtillery, so I make sure I am picking the tech info rather than the unit info? I am not very knowledgeable with how Python communicates with the XML. So if I were to, say, rename iArtillery to iArtilleryTech on RiseAndFall.py and Consts.py, would I need to change TECH_ARTILLERY to TECH_ARTILLERY_TECH on Civ4TechInfos.xml? Or is there another better workaround than renaming?
 
Back
Top Bottom