Example Scripts

From Total War Modding
Revision as of 07:54, 3 February 2021 by Aexrael (talk | contribs)

A list of example scripts that can easily be copied, edited and then put into a mod.

Using Example Scripts

Unless otherwise stated these scripts go into a .pack file at `script/campaign/mod/?.lua`, replace ? with whatever your file name is.

Each script listed is self-contained - so you can use multiple of the example scripts in a single .lua file.

When using the scripts, please keep the credits at the top and don't remove comments. Comments are the text following -- or in a comment block denoted by --Text here .

Typically an example script will have a list of variables that should be changed to tailor the script to your particular mod, these will often have comments next to them explaining where you will find the keys or values from.

Example in the Replace Starting General example script, you have a line that reads 'local faction_name = "wh_main_emp_empire";'

This could instead be changed to 'local faction_name = "wh2_dlc11_vmp_the_barrow_legion";' to affect the Barrow Legion faction instead of The Empire.

If there are out() calls within the example script, you are encouraged to insert a unique text identifier, so you can find your unique output in the script logs using ctrl+f.

Example in the Replacing Starting General Script, replace REPLAC: with your unique identifier, maybe the starting letters of your discord username, or the mod name or the name of your cat, or something else unique to you.

Contributing new scripts

If you have some generic scripted functionality you think would be useful for the wider community, please consider adding it to the wiki here, or bring attention to it via Modding Discord in the channel for the wiki.

Add a new Sub-Heading 1 within the Example Scripts section below, give it a meaningful title and a short description. Include what games it is valid for and any specific notes necessary, ie. has to go in this directory, has to be done this way etc.

Avoid using global variables in the example scripts, use local variables and local functions to avoid incidents involving scripts that have overlapping names. Make sure to use comments explaining what the various parts of the script is doing or when referring to specific keys from the database, like where to find them. Context and explanation goes a long way towards helping make sense of the scripts for beginners.

If your script runs through a single init function that's triggered through a first tick callback, give the local function a meaningful name and implement the first-tick-callback, and leave it at that. No need to have the modder replace the local function name in their own replication.

Mind that plopping something in this page leaves it open for collaboration, so someone in the future may come in and add more comments, change anything necessary for an update, make an extra version for another game, or much else. If you're editing the original script, leave the credits the same, or add your name to the credits if you think the addition is meaningful. Don't remove the OG author for sure.

Example Scripts

Replacing a Starting General

--[[
	Script by Aexrael Dex
	Replaces the starting general for a specific faction
]]

local function replace_starting_general()
	if cm:is_new_game() then
		-- The Empire
		local faction_name = "wh_main_emp_empire";		-- Faction key from Factions table
		local faction = cm:get_faction(faction_name);

		if faction:is_null_interface() == false and faction:is_dead() == false then

			-- Creating replacement for Karl Franz with a regular Empire General
			local general_details = {
				general_faction = faction_name,
				unit_list = "wh_main_emp_cav_reiksguard,wh_main_emp_cav_reiksguard,wh_main_emp_cav_reiksguard"; -- unit keys from main_units table
				region_key = faction:home_region():name(),
				type = "general",																				-- Agent type
				subtype = "emp_lord",																			-- Agent subtype
				forename = "names_name_1904032251",																-- From local_en names table, Bernhoff the Butcher is now ruler of Reikland
				clanname = "",																					-- From local_en names table
				surname = "names_name_151217003",																-- From local_en names table
				othername = "",																					-- From local_en names table
				is_faction_leader = true,																		-- Bool for whether the general being replaced is the new faction leader
				trait = "wh2_dlc09_trait_benevolence"															-- The trait key you want to assign to the new General from character traits table
			};

			local general_x_pos, general_y_pos = cm:find_valid_spawn_location_for_character_from_settlement(general_details.general_faction, general_details.region_key, false, true, 8);
			out(faction_name .. " home region name is " .. general_details.region_key);

			cm:create_force_with_general(
				general_details.general_faction,
				general_details.unit_list,
				general_details.region_key,
				general_x_pos,
				general_y_pos,
				general_details.type,
				general_details.subtype,
				general_details.forename,
				general_details.clanname,
				general_details.surname,
				general_details.othername,
				general_details.is_faction_leader,

				-- Generals created this way does not come with a trait normally
				function(cqi)
					local char_str = cm:char_lookup_str(cqi);

					-- Adding a new trait to the above general
					cm:force_add_trait(char_str, general_details.trait, true);
					out("Adding Replacement General's trait");
				end
			);
			out("Created replacement Lord " .. general_details.forename .. " for " .. faction_name);

			-- Killing Karl Franz permanently
			local char_list = faction:character_list();
			local char_subtype = "emp_karl_franz"; -- Karl Franz's agent subtype
			local char_forename = "names_name_2147343849"; -- Karl Franz's forename

			for i = 0, char_list:num_items() - 1 do
				local current_char = char_list:item_at(i);
				local char_str = cm:char_lookup_str(current_char);

				if current_char:is_null_interface() == false and current_char:character_subtype_key() == char_subtype and current_char:get_forename() == char_forename and current_char:has_military_force() == true then
					cm:set_character_immortality(char_str, false);
					cm:disable_event_feed_events(true, "wh_event_category_character", "", "");
					cm:kill_character(current_char:command_queue_index(), true, true);
					cm:callback(function() cm:disable_event_feed_events(false, "wh_event_category_character", "", "") end, 0.5);
					out("Killing original " .. char_subtype .. " with forename " .. char_forename .. " for " .. faction_name .. " permanently");
				end;
			end;
		end;
	end;
end;

cm:add_first_tick_callback(function() replace_starting_general() end);

Adding custom RoRs to mercenary pool

--[[
    Script by Aexrael Dex
    Adds custom Regiments of Reknown to defined factions
]]

local function cror_initiator()
    -- Checking whether the script has already run for saved games and if it has then the script doesn't need to run again
    if cm:get_saved_value("custom_ror_enabled") == nil then

        -- Table for faction, unit key and parameters for add_unit_to_faction_mercenary_pool
        local cror_list = {
            {faction = "wh_main_vmp_schwartzhafen", unit = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", count = 1, rcp = 100, munits = 1, murpt = 0.1, xplevel = 0, frr = "", srr = "", trr = "", replen = false},
            {faction = "wh_main_vmp_vampire_counts", unit = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", count = 1, rcp = 100, munits = 1, murpt = 0.1, xplevel = 0, frr = "", srr = "", trr = "", replen = false}
        };

        -- Loop for the table above
        for i = 1, #cror_list do
            local faction_str = cror_list[i].faction; -- Faction whose pool the unit(s) should be added to
            local faction_obj = cm:get_faction(faction_str); -- FACTION_SCRIPT_INTERFACE faction
            local unit_key = cror_list[i].unit; -- Key of unit to add to the mercenary pool, from the main_units table
            local unit_count = cror_list[i].count; -- Number of units to add to the mercenary pool
            local rcp = cror_list[i].rcp; -- Replenishment chance, as a percentage
            local munits = cror_list[i].munits; -- The maximum number of units of the supplied type that the pool is allowed to contain.
            local murpt = cror_list[i].murpt; -- The maximum number of units of the supplied type that may be added by replenishment per-turn
            local xplevel = cror_list[i].xplevel; -- The experience level of the units when recruited
            local frr = cror_list[i].frr; -- (may be empty) The key of the faction who can actually recruit the units, from the factions database table
            local srr = cror_list[i].srr; -- (may be empty) The key of the subculture who can actually recruit the units, from the cultures_subcultures database table
            local trr = cror_list[i].trr; -- (may be empty) The key of a technology that must be researched in order to recruit the units, from the technologies database table
            local replen = cror_list[i].replen; -- Allow replenishment of partial units

            -- Adding the listed unit to the listed faction in the above table
            cm:add_unit_to_faction_mercenary_pool(faction_obj, unit_key, unit_count, rcp, munits, murpt, xplevel, frr, srr, trr, replen);

            -- Setting saved value, so that the script doesn't run again when reloaded from a saved game
            cm:set_saved_value("custom_ror_enabled", true);

            -- Debug message for log
            out("adding the custom ror unit " .. unit_key .. " to " .. faction_str);
	    end;
    end;
end;

cm:add_first_tick_callback(function() cror_initiator() end);

Replacing Starting Armies

--[[
	Script by Aexrael Dex
	Replaces the starting units for the designated characters
]]

-- Rename edit_starting_army
local function edit_starting_army()
    if cm:is_new_game() then
        local custom_starting_army = {
            -- Vlad, Carsteins
            {faction = "wh_main_vmp_schwartzhafen", subtype = "dlc04_vmp_vlad_con_carstein", forename = "names_name_2147345130", units = {"wh_main_vmp_inf_skeleton_warriors_0", "wh_main_vmp_inf_skeleton_warriors_0", "wh_main_vmp_mon_fell_bats", "wh_main_vmp_mon_fell_bats", "wh_main_vmp_cav_black_knights_0", "wh_main_vmp_cav_black_knights_0"}},
            -- Isabella, Carsteins
            {faction = "wh_main_vmp_schwartzhafen", subtype = "pro02_vmp_isabella_von_carstein", forename = "names_name_2147345124", units = {"wh_main_vmp_inf_zombie", "wh_main_vmp_inf_zombie", "wh_main_vmp_mon_dire_wolves", "wh_main_vmp_mon_dire_wolves", "wh_main_vmp_mon_fell_bats", "wh_main_vmp_mon_vargheists"}}
        };

        for i = 1, #custom_starting_army do
            local faction_str = custom_starting_army[i].faction;
            local faction_obj = cm:get_faction(faction_str);
            local char_list = faction_obj:character_list();
            local general_subtype = custom_starting_army[i].subtype;
            local general_forename = custom_starting_army[i].forename;
            local unit_list = custom_starting_army[i].units;

            for j = 0, char_list:num_items() - 1 do
                local current_char = char_list:item_at(j);
        
                if current_char:is_null_interface() == false and current_char:character_subtype_key() == general_subtype and current_char:get_forename() == general_forename and current_char:has_military_force() == true then
                    cm:remove_all_units_from_general(current_char);
                    out("Removing starting units from " .. general_subtype .. " with forename " .. general_forename);

                    for k = 1, #unit_list do
                        local unit = unit_list[k];
                        cm:grant_unit_to_character(cm:char_lookup_str(current_char:cqi()), unit);
                        out("Granting new starting units to " .. general_subtype .. " with forename " .. general_forename);
                    end;
                end;
            end;
        end;
    end;
end;

-- Rename edit_starting_army to match the function name at the top
cm:add_first_tick_callback(function() edit_starting_army() end);