Post by neppi on Feb 9, 2019 10:48:32 GMT -8
Tweakpack for LD (Mod framework 2.0)
As bigfoot is too busy to continue keeping the Tweakpack updated, he handed it over to me.
This is a collection of tweaks for LD that might be useful for modders, its not complete yet but given there is some new interest in modding, I'm going to release it and update as it goes along. All updates and tweaks should be entirely backwards compatible.
Please feel free to use it, but also please link to this thread so people pick up the latest version rather than include it in your own mods directly, it makes it much easier to fix bugs if they can just download the newest version.
Install:
Copy the Mod folder into the game folder of Sunrider LD
Features:
Options page for mods (by sayonara) :
Basically, this just redefines the preferences screens to add a mods tab. You can add a new screen by appending (<mod_name>, <screen_name>) to `options_mods_list`, and the screen appears in the right-hand pane of the mods tab when you select that mod. The Tweakpack option screen shows how to add buttons. This is especially useful for mod settings which were normally configured in the config.rpy of mods. To change a variable by a button, use SetVariable(). This way the variable cannot be changed, except with another SetVariable(). I will create an option page for my Jaguar mod soon which then can be looked at as an example. The general Syntax is:
init python:
options_mods_list.append(
('My awesome mod', 'modopttest')
)
screen modopttest():
vbox:
spacing 5
text "My Awesome Mod! (test)" size 50 color "#c44"
text "This is a test screen."
text "You could put options here."
Some mods might not want options to be changed during combat if it can break things. To enable this, define your screen with something like this:
...
vbox:
button:
action SensitiveIf(BM.battlemode is False), SetVariable('mod_config_option', 'value'), <or other Actions>
insensitive_background "#888" # or whatever, so you can tell it's disabled
...
-OR-
...
showif BM.battlemode == False:
text "You cannot change Awesome Combat Mod settings during battle"
else:
button:
<etc>
...
Mod interface:
A mod interface is now part of the main menu to improve accessing standalone mods which are not part of the original Sunrider story (like The Void or Arcade) which have to be called with a command in the main menu otherwise. In the main menu there is a new button "Mods". There you can enter a menu where modders can add buttons with custom functions (most likely the Start("start_label") function).
To use, just add your entries to `mod_button_entries`, with an image or text and a set of actions to perform on click. The Tweakpack will look for an image file or image definition matching the value you give for the first entry, but if it doesn't find one then it will format the value as text using a nearly-matching font. Syntax example from the arcade mod to add buttons:
Without a button image:
mod_button_entries.append((
"Arcade",
(Hide("main_menu_mod"), Start("arcade_from_main_menu")),
))
If you possess a proper image, the syntax would look like this:
mod_button_entries.append((
"Mod/arcade/UI/arcade_bt.png",
(Hide("main_menu_mod"), Start("arcade_from_main_menu")),
))
In the Tweakpack folder you can find a template for the button so you can paint your own. I usually assemble my mod button with letters from the already existing buttons.
Start is the label where your mod starts from. Also it is imaginable to perform an action like "Show("your_mod_screen)" where you can make like an option menu for your mod. With SetVariable() the variable is set globally even if you start a new game. No limits are set to your fantasy.
Pictures:
Ava Fix:
Ava can now be shown with dshow before the sprite might change due to story reasons without breaking the game.
Choice variables are now persistent:
Choices from mods can now be put into dump_variables which will be saved in the libday_mp file that will be imported into any future sunrider game.
In addition, any history chosen at the start of the game will also be stored there, so every option is known. Libday in MoA will be updated shortly so it also updates those variables. This lets you callback to events you couldn't before and let mods in later games use variables from LD, but some games will have them set to None if they were imported from MoA so it might be worth putting a check for that in.
Syntax:
variable = 3
dump_variables.append("variable")
# It must be the variable name (so a string) not the actual variable
# If you do dump_variables.append(variable) it will instead add 3 to the list
Decisions:
Decision choices can now have an additional field that is an eval string and lets you pick if options should be available
If there is no additional field, it will always show
Syntax:
$menu_choices = []
$menu_choices.append(["Choice","label","eval condition"])
Example:
label:
$menu_choices = []
$menu_choices.append(["What do you think Asaga?","ask_asaga","asked_asaga"])
# If asked_asaga == True then the option is shown, set to False or something to disable
show screen decision
pause
Objectives
An objectives button is now displayed by the command panel, when it is hovered it displays the name of the mission and any relevant objectives. Objectives for LD missions are already added, and MoA/FA will be added on the MoA mod.
Objectives are easy to add for custom missions.
Syntax:
init 2 python:
objectives[BM.mission] = ["Mission Name",["Eval","objective"],["Eval","objective"],]
BM.mission is what the mission is set to in BM.mission, if it matches then it shows the string, and any objective that returns a True eval
Example:
objectives[2] = ["Ion Storm Ambush",["BM.turn_count <= 2","Sunrider Incoming...\n"],["BM.turn_count < 5", "Survive for [BM.turn_count]/5 turns"],["BM.turn_count >= 5","Destroy the PACT ambushers"]]
# This updates as the BM.turn_count does, when the Sunrider is here, it removes the objectve, and the survive objective updates as the mission progresses.
Ship Info
Ships now have an info attribute, that lets you add either flavor, advisory or even interactive notes to ships. These are displayed with Buffs/curses and there is a toggle to pick the view. If either .buffs or .info are empty, it will show the other one.
Info can have tooltips, open screens or just be info.
Syntax:
sunrider.info.append(["Display","Tooltip","Screen (optional)"])
Example:
sunrider.info.append(["This is an info line",""])
sunrider.info.append(["This one has a tooltip","This is a tooltip"])
sunrider.info.append(["This has a screen popup","Click it to see","examplescreen"])
If a screen is not wanted, use only two strings
If a tooltip is not wanted, leave it at "" and it will not display
Example:
#In battle
if get_distance(liberty.location,cargo_ship.location) == 1:
cargo_ship.info.append(["Cargo","Click to expand","cargo_hold"])
chi "Captain! I've found something"
#in init
screen cargo_hold:
frame:
vbox:
text "Cargo Hold"
text ""
text "Medical goods"
text "Harmless stuff"
textbutton "Nuclear Warhead":
action confiscate()
text ""
textbutton "close":
action Hide(cargo_hold)
Weapon target validation:
Weapons now have two new attributes, works_on and not_works_on. These are lists that should contain strings, if the ship type is in works/not works then it marks it as a valid/invalid target.
Syntax:
anti_ryder_missile.works_on = ["Ryder"] # ONLY targets Ryders
anti_ship_laser.not_works_on = ["Ryder"] # CANNOT target Ryders but hits everything else not listed
The ship type is the stype attribute on its blueprint and you can always set it to "capture" or similar to make a weapon only able to target that specific ship. Works with all weapon types.
Weapon customization enabled:
Flak
Missile and rockets now have the attribute flak_degradation. This is set at the game default of 0.2 but can now be set higher or lower to cause more or less flak damage. (all weapons have it, but only rockets and missiles use it)
Syntax
exploding_death.flak_degredation = 0.1
flakbreaker.flak_degredation = 0.5
Battlemap weapon image customization
Weapons now can have a custom fire image. Weapons have the custom_fire attribute (default is None) that can be set to an image which they will then use instead of their default. The image should match roughly the existing image so the angles still work. Recolors work fantastically and can be handled by RenPy itself.
Syntax
MegaDeathBossLaser.custom_fire = im.MatrixColor('Battle UI\laserhit map.png',im.matrix.tint(1.6,0.6,0.6)) # This would change MegaDeathBossLaser to a red tint rather than blue, like the legion should have. With a name like that it *needs* something special
Weapon Ammo
All non-support weapons now can be individually set to use ammo. Ammo can be shared between weapons and it can be set to either regenerate at the start of battle, or to be restocked through store.
Ammo is stored on the ship rather than weapons for ease of store restocking. Weapons can be modified to use ammo from in game in active play, not just via editing classes.
Syntax:
# Modified on blueprints
init 2 python: # 2 or later
SunriderLaser.ammo = "NAME" # any string
SunriderLaser.ammo_cost = 1 # any integer
Sunrider.ammo["NAME"] = [10,10,True] # Current Ammo, Max Ammo, Refil on battle start (True/False)
# in game:
sunrider.weapons[0].ammo = "L"
sunrider.weapons[0].ammo_cost = 1
sunrider.ammo["L"] = [10,10,True]
Ammo can be recharged turn by turn or set to a certain number by using turn_action or start_funcs lists, or be done in missions for special ships/weapons.
init 2 python:
Deathstar.ammo["superlaser"] = [1,5,False]
DeathstarLaser_charge():
if deathstar in player_ships:
if deathstar.ammo["superlaser"][0] < deathstar.ammo["superlaser"][1]:
deathstar.ammo["superlaser"][0] += 1
DeathstarLaser_reset():
if deathstar in player_ships:
deathstar.ammo["superlaser"][0] = 1
turn_actions.append(("True",DeathstarLaser_charge)) # Triggers on END of turn
start_funcs.append(("True",DeathstarLaser_reset)) # Triggers on START of battle
# This would give you a charge up weapon for example
This is still a bit buggy. Please give me a word, if this makes problems!Create_Ship improvement
This works with both the improved combat mod and the gunship voices mod.
Ships now have the create_funcs and the ship_load_variables lists.
These run when the ship is created and lets you override variables that otherwise default to original ( like voices ) and runs functions when the ship is created. They are particularly useful when modding mechanics or adding special abilities to ships that could be used on any mission, as they don't need to be scripted into each mission they might take part in.
ship_load_variables is a niche use but create_funcs is particularly useful.
Syntax:
space_whale.create_funcs = ["spacewhale_alert"] # Runs spacewhale_alert function on ship spawn
CeraGunboat.evoice_files = {files}
CeraGunboat.pilot = "Ceragunboat"
CeraGunboat.voice_files = {}
for a in ["evoice_files","pilot","voice_files"
CeraGunboat.ship_load_variables.append(a)
Function to get real angle between two ships:
The angle between two ships can now be determined with the function get_realangle(ship1.location,ship2.location). Ship1 is the center in that calculation. It returns a value in °, not rad.
Resurrection of other ships
Added ships can now be ressurrected without crashing the game, if they are not mercenaries.
How to use:
To make a ship resurrectable:
Example:
#---ship class code --
ship.ryderlist_button = "Filename" #if set to False, attemps to make a button from the template and ship.lbl
ship.can_be_ress = True #must be true to be enable resurrection. Doesn't work on mercenaries.
If no button exists, the ship.lbl is used to create a button with the help of a template included in the Tweakpack folder.
Example:
#---ship class code --
ship.ryderlist_button = "Filename" #if set to False, attemps to make a button from the template and ship.lbl
ship.can_be_ress = True #must be true to be enable resurrection. Doesn't work on mercenaries.
If no button exists, the ship.lbl is used to create a button with the help of a template included in the Tweakpack folder.
Upgrade other ships in RnD
Ships can now be upgraded the same way the base ships can. There is no limit to the amount of ships that can be upgraded. The upgrade screen now has a scrollable list of ships and can be used to attempt to make its own screen. Blanks that can be copied and made are included in the tweakpack.
How to use:
In the ship class, set the attribute can_upgrade to True. When a ship with that is in the player_ships list, it can be improved.
The ship.upgrade_screen attribute defaults to False and can be set to...
False: Displays an upgrade screen with no pilot or ship image
True: Attempts to make an upgrade screen from the pilot portrait and the ship lbl (ship labels will scale so should always fit the screen but non-centered labels and long ships arn't great)
"string" : The filepath to an image you want to use. Blank images for you to copy and use are in the tweakpack folder.
functionname: This is run with no arguments and is used for the sunrider (ava may or may not have an eye patch for example) and can be used to pick the right image out of a few varients .
The ship selection buttons are pulled from icon and hovericon also defined on the ship. There is a blank icon image in the same folder as the tweakpack that can be coppied for use, if the icons are the wrong size, they will overlap so please try to keep them only 64 pixles tall.
Example:
#---ship class code --
self.can_upgrade = True
self.upgrade_screen = True
self.icon = "Filename"
self.hovericon = "Filename"
self.hoverglow(self.icon)
will give you a ship that can be upgraded
The ship.upgrade_screen attribute defaults to False and can be set to...
False: Displays an upgrade screen with no pilot or ship image
True: Attempts to make an upgrade screen from the pilot portrait and the ship lbl (ship labels will scale so should always fit the screen but non-centered labels and long ships arn't great)
"string" : The filepath to an image you want to use. Blank images for you to copy and use are in the tweakpack folder.
functionname: This is run with no arguments and is used for the sunrider (ava may or may not have an eye patch for example) and can be used to pick the right image out of a few varients .
The ship selection buttons are pulled from icon and hovericon also defined on the ship. There is a blank icon image in the same folder as the tweakpack that can be coppied for use, if the icons are the wrong size, they will overlap so please try to keep them only 64 pixles tall.
Example:
#---ship class code --
self.can_upgrade = True
self.upgrade_screen = True
self.icon = "Filename"
self.hovericon = "Filename"
self.hoverglow(self.icon)
will give you a ship that can be upgraded
AutoPlace all ships without Devmode by Neppi
The auto-deploy ships button is available by default without enabling Dev mode and now works with all ships in the player pool
For Modders:
In a battle, if you want to get locations of ships (if your creating ships, and moving them about to design the start) you can now run PrintShips() and Sunrider will make a text file in the base folder called battlepositions which contains all the ship and cover locations on the battle, so it can be copy/pasted into the game easily.
Fixes:
laser_fire, Kinetic_fire, Missile_fire, Support_fire, Melee_fire are all fixed to stop a bug with weapon-activation functions
that was causing functions to fire twice.
End of turn clock was fixed, this caused battle_turn_count to not update correctly and the turn_actions list was never firing.
Upcoming:
-
Known Bugs:
-
Bigfoot's Pipe dream:
Customizable factions with dynamic friend/foe. Halfway there but keep breaking the game... Fight with AI controlled pirates (because why would they listen to you) vs PACT or have a sprawling battle with Pirates fighting each other.
Spoiler is Old Stuff that is now built into the game but might still be useful as reference:
Mod Framework for LD
This is in constant development (like the other one still is) and is aimed at helping mods interact with the game in new ways whilst maintaining compatibility between them. It will try to minimize any difference to the actual game (except in usability and bug-fixes) and should not be noticeable in most cases.
If there is something you would like to see in it, let me know and I will do my best to add it.
To Modders: You are welcome to use any and all code, but PLEASE direct people to download from the live link and if you add code to your mod separately be aware it may cause conflict problems, as this will be frequently patched and keeping an old version in a mod will likely conflict with other mods/newer versions of this.
Backwards compatibility will be maintained as best as able
Installation:
Drop the file into the Sunrider\game folder
Link:
Current Features (5)
Modifiable Choices at start:
Lets you insert extra choices in the new game menu
Choices can now be added in by mods and inserted wherever you want in the choice screen.
You can hide choices at will and declare they must be picked or not, either by variable or more complex functions.
The screen auto-adjusts its size to fit the number of choices
Use:
The Syntax is different for a title block and a choice block. You can use any number of choices but they must share the same variable they change to update correctly. You must define your variable name BEFORE you define your choice blocks.
Title Block:
The 1 tells the game it is a title block
Title and tooltip are obvious
An eval string is a string of conditions that must return eval(string) == True to show the block
It can be as simple as "True" to always show or it can be "previous_choice_variable == True" or even a function
Choice Block:
This is similar to the title block but it starts with a 2 and has an extra field
The extra field tells the block what variable to associate with, the variable name should be a string and the value can be anything.
Inserting into the list:
To actually implement them in the list you need to do:
For each of the blocks.
Validating:
To make an answer compulsory then you can add the variable name into Optionsvars as a string
If one of the variables listed in Optionsvars == None, the confirm button will not show.
If you have a choice that depends on another variable you can add a function to check the validity of the choice into Optionfuncs:
You can hide choices at will and declare they must be picked or not, either by variable or more complex functions.
The screen auto-adjusts its size to fit the number of choices
Use:
The Syntax is different for a title block and a choice block. You can use any number of choices but they must share the same variable they change to update correctly. You must define your variable name BEFORE you define your choice blocks.
Title Block:
[1,"Title","tooltip","eval string"]
The 1 tells the game it is a title block
Title and tooltip are obvious
An eval string is a string of conditions that must return eval(string) == True to show the block
It can be as simple as "True" to always show or it can be "previous_choice_variable == True" or even a function
Choice Block:
[2,"Title", "tooltip, "eval string", ("variablename",Value)]
This is similar to the title block but it starts with a 2 and has an extra field
The extra field tells the block what variable to associate with, the variable name should be a string and the value can be anything.
Inserting into the list:
To actually implement them in the list you need to do:
setoptions.append([ code ])
For each of the blocks.
Validating:
To make an answer compulsory then you can add the variable name into Optionsvars as a string
Optionsvars.append("variablename")
If one of the variables listed in Optionsvars == None, the confirm button will not show.
If you have a choice that depends on another variable you can add a function to check the validity of the choice into Optionfuncs:
init 2 python:
def validate_spire():
global his_pactspire, his_capturetraffickers
Confirm = True
if his_pactspire == False and his_capturetraffickers == None:
Confirm = False
return Confirm
Optionfuncs.append(validate_spire)
This returns True if the combination is valid, and False if it isn't. This works the same way as the Optionsvars but you should put the function in without quotes. If any function returns False, the confirm button will not show.
Inserting Choices:
As the choices are chronologically organized, there is a function that lets you insert a choice wherever you want. To do this, put all your blocks in one list and use the insert_test function like:
Inserting Choices:
As the choices are chronologically organized, there is a function that lets you insert a choice wherever you want. To do this, put all your blocks in one list and use the insert_test function like:
init 2 python:
VariableName = None # define your variable name
insert_test = ([Title],[Choice1],[Choice2])
options_insert(Block Title,insert_test)
This will insert your choices before the Block you called with the title.
Example Code:
Example Code:
Basic Options
(From modified game file)
(From altered game code)
This code is a bit more complex, it uses the same code as the previous, but the eval string in the choices, checks that the same pick hasn't been made in the other 2 selections, it then hides that choice option.
This works better than the original code, and validate_beach_decision is no longer needed but it is a good example of using a function to hide the confirm button if there is a problem. The function returns false if any choices have been made twice.
(From modified game file)
init 2 python
setoptions.append([1,"Flag","After the fall of Cera, which flag did you suggest flying?","True"])
setoptions.append([2,"Cera","You told Ava the Sunrider would always fly Cera's flag.","True",("his_ceraflag",True)])
setoptions.append([2,"Pirate","You told Ava being a pirate ship wouldn't be bad.","True",("his_ceraflag",False)])
Optionsvars.append("his_ceraflag")
Here, the first block is the title, hence the 1 at the start. The showing text is Flag and the Tooltip is "After the fall of Cera, which flag did you suggest flying?". Because it has an eval string of "True" it always shows.
The second and third blocks are choice blocks that both modify his_ceraflag setting it to either True or False. They are again both visible because of "True"
Because the variable is put in Optionsvars then you cannot confirm without picking a choice
To make the choice only appear if another option has been chosen, like if you saved pirates, the Eval strings should be "Variable == x" where x is the defined choice.
Possible Options code:
The second and third blocks are choice blocks that both modify his_ceraflag setting it to either True or False. They are again both visible because of "True"
Because the variable is put in Optionsvars then you cannot confirm without picking a choice
To make the choice only appear if another option has been chosen, like if you saved pirates, the Eval strings should be "Variable == x" where x is the defined choice.
Possible Options code:
init 2 python:
setoptions.append([1,"Beach Time 1","Who did you talk with at the beach?","True"])
setoptions.append([2,"Asaga","","his_beach2 != 1 and his_beach3 != 1",("his_beach1",1)])
setoptions.append([2,"Chigara","","his_beach2 != 2 and his_beach3 != 2",("his_beach1",2)])
setoptions.append([2,"Ava","","his_beach2 != 3 and his_beach3 != 3",("his_beach1",3)])
setoptions.append([2,"Icari and Kryska","","his_beach2!= 4 and his_beach3!= 4",("his_beach1",4)])
setoptions.append([2,"Claude","","his_beach2 != 5 and his_beach3 != 5",("his_beach1",5)])
setoptions.append([2,"Sola","","his_beach2 != 6 and his_beach3 != 6",("his_beach1",6)])
def validate_beach_decision():
if his_beach1 == his_beach2 or his_beach1 == his_beach3 or his_beach2 == his_beach3:
return False
return True
Optionsfuncs.append(validate_beach_decision)
This works better than the original code, and validate_beach_decision is no longer needed but it is a good example of using a function to hide the confirm button if there is a problem. The function returns false if any choices have been made twice.
Insert Choice Example:
init 2 python:
beardtest = None
insert_test = ([1, "Do you like beards?","The Answer is always YES","True"],[2, "Yes", "Yes", "True", ("beardtest",True)],[2, "No", "Liar", "True", ("beardtest",True)])
options_insert("Ava's sacrifice",insert_test)
This code inserts a Title and 2choice set into the choice list.
It appears above Ava's Sacrifice because the options_insert looks for a matching string in title blocks and when it finds it, puts it one slot ahead.
This means it is easy to slot a choice into the list wherever you want.
Multiple effects from choices:
Whilst it is easy to set single variables, if you want to set multiple variables (if a choice made multiple people happy for example) you can add a label to stat_labels. This label is called and can be used to interprate the choices.
Would cause Labelname to be jumped to after the initial choices have been set. This should be an invisible label (that just sets variables)
This label will happen silently and can be used to get more use out of the choice menu.
It appears above Ava's Sacrifice because the options_insert looks for a matching string in title blocks and when it finds it, puts it one slot ahead.
This means it is easy to slot a choice into the list wherever you want.
Multiple effects from choices:
Whilst it is easy to set single variables, if you want to set multiple variables (if a choice made multiple people happy for example) you can add a label to stat_labels. This label is called and can be used to interprate the choices.
stat_labels.append("Labelname")
Would cause Labelname to be jumped to after the initial choices have been set. This should be an invisible label (that just sets variables)
label Labelname:
python:
if asagamission == True:
affection_asaga += 3
affection_chigara += 1
captain_moralist += 1
if asagamission == False:
affection_ava += 1
affection_icari += 2
captain_prince += 1
return
Dynamic buttons in Ship Map:
Allows for easy and unobtrusive mod insertion into the storyline
Buttons can now be added to the ship map by mods. This works very similarly to MoA framework's buttons but uses a different list and has extra features:
You can use buttons to go either to a label (like regular character buttons) or you can now set buttons to trigger functions (like research and the store)
Button graphics can change dynamically according to variables (for example Ava's eye patch only appears if legion_destroyed == True)
You can add your own buttons using custom images and they will display in any of the ship locations you pick.
Name and location codes:
Use:
Basic:
To display a button with a label jump, you add a list to talk_buttons.
The eval string tells the game if it should display the button. If it returns True then it is displayed. This CAN overwrite story defined labels so unless there is good reason, you should always include Btest("name code") in the eval string. This returns False if that character's location is not None and prevents the button being activated.
If all eval conditions are True, then the named button will show up at the location and clicking it will jump you to the named label.
The talk_buttons should only be added to in init, because this means if the mod is removed, talk_buttons will not remember the new button.
In the label you jump to, you MUST set "namecode"_location = None and "namecode"_event = None or it will still show on the ship map when you return.
Example:
This will make asaga appear in the lab if seen_mod_label is False. When she is clicked, you jump to the mod_asagaquest label and her _location and _event variables are reset.
Event Button:
An event button calls a function or triggers an effect, rather than jumping to a label. The syntax is broadly the same, but you don't set the event.
The event is fixed with the button and to create a new event, you need to make a new button, which will be covered in a moment.
To display the event button you do:
The hoveredimage is a transform whilst the image is the file in sunrider/game/UI (which is actually hidden inside an archive)
Dynamic: Ava, Change sprite if Legion is destroyed
You can use buttons to go either to a label (like regular character buttons) or you can now set buttons to trigger functions (like research and the store)
Button graphics can change dynamically according to variables (for example Ava's eye patch only appears if legion_destroyed == True)
You can add your own buttons using custom images and they will display in any of the ship locations you pick.
Name and location codes:
The name code can be:
"ava" for Ava
"asa" for Asaga
"chi" for Chigara
"ica" for Icari
"cla" for Claude
"sol" for Sola
"kry" for Kryska
"pro" for Progress
"gal" for Galaxy Map
The location code can be:
"captainsloft"
"hallway"
"sickbay"
"messhall"
"bridge"
"engineering"
"lab"
"hangar"
"ava" for Ava
"asa" for Asaga
"chi" for Chigara
"ica" for Icari
"cla" for Claude
"sol" for Sola
"kry" for Kryska
"pro" for Progress
"gal" for Galaxy Map
The location code can be:
"captainsloft"
"hallway"
"sickbay"
"messhall"
"bridge"
"engineering"
"lab"
"hangar"
Use:
Basic:
To display a button with a label jump, you add a list to talk_buttons.
talk_buttons.append(["eval string", "name code", "location", "label name"])
If all eval conditions are True, then the named button will show up at the location and clicking it will jump you to the named label.
The talk_buttons should only be added to in init, because this means if the mod is removed, talk_buttons will not remember the new button.
In the label you jump to, you MUST set "namecode"_location = None and "namecode"_event = None or it will still show on the ship map when you return.
Example:
init 2 python:
talk_buttons.append([("Btest("asa") and seen_mod_label == False", "asa", "lab", "mod_asagaquest"])
label mod_asagaquest:
$ asa_location == None
$ asa_event == None
asa "This is an awesome quest."
jump Wherever
This will make asaga appear in the lab if seen_mod_label is False. When she is clicked, you jump to the mod_asagaquest label and her _location and _event variables are reset.
Event Button:
An event button calls a function or triggers an effect, rather than jumping to a label. The syntax is broadly the same, but you don't set the event.
The event is fixed with the button and to create a new event, you need to make a new button, which will be covered in a moment.
To display the event button you do:
event_buttons.append(["eval string", "name", "location"]]
The Eval string and the location is the same as previously.
Name is one you define when you make the button, or it can be "res" for research and "cal" for store to move them to your location.
Alternatively:
Both these new buttons work by setting "namecode"_location and "namecode"_event to make the button appear and know what to do with it. You can always manually do it, in a label by asa_location = "bridge" if you know you want it immediately after a certain scene, the lists just place it automatically when you tell them to.
Creating a new Button:
It is now possible to make your own button to display on the ship map, by defining it in a new list. After it's been defined then it will show up at the location you want. PLEASE only define it in an init block as otherwise if a mod is removed it will cause errors.
To make your button, you need to add a list to buttonlist or eventlist
Name is one you define when you make the button, or it can be "res" for research and "cal" for store to move them to your location.
Alternatively:
Both these new buttons work by setting "namecode"_location and "namecode"_event to make the button appear and know what to do with it. You can always manually do it, in a label by asa_location = "bridge" if you know you want it immediately after a certain scene, the lists just place it automatically when you tell them to.
Creating a new Button:
It is now possible to make your own button to display on the ship map, by defining it in a new list. After it's been defined then it will show up at the location you want. PLEASE only define it in an init block as otherwise if a mod is removed it will cause errors.
To make your button, you need to add a list to buttonlist or eventlist
# Talk Button:
buttonlist.append(["name code","unhovered image", "hovered image"])
# Event button:
eventlist.append(["name code", "unovered image", "hovered image", function])
The name code is identical to seen previously, it is what the map looks for when trying to display a button. If it thinks it should display it, then it places the unhovered image button which transforms when it is moused over.
For event buttons, the function is triggered when it is clicked rather than the label jump. The function can have no non-default arguments.
If you want to make a button change its displayed image dynamically, then instead of a string containing the file name, you should put a function. It will automatically be run and the result will be used.
To make the image glow when moused over, the hovered image should be tr_hoverglow(hoverimage). Other transforms will also be shown if entered.
Example useing pre-defined buttons:
Basic: Asaga
For event buttons, the function is triggered when it is clicked rather than the label jump. The function can have no non-default arguments.
If you want to make a button change its displayed image dynamically, then instead of a string containing the file name, you should put a function. It will automatically be run and the result will be used.
To make the image glow when moused over, the hovered image should be tr_hoverglow(hoverimage). Other transforms will also be shown if entered.
Example useing pre-defined buttons:
Basic: Asaga
init 2 python:
buttonlist.append(["asa","UI/asa_button.png",tr_hoverglow("UI/asa_button.png")])
Dynamic: Ava, Change sprite if Legion is destroyed
init 2 python:
def ava_img():
if legion_destroyed:
return "UI/ava_button_eyepatch.png"
return "UI/ava_button.png"
def ava_img2():
if legion_destroyed:
return tr_hoverglow("UI/ava_button_eyepatch.png")
return tr_hoverglow("UI/ava_button.png")
buttonlist.append(["ava",ava_img,ava_img2])
The functions return the string of the image file, depending on if the legion is destroyed. Because they are functions they are automatically triggered and the button shows the correct sprite.
Reactive galaxy map:
Planets no longer need their own mission select label, and can have missions added to the planets themselves (so existing planets are usable). Up to 4 missions are displayable at the same time.
Planets with available missions show red on the galaxy map, but you can also define the image you want for a high-priority or time-sensitive mission.
Planets now create their own variable so they are easily referenced.
Use:
Planets now have three additional attributes, background, info and missions
Planets are still created by:
and they can still be used in MoA style mission select which means makeing a new label for it, and makeing it harder to use existing planets in mods.
To use mod-freindly planets, they are defined the same way with a few extra steps:
When you create the planet, use "Dynamic_mission" as the jumpLocation.
After the planet is created, it sets itself to a variable that lets you track and modify it easily. The variable is the planet Name with spaces replaced with underscores.
Now you need to do:
Planetvariable.background = "image"
Planetvariable.info = "image" (or False, if you don't want an infocard)
Now when you click the planet in the galaxy map. you will be shown a screen where you can pick and choose from missions. There is a maximum of 4 missions shown at one time.
Missions:
These are easy to add.
Planetvariable.missions.append( [ "Eval String", "Name", "Jump label"] )
If the Eval string is matched, it shows a button with the name of the mission. When the button is clicked, then you jump to the chosen label.
Example:
Planets now have three additional attributes, background, info and missions
Planets are still created by:
Planet("planetname", "jumpLocation", xpos, ypos, "eval string")
and they can still be used in MoA style mission select which means makeing a new label for it, and makeing it harder to use existing planets in mods.
To use mod-freindly planets, they are defined the same way with a few extra steps:
When you create the planet, use "Dynamic_mission" as the jumpLocation.
After the planet is created, it sets itself to a variable that lets you track and modify it easily. The variable is the planet Name with spaces replaced with underscores.
Now you need to do:
Planetvariable.background = "image"
Planetvariable.info = "image" (or False, if you don't want an infocard)
Now when you click the planet in the galaxy map. you will be shown a screen where you can pick and choose from missions. There is a maximum of 4 missions shown at one time.
Missions:
These are easy to add.
Planetvariable.missions.append( [ "Eval String", "Name", "Jump label"] )
If the Eval string is matched, it shows a button with the name of the mission. When the button is clicked, then you jump to the chosen label.
Example:
PACEMUS_NEBULA.background
PACEMUS_NEBULA.info
PACEMUS_NEBULA.jumpLocation
This sets a planet to use the automatic label that can be used for mission selection.
PACEMUS_NEBULA.missions.append(["mission4_complete == False","Side: Investigate nebula","pacemusnebula"])
This is how a mission is formatted (mission already exists in game)
So long as "mission4_complete == False" it will show up red in the galaxy map, telling you it's active
"Side: Investigate Nebula" will be shown on the mission label
pacemusnebula is where the game jumps to if it's clicked.
If you want to make the galaxy map icon change when the mission is active, add an additional section onto the mission list. If there is a 4th entry then it is treated as a function calling the planet.
This function should change gal_icon1 and gal_icon2 to the wanted icon.
So long as "mission4_complete == False" it will show up red in the galaxy map, telling you it's active
"Side: Investigate Nebula" will be shown on the mission label
pacemusnebula is where the game jumps to if it's clicked.
If you want to make the galaxy map icon change when the mission is active, add an additional section onto the mission list. If there is a 4th entry then it is treated as a function calling the planet.
This function should change gal_icon1 and gal_icon2 to the wanted icon.
def makeglow(planet):
gal_icon1 = tr_hoverglow("Map/map_icon_base_highlight.png")
gal_icon2 = tr_hoverglow("Map/map_icon_hover_highlight.png")
return
For example, to make Pacemus Nebula glow with that mission you would do:
PACEMUS_NEBULA.missions.append(["mission4_complete == False", "Side: Investigate nebula", "pacemuanblula", makeglow]
Interactive Function Points:
This part lets you run functions on actions, like moving, firing weapons, ship destruction, battle start, every turn in battle and button interrupts.
Move Functions:
Weapon Functions:
Destruction Functions:
Battle Interrupts:
Turn Actions:
Battle Start Functions:
These functions are added to ship.move_funcs
The Syntax is:
The positional can be 1 or 2, If it's 1, then it triggers before counter attacks, if it's 2, it triggers after counter attacks. The function takes Ship as the argument.
Example:
This triggers after the ship has moved and sets new_ship_location to the ship location.
The Syntax is:
ship.move_funcs.append([positional, function])
The positional can be 1 or 2, If it's 1, then it triggers before counter attacks, if it's 2, it triggers after counter attacks. The function takes Ship as the argument.
Example:
def movefunction(ship, location, new_location):
globals new_ship_location
new_ship_location = new_location
return
sunrider.move_funcs.append([2,movefunction])
Weapon Functions:
Weapon functions can be put either into weapon.weapon_funcs or ship.weapon_funcs. If they are put in ship, they trigger on every weapon that is fired by that ship, when set in weapon, it only triggers on that weapon.
For all weapon types but support and gravity, functions use the following positional:
If the positional == 0, then it should return an integer which is added to accuracy
if it == 1, then it triggers on hitting the enemy
if it == 2, then it should return an integer which is added to damage
for support, a positional of 2 adds to healing, a positional of 1 always triggers.
The functions should take three arguments (total_damage, hit_count, damage_id)
Example:
Useful variables:
BM.attacker (the ship that initiated the attack)
BM.target (the ship that was attacked)
The damageid is used in checking if the attack caused ship destruction, explained below.
For all weapon types but support and gravity, functions use the following positional:
If the positional == 0, then it should return an integer which is added to accuracy
if it == 1, then it triggers on hitting the enemy
if it == 2, then it should return an integer which is added to damage
for support, a positional of 2 adds to healing, a positional of 1 always triggers.
The functions should take three arguments (total_damage, hit_count, damage_id)
Example:
def inc_damage(damage, hitcount, damageid):
return damage*0.1
def disintergrate_ship(damage, hitcount, damageid):
if BM.target.hp <= BM.target.max_hp/2:
BM.target.hp = 0
return
superkinetic.weapon_funcs.append([2,inc_damage])
superkinetic.weapon_funcs.append([1,disintergrate_ship])
or
PactSuperSniper.weapon_funcs.append([2,inc_damage])
PactSuperSniper.weapon_funcs.append([1,disintergrate_ship])
BM.attacker (the ship that initiated the attack)
BM.target (the ship that was attacked)
The damageid is used in checking if the attack caused ship destruction, explained below.
Destruction Functions:
Death functions can trigger either in every case, or if a specific attack destroys them.
Death functions can be triggered either constantly or specifcally when a certain weapon destroys a ship.
The syntax is:
ship.death_funcs.append([conditional,function])
where conditional is either "True" (when it should trigger on every destruction)
or if applied by a weapon (from inside a weapon function) to trigger only on death:
Death functions can be triggered either constantly or specifcally when a certain weapon destroys a ship.
The syntax is:
ship.death_funcs.append([conditional,function])
where conditional is either "True" (when it should trigger on every destruction)
or if applied by a weapon (from inside a weapon function) to trigger only on death:
def add_function(damage, hits, damageid)
BM.target.death_funcs.append([damageid,function])
return
This would trigger only if the damageid of the attack matches the last id of the attack that hit the ship (the destroying shot)
Example:
This would trigger only if the damageid of the attack matches the last id of the attack that hit the ship (the destroying shot)
Example:
def reduce_shields(ship)
PACTBoss.shield_generation -= 20
return
shield_generator.death_funcs.append(["True",reduce_shields])
This would reduce the PACTBoss ship's shield generation by 20 when the shield_generator is destroyed.
Battle Interrupts:
Functions can be added to battle_interupt to be automatically and instantly run on the player turn of a battle. This is useful for triggering functions in response to a click, that use the UI, such as warping a ship or laying mines. The other way to do this is to write a battle dispatcher. It makes a "bubble" that is executed before asking the UI for the player's next action.
Example:
Example:
battle_interupts.append(function)
Turn Actions:
Turn actions are checked and run once a turn, as soon as the player gets control. To add functions, put them in the turn_actions list, with a syntax of ("eval string",function)
As long as they pass the eval check, the function will trigger.
Example:
As long as they pass the eval check, the function will trigger.
Example:
turn_actions.append(("sunrider.hp <= (sunrider.max_hp/5)", Emergency_function))
Would trigger every turn the sunrider's hp is below 20%Battle Start Functions:
These functions trigger when battles start, useful to reset values for global mods.
Example:
Example:
start_funcs.append(["True",ResetDirectionVars])
If the first value evals to True, the function triggers.
Improved Choice Menu
Because the standard menu: syntax of renpy dosen't work in LibDay, choices need to be handled with screens. There is a new menu screen available which lets you pick from 6 options and adjusts its spaceing to make it convenient.
Important: At the moment, the screen is called decison, when the framework and base code are merged, it will be called decision and replace the current choice menu.
Syntax:
Rather than setting two variables for each choice, there is now only one, a list containing lists or tupples of choice, jump_location. Lists can be split over more than one line for readability.
Important: At the moment, the screen is called decison, when the framework and base code are merged, it will be called decision and replace the current choice menu.
Syntax:
Rather than setting two variables for each choice, there is now only one, a list containing lists or tupples of choice, jump_location. Lists can be split over more than one line for readability.
After the list has been defined you show the screen and pause. When the player clicks a choice, they are jumped to that label.
label ice_cream:
cla "What ice cream do you want?"
$ menu_choices = [
["Strawberry","chosestrawberry"],
["Blueberry","choseblueberry"],
["Lemon","choselemon"],
["Cherry","chosecherry"],
]
show screen decision2
pause
label chosestrawberry:
cla "aww, That was the last of it..."
After the list has been defined you show the screen and pause. When the player clicks a choice, they are jumped to that label.
Resources:
These are minor but useful things that the modframework includes:
MHL: A list containing all hexes in the battlefield.
Storeships: A list of all ship classes (includeing modded ones)
Storeweps: A list of all weapon classes (includeing modded ones)
Coreships: a list of classes of the main player ships (usefull to strip away mercenaries and such)
MHL: A list containing all hexes in the battlefield.
Storeships: A list of all ship classes (includeing modded ones)
Storeweps: A list of all weapon classes (includeing modded ones)
Coreships: a list of classes of the main player ships (usefull to strip away mercenaries and such)
If you have any requests then please post them and I will see what I can do.
If there are any problems with the code, then please let me know and I will do my best to fix it.
If there are any problems with the code, then please let me know and I will do my best to fix it.