How to properly make a new Unit Ability (in UnitAbilities)?

Luke Vo

Chieftain
Joined
Apr 29, 2019
Messages
59
I am trying to create my own UnitAbility similar to how `ABILITY_TRADE_ROUTE_PLUNDER_IMMUNITY_SEA` or `ABILITY_ECONOMIC_GOLDEN_AGE_PLUNDER_IMMUNITY` works. Here's the code:

Code:
INSERT INTO UnitAbilities(UnitAbilityType, Name, Description, Inactive) VALUES
    ('ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY', 'LOC_ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY_NAME', 'LOC_ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY_DESC', 1);
INSERT INTO UnitAbilityModifiers(UnitAbilityType, ModifierId) VALUES
    ('ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY', 'TRADER_MERCENARIES_IMMUNITY_LAND'),
    ('ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY', 'TRADER_MERCENARIES_IMMUNITY_SEA');

The database entries go in, but I cannot grant that ability to any unit, even with Firetuner (in the code, I use
a MODIFIER_PLAYER_UNITS_GRANT_ABILITY modifier).

After some investigation, I realize that certain ability can only be granted to certain unit, including in Firetuner. For example, Pikeman has their own `ABILITY_ANTI_CALVARY` and that ability cannot be added for any other unit class. It's the same for `ABILITY_TRADE_ROUTE_PLUNDER_IMMUNITY_SEA` or `ABILITY_ECONOMIC_GOLDEN_AGE_PLUNDER_IMMUNITY`.

It's interesting and I guess it's some kind of optimization, because the modifier for Golden Age simply grants ABILITY_ECONOMIC_GOLDEN_AGE_PLUNDER_IMMUNITY to every units (there is no condition), however checking in the Firetuner, only Traders get that ability.

However, I cannot find any reference in the database about which ability can go to which unit/unit classes. Can someone point it out to me? Thanks!
 
I have found it. I found it from the code of Alexander Scenario, they add new abilities also in the TypeTags table (and obviously the Ability needs to be manually added in Type table too). So for my case, I added:

Code:
INSERT INTO Types(Type, Kind) VALUES
    ('ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY', 'KIND_ABILITY');
INSERT INTO TypeTags(Type, Tag) VALUES
    ('ABILITY_TRADER_MERCENARIES_PLUNDER_IMMUNITY', 'CLASS_TRADER');
 
I've isolated what I believe is all the (SQL) code pertaining to the creation and assignment of a unit ability and its modifiers (and their requirements) in the context of my custom civ's unique unit.

I've used a mix of templates, browsing the game's debug database and this useful Google Sheet to figure out the stuff I needed. The Collections bit is rather hard to grasp, but unless you're attempting something really exotic, you can look into how similar abilities work and try to mimic what you need.
Code:
-----------------------------------------------
-- Types
-----------------------------------------------  
  
INSERT INTO Types
        (Type,                                                        Kind            )
VALUES    ('ABILITY_WINGARDE_GREENCOAT',                                'KIND_ABILITY'    ),
        ('MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    'KIND_MODIFIER'    ),
        ('MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    'KIND_MODIFIER'    );

-----------------------------------------------
-- Tags
-----------------------------------------------  
  
INSERT INTO Tags
        (Tag,                Vocabulary        )
VALUES    ('CLASS_GREENCOAT',    'ABILITY_CLASS'    );

-----------------------------------------------
-- TypeTags
-----------------------------------------------      

INSERT INTO TypeTags
        (Type,                            Tag                    )
VALUES    ('ABILITY_WINGARDE_GREENCOAT',    'CLASS_GREENCOAT'    );

-----------------------------------------------
-- UnitAbilities
-----------------------------------------------

INSERT INTO UnitAbilities
        (UnitAbilityType,                Name,                                    Description                                        )
VALUES    ('ABILITY_WINGARDE_GREENCOAT',    'LOC_ABILITY_WINGARDE_GREENCOAT_NAME',    'LOC_ABILITY_WINGARDE_GREENCOAT_DESCRIPTION'    );

-----------------------------------------------
-- DynamicModifiers

-- This is where we start to define the Modifiers.
-----------------------------------------------

INSERT INTO    DynamicModifiers
        (ModifierType,                                                CollectionType,                EffectType                                                )
VALUES    ('MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    'COLLECTION_UNIT_COMBAT',    'EFFECT_ADJUST_PLAYER_STRENGTH_MODIFIER'                ),
        ('MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    'COLLECTION_UNIT_COMBAT',    'EFFECT_ADJUST_PLAYER_STRENGTH_MODIFIER'                );

-----------------------------------------------
-- Modifiers

-- This is where we attach the ModType made in "DynamicModifiers" to our "ModifierID" mentioned in the first section.
-----------------------------------------------

INSERT INTO    Modifiers
        (ModifierId,                                                ModifierType,                                            OwnerRequirementSetId,    SubjectRequirementSetId,                        Permanent,    RunOnce    )
VALUES    ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    'MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    NULL,                    'REQSET_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE',        0,            0        ),
        ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    'MODTYPE_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    NULL,                    'REQSET_WINGARDE_GREENCOAT_PLOT_IS_FOREST',        0,            0        );

-----------------------------------------------
-- UnitAbilityModifiers

-- These setup the modifers for your ability by hooking your specified modifiers into the ability.
-- "UnitAbilityType" is the Unit's Ability to which you are inserting the "ModifierID", or the modifier, into.
-----------------------------------------------
      
INSERT INTO UnitAbilityModifiers
        (UnitAbilityType,                ModifierId                                                    )
VALUES    ('ABILITY_WINGARDE_GREENCOAT',    'MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE'        ), -- Inserting the "More Strength in Rainforest Tiles" Modifier
        ('ABILITY_WINGARDE_GREENCOAT',    'MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST'        ); -- Inserting the "More Strength in Forest Tiles" Modifier

-----------------------------------------------
-- ModifierArguments

-- This is where we further define the Modifiers.
-----------------------------------------------

INSERT INTO    ModifierArguments      
        (ModifierId,                                                Name,        Value    )
VALUES    ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    'Amount',    10        ), -- States that you adjust the strength by 10.
        ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    'Amount',    10        ); -- States that you adjust the strength by 10.

-----------------------------------------------
-- ModifierStrings

-- This is where we are going to link the Localisation to the Unit's Ability
-----------------------------------------------

INSERT INTO ModifierStrings
        (ModifierId,                                                Context,    Text                                                        )
VALUES  ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE',    'Preview',    'LOC_MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_JUNGLE'    ),
        ('MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST',    'Preview',    'LOC_MODIFIER_WINGARDE_GREENCOAT_ADJUST_STRENGTH_IN_FOREST'    );
        -- Links the Unit to display his ability's text.

-----------------------------------------------
-- Requirements

-- This is where you define your Requirements
-----------------------------------------------

INSERT INTO Requirements
        (RequirementId,                                RequirementType,                Likeliness,   Inverse,   Triggered)
VALUES    ('REQ_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE',    'REQUIREMENT_PLOT_FEATURE_TYPE_MATCHES',    0,  0,  0            ), -- Defines the Requirement as whenever you're in a (Feature) tile.
        ('REQ_WINGARDE_GREENCOAT_PLOT_IS_FOREST',    'REQUIREMENT_PLOT_FEATURE_TYPE_MATCHES',    0,  0,  0            ); -- Defines the Requirement as whenever you're in a (Feature) tile.
  
-------------------------------------
-- RequirementArguments
-------------------------------------
INSERT INTO RequirementArguments
        (RequirementId,                                     Name,                    Value                 )
VALUES    ('REQ_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE',             'FeatureType',            'FEATURE_JUNGLE'    ),
        ('REQ_WINGARDE_GREENCOAT_PLOT_IS_FOREST',             'FeatureType',            'FEATURE_FOREST'    );

-----------------------------------------------
-- RequirementSets

-- This is where you define your Requirement Set
-----------------------------------------------

INSERT INTO RequirementSets
        (RequirementSetId,                                RequirementSetType            )
VALUES    ('REQSET_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE',    'REQUIREMENTSET_TEST_ANY'    ),
        ('REQSET_WINGARDE_GREENCOAT_PLOT_IS_FOREST',    'REQUIREMENTSET_TEST_ANY'    );
        -- Defines the ReqSet.

-----------------------------------------------
-- RequirementSetRequirements

-- This is where you link your RequirementSet to your actual RequirementIDs
-----------------------------------------------

INSERT INTO RequirementSetRequirements
        (RequirementSetId,                                RequirementId                                )
VALUES    ('REQSET_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE',    'REQ_WINGARDE_GREENCOAT_PLOT_IS_JUNGLE'        ),
        ('REQSET_WINGARDE_GREENCOAT_PLOT_IS_FOREST',    'REQ_WINGARDE_GREENCOAT_PLOT_IS_FOREST'        );
        -- Defines the ReqSet by linking it to a RequirmentID
PS: The Pikeman's anti-cavalry bonus I'd wager belongs to the anti-cavalry unit class and not every anti-cav unit individually.
 
Thanks, I also figured out from the code from Alexander Scenario too. Thanks for the spreadsheet though, that looks useful!
 
Top Bottom