Page 1 of 5 12345 LastLast
Results 1 to 20 of 92

Thread: [scripting] The "does this code work" - Thread

  1. #1

    Default [scripting] The "does this code work" - Thread

    Hey folks,
    I thought I'd start some kind of Q and A thread for scripting porposes, where you can post a pice of code and have it reviewed by more advanced users. This might be particularly helpful for scripting.
    For example, I have written this small function, which aims at toggling FOW for all regions a particular faction owns. This is thought as a debugging tool: check if your modifications are applied as intended without having to remove the whole FOW, which should result in performace issues.
    Code:
    local function showAiFactions(context)
        if context.string == "rom_carthage" and context:faction():is_human() == false and context:region():owning_faction =="rom_carthage" then
            scripting.game_interface:make_region_visible_in_shroud(context)
        end
    end
    This does not work yet. The problem is, as I can see, that you can make certain regions visible, but not automatically every region a faction owns. It would be far more easy if R2 would support for-loops.

  2. #2

    Default Re: [scripting] The "does this code work" - Thread

    Rome 2 DOES support for loops - it uses Lua, which is a full turing complete scripting language. Even if it didn't support for loops, you can easily fake one with a while, or if you are so inclined, a goto!

    Anyways, what callback are you attaching this to?
    modificateurs sans frontières

    Developer for Ancient Empires
    (scripter, developed tools for music modding, tools to import custom battle maps into campaign)

    Lead developer of Attila Citizenship Population Mod
    (joint 1st place for Gameplay Mods in 2016 Modding Awards)

    Assisted with RMV2 Converter
    (2nd place for Warscape Engine Resources in 2016 Modding Awards)

  3. #3

    Default Re: [scripting] The "does this code work" - Thread

    None Forgot about that... I would take something like:
    Code:
    scripting.AddEventCallBack("FactionTurnStart", showAIFactions);
    Btw: thanks for the info!

    Edit:
    if loops are supported, then I'd write:
    Code:
    local function showAiFactions(context)
    if context.string == "rom_carthage" and context:faction():is_human() == false then
    local regionID = context:region():faction_region_list():num_items();
    while regionID >=0 do
    scripting.game_interface:make_region_visible_in_shroud(regionID);
    end --end while
    end --end if
    end --end function
    or did I misunderstand something?
    Last edited by Fridericus Secundus; November 08, 2014 at 11:16 AM.

  4. #4

    Default Re: [scripting] The "does this code work" - Thread

    There's a context function called "region_list"- you may want to try calling that and seeing what it returns, and see if you could loop through that.
    modificateurs sans frontières

    Developer for Ancient Empires
    (scripter, developed tools for music modding, tools to import custom battle maps into campaign)

    Lead developer of Attila Citizenship Population Mod
    (joint 1st place for Gameplay Mods in 2016 Modding Awards)

    Assisted with RMV2 Converter
    (2nd place for Warscape Engine Resources in 2016 Modding Awards)

  5. #5

    Default Re: [scripting] The "does this code work" - Thread

    hm, region_list has several "subfunctions", for example "num_items", "item_at" etc. Thus, I tried:
    Code:
    local region = context:region():region_list():item_at(2);
            scripting.game_interface:make_region_visible_in_shroud(region);
    which did not work, as did iterating over "num_items". I have RTR Scripting Toolkit enabled and set to full logging mode, but it does not put out any error message. I just get an empty massage after turn 1 started.
    Last edited by Fridericus Secundus; November 09, 2014 at 05:28 AM.

  6. #6
    Litharion's Avatar Artifex
    Join Date
    Sep 2013
    Location
    Germany
    Posts
    2,622

    Default Re: [scripting] The "does this code work" - Thread

    this should help to get the faction owning the region
    context:garrison_residence():faction()

  7. #7

    Default Re: [scripting] The "does this code work" - Thread

    Thanks for the advice...but I bet I don't really understand how to put together the script. In theory, it should be something like
    Code:
    local function showAiFactions(context)
    if <<the local faction is Carthage and Carthage is controlled by AI then
    check for every region if its owning faction is carthage
    if it's true: make region visible
    >>
    end
    I'm really sorry for asking all that stupid stuff. But trying around just fails all the time :-p

  8. #8
    Inevitability won
    Patrician Citizen

    Join Date
    Mar 2010
    Posts
    9,594

    Default Re: [scripting] The "does this code work" - Thread

    So I just did what you wanted and made special care to record what I did, my method and thought process to approaching this would be as such, hopefully you can find this useful:

    ( This all worked for me ingame perfectly fine, however it may be the case that during typing it up I made a syntax error somewhere, so I suggest using this as a guide only! )




    1 - I want to remove the FOW for only the regions of a certain faction, as such I know I need to use the "make_region_visible_in_shroud" function.

    2 - To use this function I need an event in which to call this function and the two arguments that the function takes, which is the faction who will see the FOW removed and the region to remove the FOW from.

    Example usage: scripting.game_interface:make_region_visible_in_shroud("pro_rome", "pro_magna_grecia_italia");

    3 - I want the FOW shown on the start of each of my turns, so I know to use the "FactionTurnStart" event, from that I can check it's my turn with "scripting.game_interface:model():is_player_turn()" and then get the ID of my faction from the string of the context argument for that event.

    So far my code looks like this:
    Code:
    local function OnFactionTurnStart(context)
        local current_faction = context.string;
        
        if scripting.game_interface:model():is_player_turn() == true then
            -- I know that at this point it's the players (my) turn and I have the ID of my faction in the current_faction variable.
        end
    end
    
    scripting.AddEventCallBack("FactionTurnStart", OnFactionTurnStart);

    4 - Now all I need are the ID's of the regions controlled by the faction I want to unhide the FOW of. For that I'll create a new function so as to allow code reusability and keep things neat. My function will take the ID of the player faction and the ID of the faction to unhide the FOW in their regions.

    Code:
    function RemoveFOW(player, factionID)
    -- Do stuff
    end
    5 - I need to be able to access the actual faction object of the faction to unhide the FOW of, so I'll use the "faction_by_key" function and pass it the factionID. With this faction object I can then get the factions regions using the "region_list" method of that faction. My function now looks like this:

    Code:
    function RemoveFOW(player, factionID)
        local faction = scripting.game_interface:model():world():faction_by_key(factionID);
        local factions_regions = faction:region_list();
    end
    6 - I can now iterate through the "factions_regions" list and from that I know I can use the "name" method of the region to get the ID of the region to pass to the "make_region_visible_in_shroud" function. My function is complete and when called will unhide the FOW for the specified factions region in the second argument for the other faction specified in the first argument:

    Code:
    function RemoveFOW(player, factionID)
        local faction = scripting.game_interface:model():world():faction_by_key(factionID);
        local factions_regions = faction:region_list();
        
        for i = 0, factions_regions:num_items() - 1 do
            local region = factions_regions:item_at(i);
            local region_name = region:name();
            scripting.game_interface:make_region_visible_in_shroud(player, region_name);
        end
    end
    7 - I now combine it all together and call my function within the event created earlier to get my faction ID, make sure it used on my turn as that's when I want the FOW unhidden. I also need to make sure to specify here what faction I want the FOW unhidden for:

    The final code
    Code:
    local function OnFactionTurnStart(context)
        local current_faction = context.string;
        
        if scripting.game_interface:model():is_player_turn() == true then
            RemoveFOW(current_faction, "rom_carthage") -- Note: here I set the faction to unhide the FOW of, in this case Carthage
        end
    end
    
    function RemoveFOW(player, factionID)
        local faction = scripting.game_interface:model():world():faction_by_key(factionID);
        local factions_regions = faction:region_list();
        
        for i = 0, factions_regions:num_items() - 1 do
            local region = factions_regions:item_at(i);
            local region_name = region:name();
            scripting.game_interface:make_region_visible_in_shroud(player, region_name);
        end
    end
    
    scripting.AddEventCallBack("FactionTurnStart", OnFactionTurnStart);

  9. #9

    Default Re: [scripting] The "does this code work" - Thread

    excellent stuff.
    This shows the concept how to build up a script, which is extremely helpful, als well as some technical things (didn't know how this worked exactly, like the required parameters for some functions). I hope I can use this in order to write further scripts.

  10. #10
    Litharion's Avatar Artifex
    Join Date
    Sep 2013
    Location
    Germany
    Posts
    2,622

    Default Re: [scripting] The "does this code work" - Thread

    indeed great stuff Mitch, one of the bigger problems is to get the required parameters for the game functions right.

    For example does someone know which parameters are required for the apply_effect_bundle and remove_effect_bundle functions ?
    I only managed to produce crashes when I tried to call the function, which usually happens if wrong parameters are used.

  11. #11
    Inevitability won
    Patrician Citizen

    Join Date
    Mar 2010
    Posts
    9,594

    Default Re: [scripting] The "does this code work" - Thread

    Crash = Not enough parameters
    Function not working = Incorrect parameters

    The hardest aspect of scripting is getting the parameters, I have a big folder of all script files from ETW to R2 and I just do a "Find In Files" search for the function. That 50% of the time finds an example usage from CA, but if that fails you have to just try find them yourself through trial and error. For example I'd try:
    scripting.game_interface:apply_effect_bundle("effect name", "faction id");

  12. #12

    Default Re: [scripting] The "does this code work" - Thread

    That "effect_bundle" thing sounds really interesting. Some of the effects are defined in tables (effect_bundles_to_effects_junctions), but for example the "Ludi Plebeii" have an concrete effect ingame, a bonus on public order. I haven't figured out, however, how this works in detail. There are apparently no scripts doing that, but somehow the bonus has to be linked with the event and some kind of trigger.

  13. #13
    Litharion's Avatar Artifex
    Join Date
    Sep 2013
    Location
    Germany
    Posts
    2,622

    Default Re: [scripting] The "does this code work" - Thread

    Quote Originally Posted by .Mitch. View Post
    Crash = Not enough parameters
    Function not working = Incorrect parameters
    thanks Mitch, this alone is a valuable information. Will do the trial and error thing and post the results later.

    Edit: scripting.game_interface:apply_effect_bundle("effect_bundle name", "faction id", "number of turns");
    the last entry basically determines how long the effect_bundle will be present for the faction e.g. "1" means "1" turn

    Example:
    scripting.game_interface:apply_effect_bundle("festive_delphi", "rom_rome", 100);
    Last edited by Litharion; November 14, 2014 at 08:05 AM.

  14. #14

    Default Re: [scripting] The "does this code work" - Thread

    Quote Originally Posted by Fridericus Secundus View Post
    hm, region_list has several "subfunctions", for example "num_items", "item_at" etc. Thus, I tried:
    Code:
    local region = context:region():region_list():item_at(2);
            scripting.game_interface:make_region_visible_in_shroud(region);
    which did not work, as did iterating over "num_items". I have RTR Scripting Toolkit enabled and set to full logging mode, but it does not put out any error message. I just get an empty massage after turn 1 started.
    Sadly, the R2TR scripting toolkit has no error detecting functionality. It lets you manually log information to a file, but it's incapable of finding logic or syntax errors.
    modificateurs sans frontières

    Developer for Ancient Empires
    (scripter, developed tools for music modding, tools to import custom battle maps into campaign)

    Lead developer of Attila Citizenship Population Mod
    (joint 1st place for Gameplay Mods in 2016 Modding Awards)

    Assisted with RMV2 Converter
    (2nd place for Warscape Engine Resources in 2016 Modding Awards)

  15. #15
    Inevitability won
    Patrician Citizen

    Join Date
    Mar 2010
    Posts
    9,594

    Default Re: [scripting] The "does this code work" - Thread

    I have a pretty flawless approach to finding syntax errors, or indeed most error in a script.

    If I'm making a script for the Augustus Campaign I'll add into the Augusts scripting.lua at the bottom this:

    Code:
    function Log(text)
        local logInterface = io.open(data/error.txt, "w");
        logInterface:write(text.."\n");
        logInterface:flush();
        logInterface:close();
    end;
    
    local OK, errorMsg = pcall(require, "myscriptingfile");
    
    if not OK then
    Log("ERROR: "..errorMsg);
    end
    Then I'll write my script in myscriptingfile.lua, which the main scripting.lua will attempt to load through a require call, but this call is a protected call (pcall) and hence if there are any errors with my script when the script fails during the require call, the function will catch it, the var OK will become false if it failed, and the errorMsg var will contain the error information.

    Hence when I then hit the if statement if the require failed, meaning my script has something wrong with it, It'll print the error to error.txt in the data folder for me to read.

    This will contain information about what the error is, and more important the line number in my script where things went wrong.

    This may all be hard to understand and get working I admit, and it does need certain things done to your script itself to make it work.

  16. #16
    Litharion's Avatar Artifex
    Join Date
    Sep 2013
    Location
    Germany
    Posts
    2,622

    Default Re: [scripting] The "does this code work" - Thread

    even though I know since the Populous modification was revealed that changing the User Interface has to be somehow possible, I have no clue how to do it. Is it possible to actually add local script variables to the UI?

    I am working on a public order script and the big issue is to make the effects visible for the player.

  17. #17

    Default Re: [scripting] The "does this code work" - Thread

    Just a guess: there's a "ui_icon" reference in the effect_bundles table. Same for effects table; this should in my opinion provide the small icons in the province bar. However, I'm not sure how these two tables differ at all, since the outcome appears to be quite similar.

  18. #18
    Litharion's Avatar Artifex
    Join Date
    Sep 2013
    Location
    Germany
    Posts
    2,622

    Default Re: [scripting] The "does this code work" - Thread

    I think they require an actual effect ? The problem is that I don´t use an effect currently in the game to set the public order for a given region.

    Example:

    Spoiler Alert, click show to read: 
    Code:
    local function PublicOrder(context)
    local max_public_order_negative = 15;
    local public_order_negative = 0;
    
    
        if context:character():faction():state_religion() == context:character():garrison_residence():region():majority_religion()
            then public_order_negative = math.ceil(context:character():military_force():unit_list():num_items()/1.5 -1)  
                 elseif context:character():faction():state_religion() ~= context:character():garrison_residence():region():majority_religion()
                   then public_order_negative  = context:character():military_force():unit_list():num_items() -1
        end
        
    if public_order_negative > max_public_order_negative 
       then public_order_negative = max_public_order_negative
     end
    
    -- The public_order_negative value somehow needs to be displayed in the Public Order Overview for the player 
    
        if context:character():has_garrison_residence() == true
            and context:character():faction():is_human() == true  
            and char_is_general_with_army(context:character()) 
         then
            local currentpublicorder = context:character():garrison_residence():region():public_order()
            local newpublicorder = currentpublicorder - public_order_negative                                       
            local region = context:character():garrison_residence():region():name() 
            scripting.game_interface:set_public_order_of_province_for_region(region, newpublicorder);
        end
    end
    Last edited by Litharion; November 15, 2014 at 01:17 PM.

  19. #19

    Default Re: [scripting] The "does this code work" - Thread

    Ah, I see. You would need an effect to display just the current malus on public order the respective function provides, right? Maybe adding a new event or modifying an existing one works? (I didn't have the time to try this yet, but I wanted to play around with the effects in order to learn how this works. One thing is to try adding new events and referencing them using scripts - maybe a nice way to implement my planned "squalor-lategame script", which is similar to yours.)

  20. #20

    Default Re: [scripting] The "does this code work" - Thread

    Apologies for duoble-post!
    Continuing this thought, something like the following should work - as long as i'ts really possible to add new effect_bundles (effects seem to be not that important):
    Code:
    function addSqualor(context)
        if context:faction():imperium_level() >=4 and context:faction():is_human() == true then
        scripting.game_interface:apply_effect_bundle("name_of_added_bundle", "faction id", "1");
        end
    end
    scripting.addEventCallBack("FactionTurnStart", addSqualor);
    It's very simple, but plainly it should apply the effect of the selected bundle (for example a negative effect on public order) every single turn, as long as the imperium level is above or equal four. The effect continues just one turn, but the game should check the conditions again at the start of every new turn, so the whole thing can re-apply.

Page 1 of 5 12345 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •