Quick Modding Questions Thread

@AntSou Effects are the elemental building blocks here. Directly handled by the DLL, so you cannot see “how they are implemented”, only observe the results ingame. You can’t add new ones, only use existing ones.
 
I've attempted to implement a modifier which gives +1 Gold to trade routes for each Desert tile traversed. I replaced Mali's ability for simplicity sake while testing. Yet all it accomplished was +1 Gold for each tile between two cities. Here's the code:

-- Adding Modifiers
INSERT OR REPLACE INTO Modifiers
(ModifierId, ModifierType)
VALUES ('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'MODIFIER_PLAYER_ADJUST_TRADE_ROUTE_YIELD_PER_PATH_TILE');

INSERT OR REPLACE INTO ModifierArguments
(ModifierId, Name, Value)
VALUES ('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'Amount', '1'),
('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'TerrainType', 'TERRAIN_DESERT'),
('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'YieldType', 'YIELD_GOLD');

-- Altering Mali's Trade Route trait
DELETE FROM TraitModifiers
WHERE ModifierId = 'TRADE_ROUTE_GOLD_DESERT_ORIGIN';

INSERT INTO TraitModifiers
(TraitType, ModifierId)
VALUES ('TRAIT_LEADER_SAHEL_MERCHANTS', 'TRADE_ROUTE_GOLD_DESERT_ANT_OPEN');

I was hoping "TRADE_ROUTE_YIELD_PER_PATH_TILE" could be constrained to apply only to "TERRAIN_DESERT" type but alas no luck. I feel like this should be straightforward but I can't figure out what I'm doing wrong.
 
EffectTypes and CollectionTypes are attached to ModifierTypes in table DynamicModifiers. But the implementation of the individual EffectTypes and CollectionTypes is not exposed to modding. The effects of the EffectTypes are coded directly in the DLL. The valid CollectionTypes, RequirementTypes, RequirementSetTypes are all defined in the game DLL as well, but they are also listed in table GameEffects once the database has been created by starting up a game. The contents of table GameEffects are created as part of the game load-up process from a source we assume is directly within the game's DLL but also might come from another hidden file. Once we have a "built" version of the game database, however we can use a SQL database viewer program to inspect the contents of tables GameEffects and GameEffectArguments to find some interesting stuff. There are quite a few EffectTypes, CollectionTypes, etc., that Firaixs either no longer uses or never used for anything in-game -- most of the time luck seems to be with us and they are fully implemented within the game DLL even though not as yet used.

Unfortunately for Trade Routes there isn't a whole lot exposed to the Modifiers system --- the great majority of how Trade Routes work is either hardcoded in the game DLL or is tied to Districts.

------------------------------------

Also, what @Infixo said

------------------------------------

Also, you aren't necessarily doing anything wrong other than attempting to give an argument that EffectType does not implement. All that modifier appears to want is an 'Amount' value to add per tile, and a 'YieldType" value. It does not want nor care about the type of Terrain nor does it appear you will be able to specify such. The effect is counting total tiles, period.

@AntSou : All that having been said you might see whether a OwnerRequirementSetId or SubjectRequirementSetId added to the Modifier in table Modifiers will be properly implemented if you make the RequirmentSetID have a DesertTerrain "required terrain matching" RequirementID. The TerrainType of TERRAIN_DESERT in table RequirementArguments for a RequirementId whose RequirementType is REQUIREMENT_PLOT_TERRAIN_TYPE_MATCHES might work.
 
Last edited:
Tried the following code, but no luck. The result is that the Gold gain doesn't apply at all:

-- New RequirementID
INSERT OR REPLACE INTO RequirementSets
(RequirementSetId, RequirementSetType)
VALUES ('TRADE_PLOT_HAS_DESERT', 'REQUIREMENTSET_TEST_ALL');

INSERT OR REPLACE INTO RequirementSetRequirements
(RequirementSetId, RequirementId)
VALUES ('TRADE_PLOT_HAS_DESERT', 'REQUIRES_PLOT_HAS_DESERT');

-- Adding Modifiers
INSERT OR REPLACE INTO Modifiers
(ModifierId, ModifierType, SubjectRequirementSetId)
VALUES ('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'MODIFIER_PLAYER_ADJUST_TRADE_ROUTE_YIELD_PER_PATH_TILE', 'TRADE_PLOT_HAS_DESERT');

INSERT OR REPLACE INTO ModifierArguments
(ModifierId, Name, Value)
VALUES ('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'Amount', '1'),
('TRADE_ROUTE_GOLD_DESERT_ANT_OPEN', 'YieldType', 'YIELD_GOLD');

-- Altering Mali's Trade Route trait
DELETE FROM TraitModifiers
WHERE ModifierId = 'TRADE_ROUTE_GOLD_DESERT_ORIGIN';

INSERT INTO TraitModifiers
(TraitType, ModifierId)
VALUES ('TRAIT_LEADER_SAHEL_MERCHANTS', 'TRADE_ROUTE_GOLD_DESERT_ANT_OPEN');

I'll keep trying to see if I can come up with something.

Edit: I'll try class? Edit2: Didn't work.
 
Last edited:
I added Pachacuti's modifier to Mansa Musi and switched "Origin" to "Destination", but this had no effect:



I was able to add it as Origin with the expected result. I get +1 Gold from domestic trade routes for each flat desert tile.

Question: Is there a way to get the bonus at the destination? I don't think there is.
---

SO

Original Goal:
- Add +1 Gold to Trade Route for each Desert Tile it passes through (all civs).


Roundabout:
1. Create a Modifier which uses both Pachacuti's and Mansa Musi's ModifierType. Apply it to Desert and Desert Hills. Class_Desert might work. It should give "+1 Gold to Trade Routes for each Desert Tile in the Origin City".
2. Apply the modifier directly to Trade Routes. If that's not possible, add the modifier as an hidden trait to every Civ.

I feel like there should be an easier way to achieve this result.
 
Last edited:
DynamicModifiers
Code:
ModifierType								CollectionType			EffectType
MODIFIER_PLAYER_ADJUST_TRADE_ROUTE_YIELD_PER_TERRAIN_INTERNATIONAL	COLLECTION_OWNER		EFFECT_ADJUST_PLAYER_TRADE_ROUTE_YIELD_PER_TERRAIN_FOR_INTERNATIONAL
So it looks for the terrains at the cities rather than plots or terrains along the trade route.

Modifiers
Code:
ModifierId				ModifierType
TRADE_ROUTE_GOLD_DESERT_ORIGIN		MODIFIER_PLAYER_ADJUST_TRADE_ROUTE_YIELD_PER_TERRAIN_INTERNATIONAL
The Modifier does not use Subject or Owner Requirements.

ModifierArguments
Code:
ModifierId			Name		Type			Value
TRADE_ROUTE_GOLD_DESERT_ORIGIN	Amount		ARGTYPE_IDENTITY	1
TRADE_ROUTE_GOLD_DESERT_ORIGIN	Origin		ARGTYPE_IDENTITY	1
TRADE_ROUTE_GOLD_DESERT_ORIGIN	TerrainType	ARGTYPE_IDENTITY	TERRAIN_DESERT
TRADE_ROUTE_GOLD_DESERT_ORIGIN	YieldType	ARGTYPE_IDENTITY	YIELD_GOLD

---------------------------------------------------------

These Modifiers all use 'Destination' ModifierArguments but the trouble may be in the ModifierType and EffectType
Code:
ModifierId	Name	Type	Value
TRAIT_TRADE_GOLD_FROM_CAMPS	Destination	ARGTYPE_IDENTITY	1
TRAIT_TRADE_GOLD_FROM_PASTURES	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_CULTURE	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_FAITH	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_FOOD	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_GOLD	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_PRODUCTION	Destination	ARGTYPE_IDENTITY	1
LETTEROFMARQUE_TRADE_ROUTE_YIELD_DROP_DEST_SCIENCE	Destination	ARGTYPE_IDENTITY	1
TRAIT_ORIGIN_DESTINATION_RELIGIOUS_PRESSURE	Destination	ARGTYPE_IDENTITY	1
 
I checked those. I don't think I can make them apply to Terrain. I'll check again, maybe I overlooked something.

I'll work a bit on this but I think I'll have to drop it. The alternative is inelegant and more powerful than I intend.

My best option is probably to give Mansa Musi's ability to all trade routes, then give something different to Mansa.

I'm increasing the harshness of deserts, so I need something to balance it. It's a simple mod and I want to be done with it today so that I can go back to my Resources one.
 
Are there any limitations to what is ethically allowed to be added in a Mod?

The Resourceful Mod adds Poppies, for instance, but I can't find the CIVILOPEDIA English entry, and the German entry makes no mention of what Poppies are for, just how it propagates. So technically just a flower.
 
Ususally ethicality in modding is more about how we treat other modders and how we treat Firaxis DLC.

I personally would not think that adding poppies as a resource would be "unethical" but the maker of such a mod might find the comment section of such a mod on steam to be rather, well, let us say "interesting".

Hemp for example is usually associated in modern times with, er, "weed", but its primary historical uses have been for rope, for textiles, for paper, etc. Although the "weed" version of Hemp is not the same specie as that historically used for making rope, paper, and whatnot, whether or not adding a Hemp resource to the game would be seen as controversial or unethical would probably be a "your mileage will vary" kind of thing.
 
Steam does have some community standards requirements. Such as no "naked" and the like.

But tbh you're more likely to run afoul of steam rules for DMCA type issues than anything else. But even DMCA type issues are hard to conceive of a condition where BigCorp would even bother since they'd have a difficult time making a reasonable argument that the content of a mod can be viewed as being equivalent to a replacement for their movie, game, etc. So it'd be a real grey question as to whether fair use doctrines apply, in which case BigCorp will probably not bother. And Steam is only likely to bother if they receive a notice from BigCorp.

If you were to take the content of one of the game DLC and plop it into a mod, however, then post that mod on Steam you'd probably see that mod get deleted and your steam account might even go *poof* as soon as anyone made Steam, Firaxis, or 2K aware of the mod. Because in such a case it would be not only unethical but also outright illegal as a violation of IP rights.
 
I was hoping something simple like the code below would be enough to achieve the desired result:

Code:
-- Adding "+1 Gold to International Trade Routes for each Desert tile in Origin City" to all Trade Routes.
INSERTO INTO CivicModifiers
    (CivicType, ModifierId)
VALUES ('CIVIC_FOREIGN_TRADE', 'TRADE_ROUTE_GOLD_DESERT_ORIGIN');

That had no effect. Might it work if I attach it to a building or district? I would rather not add it as a hidden trait to all Leaders because that feels clumsy.
 
You don't attach anything directly to individual leader traits to get a modifier to affect all civs / leaders. You attach the modifier to the
Code:
"TRAIT_LEADER_MAJOR_CIV"
Which will cover all major civilizations in one go, including modded ones (assuming the mod maker creates the mod properly).

It is sometimes necessary (depending on the modifier in question) to add a RequirementSet that the player is or is not a human player, or that the player is / is not a specific civilization or leader.

In order to get a modifier attached to all City States you use
Code:
"MINOR_CIV_DEFAULT_TRAIT"
Which will then cover them all in one go.

The modifier needs to be a Player level modifier. A City level modifier will not work. So you may need to use a Player-Level modifier that attaches a second City-Level modifier to all of a player's cities -- it is the second modifier that has the actual effect.

Some Player-Level modifiers affect all of a player's plot yields for example so with that sort of Modifier only the Player-Level one is required.
 
I feel a bit lazy, but haven't had time to do some digging on this one in the files - is there any logic in the game that allows a civilization to build a building (specifically, a wonder - but I guess the mechanisms are the same) only within a conquered city?

In my head, the requirement is along the lines of checking the original city owner is not the current city owner. I have an idea for some custom wonders that would leverage a mechanism like this, if it is possible.
 
@LeeS

Thanks. Started a game as Nubia and that worked. The modifier used for Mansa Musa is already of the second type, so I just had to use the following code:

Code:
INSERT INTO TraitModifiers
    (TraitType, ModifierId)
VALUES ('TRAIT_LEADER_MAJOR_CIV', 'TRADE_ROUTE_GOLD_DESERT_ORIGIN');

I just need to change the modifier to apply to Desert Hills as well.

Out of curiosity, what happens if I leave Mansa Musa's trait as it is? Are the effects for the duplicate "TRADE_ROUTE_GOLD_DESERT_ORIGIN" cumulative, or are they only read once?
 
Depends upon the other data provided in the definition of the Modifier in table Modifiers. All the Booleans are false for that Modifier, and there's no OwnerStackLimit or SubjectStackLimit so it might double-down. But it would also depend on how the EffectType is coded in the DLL. Sometimes what we would think ought to double-down does not seem to, and vice versa.
 
I feel a bit lazy, but haven't had time to do some digging on this one in the files - is there any logic in the game that allows a civilization to build a building (specifically, a wonder - but I guess the mechanisms are the same) only within a conquered city?

In my head, the requirement is along the lines of checking the original city owner is not the current city owner. I have an idea for some custom wonders that would leverage a mechanism like this, if it is possible.
Not that I can think of offhand. There still aren't any ModifierTypes (ie, EffectTypes) that allow or disallow construction of a building so far as I am aware.

It can be done using an unbuildable building as a Prerequisite Building, and then placing such a building via an lua script, but so far as I know it still cannot be done via Database methods.
 
Not that I can think of offhand. There still aren't any ModifierTypes (ie, EffectTypes) that allow or disallow construction of a building so far as I am aware.

It can be done using an unbuildable building as a Prerequisite Building, and then placing such a building via an lua script, but so far as I know it still cannot be done via Database methods.

That's a shame - I think there would be a lot of thematic possibilities to allow things to be built, but only in the context of captured cities/conquered territories.

Conversely - and for this one I am starting to look around - is there a logic that would allow for tying a building to a specific, named city? Or is the limitation, as I suspect, that we choose one of the distinctions of either Capital City or any non-Capital City? In fact, from what I can find we don't even have the ability to tie a building only to the Capital, but there is a boolean within the Buildings table that specifies AdjacentCapital. I would also expect that the game only recognises the Capital in that context as the owner's current capital - rather than any original capital, whether owned by original player or not.

Edit:

Done a little searching. Do we think this could be done, via the dummy-building route, but without LUA?

There is a RequirementSet named CITY_NOT_FOUNDED which essentially dictates that a city is not REQUIREMENT_CITY_IS_ORIGINAL_OWNER. If we had a dummy building and set it as the prerequisite for any building that can only be built in conquered cities and granted that dummy building to every city using the CITY_NOT_FOUNDED RequirementSet, would that work in theory?

There's a ModifierType named MODIFIER_SINGLE_CITY_GRANT_BUILDING_IN_CITY, which presumably could be used to configure that building to be granted whenever CITY_NOT_FOUNDED is true.

The key additional thing in this plan is that the buildings that identify the dummy building as a prerequisite will be limited, by traits, to specific civilizations - and the dummy buildings will have no other use - so I do not see a loophole that causes a need to have said dummy building removed in any scenario down the line.

Thinking about it, now, that dummy building could be some kind of simplistic War Memorial and grant a basic +1 Culture or something and serve as a 'permanent reminder' of that city's past struggles. Or even have no game effect but stand in the City Center as a reminder.
 
Last edited:
I need to open an exception to the Alpine Promotion to exclude Desert Hills. Is there a direct way to add one?



Since Name is a Primary Key, I can't just have four TerrainTypes with a different Value for each Hill terrain. This is what I did instead:

Code:
-- Changing Alpine Promotion to exclude Desert Hills
DELETE FROM UnitPromotions WHERE UnitPromotionType ='PROMOTION_ALPINE';
DELETE FROM ModifierArguments WHERE ModifierId ='ALPINE_IGNORE_HILLS_MOVEMENT_PENALTY';

INSERT OR REPLACE INTO Modifiers
    (ModifierId, ModifierType)
VALUES ('ALPINE_IGNORE_GRASS_HILLS_MOVEMENT_PENALTY', 'MODIFIER_PLAYER_UNIT_ADJUST_IGNORE_TERRAIN_COST'),
       ('ALPINE_IGNORE_PLAINS_HILLS_MOVEMENT_PENALTY', 'MODIFIER_PLAYER_UNIT_ADJUST_IGNORE_TERRAIN_COST'),
       ('ALPINE_IGNORE_TUNDRA_HILLS_MOVEMENT_PENALTY', 'MODIFIER_PLAYER_UNIT_ADJUST_IGNORE_TERRAIN_COST'),
       ('ALPINE_IGNORE_SNOW_HILLS_MOVEMENT_PENALTY', 'MODIFIER_PLAYER_UNIT_ADJUST_IGNORE_TERRAIN_COST');
     
INSERT OR REPLACE INTO ModifierArguments
    (ModifierId, Name, Value)
VALUES ('ALPINE_IGNORE_GRASS_HILLS_MOVEMENT_PENALTY', 'TerrainType', 'TERRAIN_GRASS_HILLS'),
       ('ALPINE_IGNORE_PLAINS_HILLS_MOVEMENT_PENALTY', 'TerrainType', 'TERRAIN_PLAINS_HILLS'),
       ('ALPINE_IGNORE_TUNDRA_HILLS_MOVEMENT_PENALTY', 'TerrainType', 'TERRAIN_TUNDRA_HILLS'),
       ('ALPINE_IGNORE_SNOW_HILLS_MOVEMENT_PENALTY', 'TerrainType', 'TERRAIN_SNOW_HILLS');

INSERT OR REPLACE INTO UnitPromotions 
    (UnitPromotionType, Name, Description, Level, Column, PromotionClass)
VALUES ('PROMOTION_ALPINE', 'LOC_PROMOTION_ALPINE_NAME', 'LOC_PROMOTION_ALPINE_DESCRIPTION', 1, 3, 'PROMOTION_CLASS_RECON');
     
INSERT OR REPLACE INTO UnitPromotionModifiers
    (UnitPromotionType, ModifierId)
VALUES ('PROMOTION_ALPINE', 'ALPINE_IGNORE_GRASS_HILLS_MOVEMENT_PENALTY'),
       ('PROMOTION_ALPINE', 'ALPINE_IGNORE_PLAINS_HILLS_MOVEMENT_PENALTY'),
       ('PROMOTION_ALPINE', 'ALPINE_IGNORE_TUNDRA_HILLS_MOVEMENT_PENALTY'),
       ('PROMOTION_ALPINE', 'ALPINE_IGNORE_SNOW_HILLS_MOVEMENT_PENALTY');

Well, that didn't work. For whatever reason I had to delete PROMOTION_ALPINE and re-insert it because just deleting the original modifier was causing the modifier to reappear as soon as I launched a new game and the remaining code not to load. So in that first attempt, the Scout would move through desert mountains as usual.

The second attempt was the code above, and it just caused Alpine Promotion to have no effect. The code loaded properly, so I'm guessing the 'MODIFIER_PLAYER_UNIT_ADJUST_IGNORE_TERRAIN_COST' ModifierType just doesn't take a TerrainType value?

Is there a workaround?
-------

One odd thing I found is that UnitPromotionType is an integer column that accepts text in UnitPromotionModifiers table:



UnitPromotionType in UnitPromotions table accepts text though. What's going on here?
 
Top Bottom