Example Scripts: Difference between revisions
No edit summary |
|||
(2 intermediate revisions by the same user not shown) | |||
Line 42: | Line 42: | ||
-- Call our "init" function. | -- Call our "init" function. | ||
init()</nowiki> | init()</nowiki> | ||
== Warhammer III Example Scripts == | |||
=== Adding RoRs to mercenary pool === | |||
<nowiki>--[[ | |||
Script by Aexrael Dex | |||
Adds custom Regiments of Renown to specified factions | |||
]] | |||
--Edited to function with total war warhammer 3, by All is Dust | |||
local function add_custom_ror() | |||
-- Easy data table for faction info and unit info | |||
local ror_table = { -- A table of many RoR's ---- BEGIN REWRITE | |||
{ -- This is the first RoR we wish to spawn | |||
faction_key = "wh_main_vmp_schwartzhafen", -- The faction we're adding this RoR to; from `factions` | |||
unit_key = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", -- The unit key; from `main_units` | |||
merc_pool = "renown", -- The mercenary pool we're adding this RoR to; from `recruitment_sources` | |||
merc_group = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", -- The mercenary pool group this unit belongs to; in `mercenary_unit_groups` | |||
count = 1, -- The number of RoRs we're adding; this will be 1 by default, only put this line if you're seeking to change the number added | |||
}, -- and you can make a new table for each other RoR you're seeking to add! | |||
} -- Closing out the ror_table variable! | |||
---- END REWRITE. | |||
-- List of default values to shove into the function before; shouldn't need to be changed, usecase may vary. | |||
local defaults = { | |||
replen_chance = 100, | |||
max = 1, | |||
max_per_turn = 0.1, | |||
xp_level = 0, | |||
faction_restriction = "", | |||
subculture_restriction = "", | |||
tech_restriction = "", | |||
partial_replenishment = true, | |||
} | |||
for i, ror in pairs(ror_table) do | |||
local faction_key, unit_key = ror.faction_key, ror.unit_key | |||
local merc_pool, merc_group = ror.merc_pool, ror.merc_group | |||
local count = ror.count or 1 -- if ror.count is undefined, we'll just use the default of 1! | |||
local faction = cm:get_faction(faction_key) | |||
if faction then | |||
cm:add_unit_to_faction_mercenary_pool( | |||
faction, | |||
unit_key, | |||
merc_pool, | |||
count, | |||
defaults.replen_chance, | |||
defaults.max, | |||
defaults.max_per_turn, | |||
defaults.faction_restriction, | |||
defaults.subculture_restriction, | |||
defaults.tech_restriction, | |||
defaults.partial_replenishment, | |||
merc_group | |||
) | |||
end | |||
end | |||
end | |||
cm:add_first_tick_callback(function() | |||
core:call_once( | |||
"my_custom_function", -- RENAME this to a unique string; this is what the game uses to determine if the below code has been run before, must be unique per instance! | |||
add_custom_ror -- Run the above function, rename if you've changed the name of the function above! | |||
) | |||
end);</nowiki> | |||
== Warhammer II Example Scripts == | == Warhammer II Example Scripts == | ||
Line 405: | Line 473: | ||
cm:add_first_tick_callback(function() add_unique_agent() end);</nowiki> | cm:add_first_tick_callback(function() add_unique_agent() end);</nowiki> | ||
Latest revision as of 22:59, 27 November 2022
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.
Global Example Scripts
Hello World
This simple script allows you to implement a very simple logging procedure:
-- Define our function "init" that is only visible to the .lua file we're making! local function init() -- Call the CA function out (name may change between games!), may require the use of a Script Log Activator mod to actually see the text output out("Hello world!") end -- Call our "init" function. init()
Warhammer III Example Scripts
Adding RoRs to mercenary pool
--[[ Script by Aexrael Dex Adds custom Regiments of Renown to specified factions ]] --Edited to function with total war warhammer 3, by All is Dust local function add_custom_ror() -- Easy data table for faction info and unit info local ror_table = { -- A table of many RoR's ---- BEGIN REWRITE { -- This is the first RoR we wish to spawn faction_key = "wh_main_vmp_schwartzhafen", -- The faction we're adding this RoR to; from `factions` unit_key = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", -- The unit key; from `main_units` merc_pool = "renown", -- The mercenary pool we're adding this RoR to; from `recruitment_sources` merc_group = "wh2_dlc11_cst_inf_zombie_deckhands_mob_ror_0", -- The mercenary pool group this unit belongs to; in `mercenary_unit_groups` count = 1, -- The number of RoRs we're adding; this will be 1 by default, only put this line if you're seeking to change the number added }, -- and you can make a new table for each other RoR you're seeking to add! } -- Closing out the ror_table variable! ---- END REWRITE. -- List of default values to shove into the function before; shouldn't need to be changed, usecase may vary. local defaults = { replen_chance = 100, max = 1, max_per_turn = 0.1, xp_level = 0, faction_restriction = "", subculture_restriction = "", tech_restriction = "", partial_replenishment = true, } for i, ror in pairs(ror_table) do local faction_key, unit_key = ror.faction_key, ror.unit_key local merc_pool, merc_group = ror.merc_pool, ror.merc_group local count = ror.count or 1 -- if ror.count is undefined, we'll just use the default of 1! local faction = cm:get_faction(faction_key) if faction then cm:add_unit_to_faction_mercenary_pool( faction, unit_key, merc_pool, count, defaults.replen_chance, defaults.max, defaults.max_per_turn, defaults.faction_restriction, defaults.subculture_restriction, defaults.tech_restriction, defaults.partial_replenishment, merc_group ) end end end cm:add_first_tick_callback(function() core:call_once( "my_custom_function", -- RENAME this to a unique string; this is what the game uses to determine if the below code has been run before, must be unique per instance! add_custom_ror -- Run the above function, rename if you've changed the name of the function above! ) end);
Warhammer II 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 RoRs to mercenary pool
--[[ Script by Aexrael Dex Adds custom Regiments of Reknown to specified factions ]] local function add_custom_ror() -- 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_key = "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 = true}, {faction_key = "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 = true} }; -- Loop for the table above for i = 1, #cror_list do local faction_name = cror_list[i].faction_key; -- Faction whose pool the unit(s) should be added to local faction = cm:get_faction(faction_name); -- FACTION_SCRIPT_INTERFACE 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, unit_key, unit_count, rcp, munits, murpt, xplevel, frr, srr, trr, replen); -- Debug message for log out("CROR: adding the custom ror unit " .. unit_key .. " to " .. faction_name); end; -- 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); end; end; cm:add_first_tick_callback(function() add_custom_ror() end);
Replacing Starting Armies
--[[ Script by Aexrael Dex Replaces the starting units for specified starting Lords ]] local function army_tweaks() -- Checking whether it's a new game, we don't want to replace armies in the middle of a campaign if cm:is_new_game() then -- Creating a table with entries for the various starting Lords, their Faction key from Factions table, subtype key from agent_subtypes, Forename from names table and Unit List with keys from Main Units local starting_army = { -- Vlad, Carsteins {faction_key = "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_key = "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, #starting_army do local faction_name = starting_army[i].faction_key; local faction = cm:get_faction(faction_name); local char_list = faction:character_list(); local general_subtype = starting_army[i].subtype; local general_forename = starting_army[i].forename; local unit_list = starting_army[i].units; for j = 0, char_list:num_items() - 1 do local current_char = char_list:item_at(j); local char_str = cm:char_lookup_str(current_char); 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 -- Removing all existing units from the General cm:remove_all_units_from_general(current_char); out("ARMY: Removing starting units from " .. general_subtype .. " with forename " .. general_forename); for k = 1, #unit_list do local unit = unit_list[k]; -- Granting new units to the General cm:grant_unit_to_character(char_str, unit); out("ARMY: Adding new starting units to " .. general_subtype .. " with forename " .. general_forename); end; end; end; end; end; end; cm:add_first_tick_callback(function() army_tweaks() end);
Changing CAI based on campaign difficulty
--[[ Script by Aexrael Dex Replaces the Campaign AI Personality for specific factions depending on the chosen campaign difficulty level ]] local function replace_cai_difficulty() if cm:is_new_game() == true then local difficulty_str = cm:get_difficulty(true); local def_personality = ""; local hef_personality = ""; local wef_personality = ""; -- CAI personality to use for easy difficulty if difficulty_str == "easy" then def_personality = "wh2_darkelf_early_easy"; hef_personality = "wh2_highelf_early_easy"; wef_personality = "wh_dlc05_wood_elves_default_main"; -- CAI personality to use for normal difficulty elseif difficulty_str == "normal" then def_personality = "wh2_darkelf_early"; hef_personality = "wh2_highelf_early"; wef_personality = "wh_dlc05_wood_elves_default_main"; -- CAI personality to use for hard difficulty elseif difficulty_str == "hard" then def_personality = "wh2_darkelf_early_hard"; hef_personality = "wh2_highelf_early_hard"; wef_personality = "wh_dlc05_wood_elves_default_main"; -- CAI personality to use for very hard difficulty elseif difficulty_str == "very hard" then def_personality = "wh2_darkelf_early_hard"; hef_personality = "wh2_highelf_early_hard"; wef_personality = "wh_dlc05_wood_elves_default_main"; -- CAI personality to use for legendary difficulty elseif difficulty_str == "legendary" then def_personality = "wh2_darkelf_early_hard"; hef_personality = "wh2_highelf_early_hard"; wef_personality = "wh_dlc05_wood_elves_default_main"; end; local faction_list = cm:model():world():faction_list(); for i = 0, faction_list:num_items() - 1 do local faction = faction_list:item_at(i); local faction_name = faction:name(); local faction_culture = faction:culture(); -- Checking whetether the faction exists and is alive if faction:is_null_interface() == false and faction:is_dead() == false and faction:is_human() == false then -- Dark Elves culture if faction_culture == "wh2_main_def_dark_elves" then -- Changing the CAI for all Dark Elf factions cm:force_change_cai_faction_personality(faction_name, def_personality); out("ELF: Changing CAI personality for " .. faction_name .. " to " .. def_personality .. " on " .. difficulty_str .. " difficulty"); -- High Elves culture elseif faction_culture == "wh2_main_hef_high_elves" then -- Changing the CAI for all High Elf factions cm:force_change_cai_faction_personality(faction_name, hef_personality); out("ELF: Changing CAI personality for " .. faction_name .. " to " .. hef_personality .. " on " .. difficulty_str .. " difficulty"); -- Wood Elves culture elseif faction_culture == "wh_dlc05_wef_wood_elves" then -- Changing the CAI for all Wood Elf factions cm:force_change_cai_faction_personality(faction_name, wef_personality); out("ELF: Changing CAI personality for " .. faction_name .. " to " .. wef_personality .. " on " .. difficulty_str .. " difficulty"); end; end; end; end; end; cm:add_first_tick_callback(function() replace_cai_difficulty() end);
Spawning a Unique Agent
--[[ Script by Aexrael Dex Spawns a Unique Agent next to the starting lord of a specified faction ]] local function add_unique_agent() -- 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("unique_agent_enabled") == nil then -- Starting agent setup unique_agent_setup(); end; end; function unique_agent_setup() -- Agent Details local agent_details = { faction_str = "wh2_dlc13_emp_the_huntmarshals_expedition", -- faction_key from factions forename_key = "names_name_2147359013", -- forename_key from names family_name_key = "names_name_1535812850", -- family_name_key from names subtype_key = "wh2_dlc13_emp_hunter_jorek_grimm", -- agent subtype_key from agent_subtypes art_set_key = "wh2_dlc13_art_set_emp_hunter_jorek_grimm_0", -- agent art_set_id from campaign_character_arts unique_string = "wh2_dlc13_emp_hunter_jorek_grimm", -- unique agent string from unique_agents saved_value = "unique_agent_enabled", -- saved_value string trait = "wh2_dlc09_trait_benevolence" -- agent trait from character_traits }; -- Monitor activated, listening for FactionTurnStart for The Huntmarshals Expedition core:add_listener( "unique_agent_setup", "FactionTurnStart", function(context) return context:faction():name() == agent_details.faction_str; end, function(context) -- Spawning Jorek as a unique agent next to Markus local faction = cm:get_faction(agent_details.faction_str); local faction_cqi = faction:command_queue_index(); local faction_leader_cqi = faction:faction_leader():command_queue_index(); cm:disable_event_feed_events(true, "wh_event_category_agent", "", ""); cm:spawn_unique_agent_at_character( faction_cqi, agent_details.unique_string, faction_leader_cqi, true ); cm:callback(function() cm:disable_event_feed_events(false, "wh_event_category_agent", "", ""); CampaignUI.ClearSelection(); end, 0.5); out("UNIQ: Spawned Jorek next to Markus"); -- Looping through the character list for The Huntmarshals Expedition local char_list = faction:character_list(); 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); -- Adding Joreks trait, replenishing AP and overriding the art set if current_char:is_null_interface() == false and current_char:character_subtype_key() == agent_details.subtype_key then -- Adding trait cm:force_add_trait(char_str, agent_details.trait, false); out("UNIQ: Adding " .. agent_details.trait .. " to Jorek"); -- Replenishing action points cm:replenish_action_points(char_str); out("UNIQ: Replenishing the action points of Jorek"); -- Failsafe for the random chance that the art_set doesn't apply properly cm:add_unit_model_overrides(char_str, agent_details.art_set_key); out("UNIQ: Adding unit model override for Jorek"); end; end; -- Setting saved value, so that the script doesn't run again when reloaded from a saved game cm:set_saved_value(agent_details.saved_value, true); out("UNIQ: Setting saved value " .. agent_details.saved_value); end, false ); end; cm:add_first_tick_callback(function() add_unique_agent() end);