1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Quick Modding Questions Thread

Discussion in 'Mod Creation Help' started by Leyrann, Oct 28, 2018.

  1. robal1991

    robal1991 Chieftain

    Joined:
    May 2, 2011
    Messages:
    95
    Location:
    Poland
    Just a quick question. I want to know the "workflow" for data in Civ6. So basically all data is in the xml files. Then, there are sql files with commands to create database with is generated when the game starts and is put in the sqlite database file? Is that correct?
    I am trying to do some experiments with game data and I just want to know if I can restrict myself to only using data from DebugGameplay.sqlite. I don't want any mods, but I want Expansions and DLCs data.

    Thanks for help!
     
  2. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    New modder myself, but I believe this is how it works:

    So, the game's database is built from the XML files. The SQL files are often a good shorthand to basically edit the table entries as if you were writing additional entries into the XML file. Example:

    Code:
    INSERT INTO    Types
              (Type,                                              Kind            )
    VALUES    ('TRAIT_LEADER_ZAG_SUMETAL_UA',                  'KIND_TRAIT'    ),
              ('ABILITY_ZAG_SUMETAL_UA_GPM_POINTS',            'KIND_ABILITY'    );
    
    Is effectively the same as
    Code:
    <Types>
         <row Type="TRAIT_LEADER_ZAG_SUMETAL_UA" Kind ="KIND_TRAIT" />
         <row Type="ABILITY_ZAG_SUMETAL_UA_GPM_POINTS" Kind ="KIND_ABILITY" />
    </type>
    
    But frankly I find the SQL version more readable. The SQL file has additional advantages in that you can use OR to specify to either INSERT or REPLACE an entry if that entry already exists. If there are two XML files with the same entry, then I believe the database compiling process has to determine which one is used through some other prioritization process.

    There may be some advantages to using xml directly, but it seems most modders have switched to using SQL.
     
  3. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    My reply up above reminds me. I have a question about some SQL in the template I'm using.

    Code:
    INSERT OR REPLACE INTO LocalizedText (Language, Tag, Text)
    VALUES
    
    The one's I've bolded are the ones that show as blue in ModBuddy. This suggests to me that the formatting is off. Since it's all unique tags for my text, I don't see any reason I shouldn't just use

    Code:
    INSERT INTO LocalizedText (Language, Tag, Text)
    VALUES
    
    Or maybe

    Code:
    INSERT INTO   BaseGameText
                            (Language, Tag, Text)
    VALUES
    
    But in both cases 'Text' is still showing up blue. I'm guessing it's tripping a SQL command? If so, then what I really want is this:

    Code:
    INSERT INTO   BaseGameText
                            (Language, Tag, "Text")
    VALUES
    
    and this would explain why I couldn't figure out where I was getting an error from (20 entries for 21 columns).

    OK, I'm mostly thinking out loud here, but I think I have it, unless some sees something I've missed?
     
  4. Laurana Kanan

    Laurana Kanan Don’t underestimate who I am.

    Joined:
    Apr 10, 2014
    Messages:
    2,511
    Gender:
    Female
    Location:
    Near the Greatest Snow on Earth
    You want to use LocalizedText instead of BaseGameText. I've also used both "INSERT INTO" and "INSERT OR REPLACE INTO", depending on the circumstance, but mostly the latter.
     
  5. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    So if REPLACE is a valid command, why is it not blue in ModBuddy? I've changed it to your recommendations, I just want to know what is going on here. :)
     
  6. Laurana Kanan

    Laurana Kanan Don’t underestimate who I am.

    Joined:
    Apr 10, 2014
    Messages:
    2,511
    Gender:
    Female
    Location:
    Near the Greatest Snow on Earth
    Don't know. I don't use ModBuddy that much and certainly not for viewing code.
     
  7. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,872
    Location:
    Illinois, USA
    INSERT OR REPLACE INTO
    • Checks to see if there is already a matching row for the table's Primary Keys. If so, the existing row in the table is literally replaced with the new data.
    • If there is no matching row already within the table, a new row is added to the table
    • Unique Constraint errors are thereby bypassed
    INSERT INTO
    • Does not check anything and simply attempts to add the new row
    • If there is already within the table a row that matches for the table's Primary Keys, a Unique Constraint error results, and the code-chunk as well as anything else following within the same file are rejected by the game.
    You do not need to use "Text" : you can safely use Text as in this example
    Code:
    INSERT INTO LocalizedText (Language, Tag, Text)
    VALUES
    Modbuddy's SQL error-checking is confused by the fact that a column definition when a table is created can be defined as needing a text-string as opposed to an integer or a Boolean value, such as
    Code:
    "Description" TEXT NOT NULL,
    As @Laurana Kanan mentions, Modbuddy's code-checking lacks quite a bit in terms of reliability. You are actually better off opening the SQL or XML file using Notepad++ and examining what it shows you since Notepad++ auto-recognizes for format correctness when you open any SQL, XML, or lua file. Notepad++ cannot however know whether the tables and columns are valid because it cannot open and read the game's database, nor can Notepad++ understand whether lua commands are valid for Civ6 but it can check for basic syntax errors like missing "end" commands.

    Modbuddy does not actually open or access the game's database either.

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

    The Primary Keys for table LocalizedText are "Tag" and "Language"
    This means every new row added to the table must have a unique combination of data for these two columns.

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

    Long story short is there is no true substitute for executing the code via the game.
     
    Laurana Kanan likes this.
  8. pauljinyong

    pauljinyong Chieftain

    Joined:
    Jul 12, 2019
    Messages:
    7
    Gender:
    Male
    I was trying to enable Multiple Specialty districts (same type) in cities. The codes were simple:
    Code:
    <Update>
    <Where DistrictType="DISTRICT_CAMPUS"/> <Set OnePerCity="false"/>
    </Update>
    <Update>
    <Where DistrictType="DISTRICT_COMMERCIAL_HUB"/> <Set OnePerCity="false"/>
    </Update>
    <Update>
    <Where DistrictType="DISTRICT_INDUSTRIAL_ZONE"/> <Set OnePerCity="false"/>
    </Update>
    <Update>
    <Where DistrictType="DISTRICT_THEATER"/> <Set OnePerCity="false"/>
    </Update>
    <Update>
    <Where DistrictType="DISTRICT_HOLY_SITE"/> <Set OnePerCity="false"/>
    </Update>
    But I got following problems after I did so:
    1. No yields indication when you are choosing which tile to place the district.
    2. No citizen slots in other districts with the same type, except the first one, which has buildings in it.

    Can anyone help me out? I don't expect citizen slots but I do need the yield indication to make this new feature more friendly.
     
  9. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,872
    Location:
    Illinois, USA
    #1) My guess would be the issue is in the game's lua file that executes the Pop-up that occurs for District Placements, or else it is an issue with the way the gamecore software works -- one or the other is not coded to 'understand' additional copies of districts with Adjacency Yields. I have not investigated the code in the lua User Interface file that controls the District Placement Pop-up, so this is merely educated guessing on my part.

    #2) A city can ever only have one copy of a building, so additional copies of the same District within the same city aren't going to allow additional copies of Buildings.
     
  10. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    9,274
    Location:
    France
    Is there a way to disable the jersey system ?
     
  11. pauljinyong

    pauljinyong Chieftain

    Joined:
    Jul 12, 2019
    Messages:
    7
    Gender:
    Male
    Can you tell me which lua file affect this interface? I don't understand lua code.
     
  12. Laurana Kanan

    Laurana Kanan Don’t underestimate who I am.

    Joined:
    Apr 10, 2014
    Messages:
    2,511
    Gender:
    Female
    Location:
    Near the Greatest Snow on Earth
    Not that I've seen. You can only "work around" it.
     
  13. Gedemon

    Gedemon Modder Moderator

    Joined:
    Oct 4, 2004
    Messages:
    9,274
    Location:
    France
    Thanks, I'm pondering reporting the transparency issue as a bug, if the game was doing a fallback on the default colors instead, I suppose we could remove all jersey colors to restore the previous behavior.
     
  14. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,872
    Location:
    Illinois, USA
    Tbh I'm not sure where the code is located. This is because all the placement lua files for city production, plot buying, etc., refer to code in other files, which refer to code in other files, which refer to mouse click "callbacks", which refer to other code in other files. It's a rabbit warren of interlocking files.
     
  15. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    To make sure I'm understanding this correctly:

    EFFECT_GRANT_YIELD_PER_GREAT_WORK_IN_CITY wants these three arguments:
    Amount
    GreatWorkObjectType
    YieldType

    So if I want to use MODIFIER_PLAYER_CITIES_ADJUST_GREATWORK_YIELDto grant multiple yields, I would need my argument to look something like this:


    Code:
    INSERT INTO    Modifiers
            (ModifierId,                                        ModifierType,                                                OwnerRequirementSetId,                SubjectRequirementSetId,            RunOnce,    Permanent    )
    VALUES
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',              'MODIFIER_PLAYER_CITIES_ADJUST_GREATWORK_YIELD',                        NULL,                                NULL,                                0,            0            );
    
    -----------------------------------------------
    -- ModifierArguments
    -----------------------------------------------
    
    INSERT INTO    ModifierArguments
            (ModifierId,                                        Name,                        Value                        )
    VALUES
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'Amount',                    2                            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'YieldType',                'YIELD_PRODUCTION'            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'Amount',                    2                            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'YieldType',                'YIELD_FAITH'                );
    
    
    Or, do I need to create a separate ModifierId for each yield type?
     
    Last edited: Apr 3, 2020
  16. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,872
    Location:
    Illinois, USA
    Table ModifierArguments in many cases will accept multiple 'arguments' within the same 'Value' column for "amount" and "yieldtype" settings. So, first, try as
    Code:
    INSERT INTO    ModifierArguments
            (ModifierId,                                        Name,                        Value                        )
    VALUES
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'Amount',                    '2,2'                            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'YieldType',                'YIELD_PRODUCTION,YIELD_FAITH'            );
    The arguments for the Value column must be presented as I have shown, as one long text-string with commas separating the different Yields and the different Amount values. You may also need to do the same thing for the GreatWorkObjectType, ie
    Code:
    ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',   'GreatWorkObjectType',  'GREATWORKOBJECT_MUSIC,GREATWORKOBJECT_MUSIC'        ),
    If the game does not implement this method for stating the ModifierArguments, then you will need two different Modifiers since repeating a combination of ModifierId and Name is not allowed.

    RequirementArguments as I recall will also accept this multi-value method for certain kinds of arguments but most other game-tables will not: they as a general rule only want one "value" for an argument and don't implement stringing of multiple values into one argument.
     
  17. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    I tried the compressed way LeeS described, and it didn't work. I also then did it with 3 modifier IDs, and it still didn't work. So I'll work my way through my thoughts/process as I put up sections of code.

    So, first I need to create 3 new ModifierIds and attach them to the same trait I already have working. Setting up just like Kongo is set up for their Nkisi trait. (I actually tried to use a second leader trait at one point, as other leaders have multiple leader traits, but it crashed on game creation until I switched to only having 1 leader trait.)

    Code:
    INSERT INTO    TraitModifiers  
            (TraitType,                                    ModifierId                                        )
    VALUES  
            ('TRAIT_LEADER_ZAG_SUMETAL_UA',                'MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS'    ),
            ('TRAIT_LEADER_ZAG_SUMETAL_UA',                'MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD'    ),
            ('TRAIT_LEADER_ZAG_SUMETAL_UA',                'MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH'    ),
            ('TRAIT_LEADER_ZAG_SUMETAL_UA',                'MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD'    );
    
    Great, now that I have 3 new ModifierIds, I need to define their Modifiers. RunOnce and Permanent are set to false/0 because they are not called on in the original Nkisi trait.

    Code:
    INSERT INTO    Modifiers
            (ModifierId,                                        ModifierType,                                                OwnerRequirementSetId,            SubjectRequirementSetId,            RunOnce,    Permanent    )
    VALUES  
            ('MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS',                'MODIFIER_PLAYER_UNITS_GRANT_ABILITY',                        NULL,                            NULL,                                0,            1            ),
            ('MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY',        'MODIFIER_PLAYER_UNIT_ADJUST_GREAT_PEOPLE_POINTS_PER_KILL',    NULL,                            NULL,                                0,            1            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD',                'MODIFIER_PLAYER_CITIES_ADJUST_GREATWORK_YIELD',            NULL,                            NULL,                                0,            0            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH',                'MODIFIER_PLAYER_CITIES_ADJUST_GREATWORK_YIELD',            NULL,                            NULL,                                0,            0            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD',                'MODIFIER_PLAYER_CITIES_ADJUST_GREATWORK_YIELD',            NULL,                            NULL,                                0,            0            );
    
    And now for the many entry version of the arguments. Once more, I'm copying the way the Kongo's Nkisi trait did it (though modified for sql instead of xml).

    Code:
    INSERT INTO    ModifierArguments
            (ModifierId,                                        Name,                        Value                                )
    VALUES  
            ('MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS',                'AbilityType',                'ABILITY_ZAG_SUMETAL_UA_GPM_POINTS'    ),
            ('MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY',        'GreatPersonClassType',        'GREAT_PERSON_CLASS_MUSICIAN'        ),
            ('MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY',        'Amount',                    10                                    ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'                ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD',                'YieldChange',                'YIELD_PRODUCTION'                    ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD',                'Amount',                    2                                    ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'                ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH',                'YieldChange',                'YIELD_FAITH'                        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH',                'Amount',                    2                                    ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'                ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD',                'YieldChange',                'YIELD_FOOD'                        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD',                'Amount',                    2                                    );
    
    And what do I get? well, the game still launches and I can select the civ, and create the game. I still get Great Musician Points on a kill. I get a musician and create a new work of music? no changes. Still +4 culture, +4 tourism.

    Now, in both the compressed version LeeS showed above and in the version I just posted, looking at the database shows my three new modifiers showing up in the table entries, along with their arguments. They show up as trait modifiers too. The only difference is that in the compressed version they showed up as

    Code:
    MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY    GreatPersonClassType    ARGTYPE_IDENTITY    GREAT_PERSON_CLASS_MUSICIAN
    MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY    Amount    ARGTYPE_IDENTITY    10
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    GreatWorkObjectType    ARGTYPE_IDENTITY    GREATWORKOBJECT_MUSIC,GREATWORKOBJECT_MUSIC,GREATWORKOBJECT_MUSIC
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    YieldChange    ARGTYPE_IDENTITY    YIELD_PRODUCTION,YIELD_FAITH,YIELD_FOOD
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    Amount    ARGTYPE_IDENTITY    2,2,2
    
    (Note: recreated from memory, I didn't think to copy/paste it originally, but I noted the structure. So there might be minor discrepancies, like the Amount entry might have had single quotes, i.e. '2,2,2', but I can't remember for sure.)

    While in this version they have more entries, like so:
    Code:
    MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY    GreatPersonClassType    ARGTYPE_IDENTITY    GREAT_PERSON_CLASS_MUSICIAN
    MODIFIER_ZAG_SUMETAL_UA_GPM_POINTS_ABILITY    Amount    ARGTYPE_IDENTITY    10
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    GreatWorkObjectType    ARGTYPE_IDENTITY    GREATWORKOBJECT_MUSIC
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    YieldChange    ARGTYPE_IDENTITY    YIELD_PRODUCTION
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_PROD    Amount    ARGTYPE_IDENTITY    2
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH    GreatWorkObjectType    ARGTYPE_IDENTITY    GREATWORKOBJECT_MUSIC
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH    YieldChange    ARGTYPE_IDENTITY    YIELD_FAITH
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FAITH    Amount    ARGTYPE_IDENTITY    2
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD    GreatWorkObjectType    ARGTYPE_IDENTITY    GREATWORKOBJECT_MUSIC
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD    YieldChange    ARGTYPE_IDENTITY    YIELD_FOOD
    MODIFIER_ZAG_SUMETAL_UA_MUSIC_FOOD    Amount    ARGTYPE_IDENTITY    2
    
    But either way, it just simply does nothing, and I don't know why. it's creating all the database entries, it's just not applying them in game, though it is applying the Great Musician Points ability to my units.
     
  18. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    And a somewhat more random and general of a question: Does civ 6 break if someone creates a promotion tree with more than 7 promotions? I know units can have more than 7 promotions if they switch promotion class somewhere along the line, I've had 14 from holding units back to fill their promotion tree before letting them upgrade.
     
  19. LeeS

    LeeS Imperator Supporter

    Joined:
    Jul 23, 2013
    Messages:
    6,872
    Location:
    Illinois, USA
    Code:
    			<ModifierId>TRAIT_GREAT_WORK_PRODUCTION_SCULPTURE</ModifierId>
    			<Name>GreatWorkObjectType</Name>
    			<Value>GREATWORKOBJECT_SCULPTURE</Value>
    		</Row>
    		<Row>
    			<ModifierId>TRAIT_GREAT_WORK_PRODUCTION_SCULPTURE</ModifierId>
    			<Name>YieldType</Name>
    			<Value>YIELD_PRODUCTION</Value>
    		</Row>
    		<Row>
    			<ModifierId>TRAIT_GREAT_WORK_PRODUCTION_SCULPTURE</ModifierId>
    			<Name>YieldChange</Name>
    			<Value>2</Value>
    		</Row>
    You need to use YieldChange where you currently are using Amount, and you need to use YieldType where you are currently using YieldChange. When something does not work first thing is to look at Database log for error reports, then Modding log to ensure the file is actually being loaded by the game. Then, if these two logs show no errors, the next step is to look at the example you are copying from the original game code or else to logically think through the argument-types you are specifying.

    It makes no logical sense to state "YieldChange" and then to specify a value of "YIELD_PRODUCTION" because everywhere else that "YieldChange" is used it requires an integer yield-amount value.

    For whatever reason Firaxis decided to code this particular ModifierType to expect a "YieldChange" argument instead of an "Amount" argument. I certainly did not pick up on this until I looked at the game's original code for how the Nkisi trait works.

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

    So this would be needed to attempt using one unified ModifierId
    Code:
    INSERT INTO    ModifierArguments
            (ModifierId,                                        Name,                        Value                        )
    VALUES
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'YieldChange',                    '2,2'                            ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'GreatWorkObjectType',        'GREATWORKOBJECT_MUSIC'        ),
            ('MODIFIER_ZAG_SUMETAL_UA_MUSIC_YIELD',                'YieldType',                'YIELD_PRODUCTION,YIELD_FAITH'            );
     
  20. Zagaroth

    Zagaroth Chieftain

    Joined:
    Nov 27, 2009
    Messages:
    60
    Oh Bloody... that makes perfect sense. I see it now. I just some how was being blind, even when I went back and looked at the Nkisi ability for reference. Thank you!
     

Share This Page