Author Topic: [7.2] Mod Framework/Tools  (Read 4427 times)

Offline The Bigfoot

[7.2] Mod Framework/Tools
« on: December 14, 2015, 11:10:23 am »
Mod Framework RPY
For Modders

This is a file intended as an enabler for mods and adds new ways to interact with the game and new functionality whilst maintaining compatibility. It is in a constant state of development but backwards compatibility should be total unless a large bug needs to be patched out.

Anyone is free to use it as they want, but please link either to the googledrive link or here so the most updated version is always available so mods do not need to be constantly updated as it changes.



Features
Function Points
These are points you can script across the entire game. These are triggered at certain events and can combo fantastically. You could do some of these things in battles you code specially, but this lets you do much more, and widens their scope across the entire game.

Weapon Functions
Use:

Allows functions to trigger on weapon fire, These can be set to trigger on hit, miss, either and can modify damage and accuracy. This lets you modify damage and accuracy or add extra effects like modifiers, cumulative damage or pretty much anything you can imagine.

If you wanted to make it only trigger on a certain ship's name you can put a function to check target.name and if it's not a valid target you can set accuracy to 0 to make it auto-miss, or do something completely different.

When the functions are put in weapon.functions they trigger only for that weapon, but if put in ship.weapon_functions they trigger for every weapon that ship uses.

Example Code:

Example
Code: [Select]
# Weapon functions are a tuple of (check,function)
# check values are: 0 - Miss only, 1 - Hit only, 2 - Hit or miss, 3 - Modify damage, 4 - Modify accuracy
# With 3 and 4, the output is an integer that INCREASES the final amount by that much

# A functions arguments must be:
# (weapon, user, target, total_damage, hit_count, accuracy, damageid)

# It is best to attach a function to the weapon or ship base class and use a variable to turn the function on, otherwise it can get removed/overwritten easily.

# Make Liberty laser a targeting laser:
init 20 python:
    def Targetlaser(weapon, user, target, total_damage, hit_count, accuracy, damageid):
        if targetenabled == True:
            if target.modifiers['evasion'][0] > -20:
                target.modifiers['evasion'] = [-20,1]
        return

# Attach Targetlaser to LibertyLaser and tell it to trigger when it hits the target   
    LibertyLaser.functions.append(1,Targetlaser)


#Make the Paladin have increased damage when it attacks an enemy ship if its next to one of the Sunrider's crew. (Code from simplified Shambler hunting reward)

#adjacent_to_core is covered later in this post

    def loyaltydmg(weapon, user, target, total_damage, hit_count, accuracy, damageid):
        return_variable = 0       
        if kry_gift:
            if paladin.adjacent_to_core():
                damage = total_damage*0.1

        return return_variable # If the function just passes, it adds 0 to the damage, otherwise 10% of initial damage

    Paladin.weapon_funcs.append((3,loyaltydmg))

    # You could also set an effect to trigger on target death by something like this:
    def function(stuff):
        target.deathfuncs.append((0 or damageid, function))
        return

Multi-turn effects
This is code from the Shambler Hunting mod, used to work the secret weapon. It triggers a function on hit and sets a flag on the target. We then use gated_player_actions to check ships for that flag on the start of the player turn. If its found, it runs the function to set a new effect and check for shambler survival.

Code: [Select]
init 20 python:

# Function to fire with the weapon, it calls another function

    def inflictshamblers(self, parent, target, damage, hits, accuracy, damageid):
        # First do a ship-check
        if target.stype == "Ryder": # Doesn't attach Rampage, just disables
            if target.name != "Nightmare": # doesn't work on 'Boss' ships
                target.en = 10
                target.max_en = 10
                if target.hp >= 1:
                    target.modifiers['Ryder Disabled'] = [100,0]
                    target.hp -= 200
                    if target.hp < 1:
                        target.destroy(sunrider)
                return # If its a Ryder target, it just wrecks it and returns out.
       
            target.modifiers["Rampaging Shambler"] = [5,0] # Use this as a flag for S_
            shamblereffect(target)
            return

    # shamblereffect(target) triggers a random effect on the target shot at

    Shamblerocket.functions.append((1,inflictshamblers))

    # This is put in gated_player_actions to run at the start of each turn. It checks for the

    def S_debuf_handler(target = False, Effect = False):
        for ship in BM.ships:
            if "Rampaging Shambler" in ship.modifiers:
                if ship.modifiers['Rampaging Shambler'][0] != 0:
                    check = ship.modifiers["Rampaging Shambler"]
                    check[0] += 10
                    if renpy.random.random()*100 <= check[0]:
                        ship.modifiers.pop("Rampaging Shambler",None)# = [0, 0]
                        show_message("The Shambler on a "+ ship.name +" has been caught")
                    shamblereffect(ship)
        return

    init_gated_player_actions.append(S_debuf_handler)


You can do something similar to trigger constant effects every turn, damage or otherwise as well as more normal things like making a weapon be more accurate or do more each time it's shot at a target in one turn.


Functions trigger on movement
Use:

This lets you trigger functions when moving, for example switching ship directions or detecting if you are next to an enemy or ally (this is done automatically). The function can be triggered before moveing, before counter attacks and after counterattacks determined by its check value.

Ideas are dealing damage if moving through a certain location on the map, or moving past enemy ships.

This can be used for Auras as the trigger on moving portion.

The Check is 0 = before move, 1 = before counter step, 2 is after counter step
The arguments must be: (ship, new_location, total_move_cost)

Example Code:
Display text when moved next to a core ship
Code: [Select]

# From Shambler mod, again a cut down part of Kryska's bonus
init 20 python:
    Ptext = "10% Teamwork bonus active."
    def loyalty_show(ship,new_location,total_move_cost):
        if adjacent_to_core(paladin):
            if not Ptext in paladin.mod:
                paladin.mod.append(Ptext)
        else:
            if Ptext in paladin.mod:
                paladin.mod.remove(Ptext)
    return

    Paladin.move_funcs.append((2,loyalty_show))
Aura code
This was used for the destroyer aura for Drath's Dreadnought, it is put in every ship's move functions and checks which mode to use when the ship moves. If its a Dreadnought then it applies it to other ships in the new location, if its not then it checks if it moves into the aura and if so, applies it.

Can also be applied to Covers.

MHL is a list of all hexes, generated by the framework.

Code: [Select]
init 20 python:
    def dread_aura_move(ship,new_location,total_move_cost):
        effect_triggered = False
        # This is split into two parts, if it is a Dreadnought then it applys/removes when it moves.
        # Else it checks where it moves for the aura and takes its effects
        # If the ship has moved out of range of the aura, it looses the disintegrate tag
        # Get aura hexes, aurahexes2 has all disintegration hexes, aurahexes is only a specific ship
       
        aurahexes2 = []
        for item in BM.ships:
            if item.name == "Dreadnought":
                for hex in MHL:
                    if get_distance(hex,new_location) <= item.aura_size: aurahexes2.append(hex)
        # The aura_size is an ship attribute unique to auras, automatically added in the framework

        if ship.name == "Dreadnought":
            aurahexes = []
            for hex in MHL:
                if get_distance(hex,new_location) <= ship.aura_size: aurahexes.append(hex)
                   
            # check all ships to see if they are in the disintegration aura, this ignores other Dreadnoughts
            # If in aura: if it has no tag, give it one set to false.
            # If tag == False, do 250 dmg and set to True
            for prey in BM.ships[:]:
                if prey.location in aurahexes:
                    if prey.name != "Dreadnought":
                        if not hasattr(prey, "Disintegrate"):
                            prey.Disintegrate = False
                        if prey.Disintegrate == False:
                            effect_triggered = True
                            prey.Disintegrate = True
                            prey.hp -= 250
                            if prey.hp < 1:
                                prey.destroy(prey)
                               
                # if outside aura, check to see if its in any other disintegrate auras.
                # If not, set tag to False
                # Uncomment this to allow repeated aura dmg when moving in-out often

                #if prey.location not in aurahexes:
                    #if prey.location not in aurahexes2:
                        #prey.Disintegrate = False

            if effect_triggered == True:
                show_message("The Dreadnought's Disintegration aura has damaged ships.")

        # If moveing ship is NOT a dreadnought
        else:
            #if new_location not in aurahexes2: # Uncomment this to allow repeated effect
            #    ship.Disintegrate = False
            if new_location in aurahexes2:
                if not hasattr(ship, "Disintegrate"):
                    ship.Disintegrate = False
                if ship.Disintegrate == False:
                    ship.Disintegrate = True
                    ship.hp -= 250
                    if ship.hp < 1: ship.destroy(ship)
        return

    # storeships is generated at init 15 and is how ship attributes can be added without modifying Battleship

    for ship in storeships:
        ship.move_funcs.append((1,dread_aura_move))
   


Death Triggers
Use:

This lets you assign functions to trigger on a ship's death.

You can either add them to the ship classes or on the ship directly, you can even use weapon functions to attach them.

You can use this to trigger shrapnel explosions, disable other ships, spawn wreckage and numerous other effects

The syntax is (check,function), if check is 0, it always fires. If its anything else then it checks the damageid of the last attack and if its the killing blow, it triggers.

It's arguments must be (self,attacker)

Example Code:
Wreckage code from Salvage Mod
Code: [Select]

This function makes a cover, and then takes information from its trigger ship to set certain attributes. Using storeships, you can set the function to every ship class including mod defined ships.

init 10 python:
    # cover_make makes the cover, sets its timer, label and some other stats used later
    def covermake(ship, attacker):
        #Ryders get obliterated, skip them
        if ship.stype == "Ryder":
            return

        # The cover attributes are pulled from ship, the destroyed ship
        create_cover(ship.location)
        c = BM.covers[-1]
        c.hp = int(ship.max_hp*(float(renpy.random.random()))) # Less than starting hp
        c.destroy = coverdestroy # New death code
        c.source = ship.stype
        c.timer = store.wreckstats[ship.stype][0]
        c.explode = store.wreckstats[ship.stype][1]
        c.cover_chance = store.wreckstats[ship.stype][2]
        c.faction = ship.faction
       
        # Apply a colourshifted image for the battle map, the labels are shifted by the timeing function
           
        if c.faction == 'PACT': # Use red tinted cover
            c.label = wreckimg[3]
            c.Degrade = wreckimg[4]
            c.Degrade2 = wreckimg[5]
           
        elif c.faction == 'Pirate': # Use green tinted cover
            c.label = wreckimg[6]
            c.Degrade = wreckimg[7]
            c.Degrade2 = wreckimg[8]
           
        else: # Use alliance tinted cover
            c.label = wreckimg[0]
            c.Degrade = wreckimg[1]
            c.Degrade2 = wreckimg[2]
       
    # Add this function to all ship's deathfunc list
init 16 python:
    for ship in storeships:
        ship.deathfuncs.append((0,covermake))
Assigning on death triggers
If you want a weapon to hit the target and cause an effect on death you can assign it by useing a weapon func to trigger on hit (check 1 or 2)  and getting it to assign the function.

If you want the function to trigger only on the kill-blow, you can use it to overwrite other functions, for example if you disintegrate the ship so it doesn't leave wreckage by setting ship.deathfuncs = []

Code: [Select]
init python:
    def expload(self, attacker):
        for ship in BM.ships:
            if get_distance(ship.location,self.location) < 3:
                ship.hp -= 200
                if ship.hp < 1:
                    ship.destroy(self)
        return
       
#This will assign the expload function to trigger on ship death

    def applyfunc(self, parent, target, dmg, hit_count, accuracy, damageid):
        if not (0,deathmessage) in target.deathfuncs:
            target.deathfuncs.append((0, expload))
        return

#This one triggers if the LAST attack on the ship is the one that kills it. damageid is passed by weapon functions.

    def applyfunc(self, parent, target, dmg, hit_count, accuracy, damageid):
        target.deathfuncs.append((damageid, expload))

Battle Start functions
Use:

This is a list run at the start of a battle, includeing if you need to restart a battle.

Syntax: (check, function)
The tuple should be put in the init_start_funcs list,  this stops functions being lost.  The check can either be the same as the mission or can be "Any".

If it matches BM.mission then the function is fired.

Example Code:
Function run on every mission
This code is taken from the Phoenix restoration mod and run at every battle to reset it.
Code: [Select]
init python:
    def setphoenix():
        global player_ships, upgrade_ships, phoenix, Attached, Boosterdead

        #if not dead at start of mission, set up booster for attached
        if booster in player_ships: # if not dead, attach phoenix to booster. set vars in case.
            if phoenix2 in player_ships: player_ships.remove(phoenix2)
            if phoenix2 in BM.ships: BM.ships.remove(phoenix2)
            if not phoenix2 in upgrade_ships: upgrade_ships.append(phoenix2)
            if not booster in player_ships: player_ships.append(booster)
            if not booster in BM.ships: BM.ships.append(booster)
            if booster in upgrade_ships: upgrade_ships.remove(booster)
            if not booster.mercenary: booster.mercenary = True
            for item in booster.weapons[:]:
                item.energy_use = item.energy_use2
            store.phoenix = booster
            store.Attached = True
            for item in booster.weapons:
                item.energy_use = item.energy_use2
            booster.move_cost = 15
            if phoenix2.location != None: set_cell_available(phoenix2.location)
            BM.unselect_ship(phoenix2)
            booster.lbl = im.Flip('Battle UI/label_phoenixboaster.png', horizontal=True)
        return

    init_start_funcs.append(("Any",setphoenix))

The important thing is to use a variable to see if the function should trigger, in this example its looking for booster in player ships.
This is because the function will be active in EVERY mission if the check is "Any", even if a needed variable hasn't been set.

Win/Loose functions
Use:
These functions are triggered either on winning or looseing a battle (shock)

Similar to start_funcs, the check is "Any" or matches BM.mission.
The tuple should go in init_win_funcs or init_loss_funcs.

These functions will run and then unless instructed otherwise, the battle will continue to the victory screen. The functions can be used to jump outside the battle flow and direct you to an alternate point in the story with renpy.jump but make sure to clean the battle fully. Have a look at battle_end in classes.rpy

This is of limited use as the code could normally be done by just modifying the after_mission label. There are some times it could be useful though, such as cutting out or redirecting the normal victory screen.

Example Code:
Run on win
this is untested code as an example

Code: [Select]
init python:
    def getsurvivors():
        # Battle cleaning code
        T = get_shipcount_in_list('Merchant Ship', player ships)
        if T > 5:
            renpy.jump('Mission_500_sucsess')

        if T < 3:
            renpy.jump('Mission_500_poor')

        renpy.jump('Mission_500_ok')
        return

    init_win_funcs.append((43,getsurvivors))

Gated player actions
Lets you run actions on every player turn on any battle. This lets you make mods that span the entire game and trigger as time progresses.

Use:
You can use this for slow-acting effects such as weapon functions or time based effects like deteriorating wreckage. It can be run on specific missions or on every mission.

The function should be added to init_gated_player_actions

Example Code:
Wreckage deterioration
Code taken from the Salvage mod, it checks all covers for a timer. If the timer exists then it is reduced and if the timer is reduced to 0, it is destroyed. if the timer reaches a certain value it changes its lbl.

Code: [Select]
init python:
    def coverclock():
        if BM.covers != []:
            for c in BM.covers[:]:
                if hasattr(c, 'timer'):
                    c.timer -= 1
                    if c.timer == 2: c.label = c.Degrade
                    if c.timer == 1: c.label = c.Degrade2
                    if c.timer == 0: c.destroy(c)
        return

    init_gated_player_actions.append(coverclock)
Timed weapon handler
This is used in the Shamble mission's secret weapon. It checks all ships in BM.ships for a modifier that's set, then runs a function to apply an effect to any afflicted ships.

Code: [Select]
init python:
    def S_debuf_handler(target = False, Effect = False):
        for ship in BM.ships:
            if "Rampaging Shambler" in ship.modifiers:
                if ship.modifiers['Rampaging Shambler'][0] != 0:
                    check = ship.modifiers["Rampaging Shambler"]
                    check[0] += 10
                    if renpy.random.random()*100 <= check[0]:
                        ship.modifiers.pop("Rampaging Shambler",None)# = [0, 0]
                        show_message("The Shambler on a "+ ship.name +" has been caught")
                    shamblereffect(ship)
        return
    init_gated_player_actions.append(S_debuf_handler)
This is run at the start of every turn so you get a turn-by-turn debuff until the shambler is caught.

Enemy actions
This is the counterpart to gated_player_actions, its run before the enemy moves and can be used to trigger functions that spawn reinforcements or other effects such as auras.

They should be added to the enemy_actions list as (check,function) where check can be "Any" or BM.mission.

Reinforce around ships
This is code from an unreleased mod that checks for certain ships and reinforces around them.
Reinforce is a function included in the framework.

Code: [Select]
init python:
    def M50function():
        for ship in BM.ships:
            if ship.name == 'Smuggler':
                reinforce( ((ship.location[0]-2,ship.location[0]+2),(ship.location[1]-2,ship.location[1]+2)),[[PactMook,1],[PactBomber,2],[PirateGrunt,1]],BM.turn_count/2,0.1 )
        return
 
    enemy_actions.append((50,M50function))

Next action trigger
Use:
This is very specialized, when a function is added to this list it triggers the next player loop in the battle, makeing a self-contained bubble in the code. This lets it interact with the battle in ways that would otherwise throw a UI error. It should be added to player_actions and will trigger pretty much instantly on the player's turn.

Example Code:
Phoenix booster warp weapon
Code taken from Phoenix restoration mod's warp weapon.
It is called from the fire code of the Warp weapon.

Code: [Select]
#weapon code
    class Boosterwarp(Support):
        def __init__(self):
            #stuff

        #Modified fire code
        def fire(self,parent,target,counter=False):
            #set variabls
            store.warpstats = []
            store.warpstats = [BM.selected, self.transport_cost, parent.move_cost, self.energy_use, parent.location, parent.weapons]
            store.player_actions.append([BM.mission,Boosterjump])
            renpy.jump('mission'+str(BM.mission))
            return

# Jumping restarts the battle code and lets the function in player_actions trigger
# Then the Boosterjump function triggers and removes itself from player_actions.
# Function that is added to player_actions, it uses UI.interact to pick a hex and jump to a new location.

    def Boosterjump():
        global WarpShockVar
        #warpstats:
        #    0 = selected ship
        #    1 = transport cost
        #    2 = original move cost
        #    3 = energy use
        #    4 = selected location
        #    5 = weaponslist
           
        store.warpstats[0].en -= store.warpstats[3]-store.warpstats[1]
        #reduces user's en by cost - 1 transport cost
        store.warpstats[0].move_cost = store.warpstats[1]
        #sets movement cost to transport cost
        store.warpstats[0].movement_tiles = MovTile2(store.warpstats[0]) # #loads areas that ship can reach
        BM.selected.weapons = []
        #store.WarpShockVar# check for to do warpshock
        #engage movement loop
        looping = True
        while looping:
            BM.selectedmode = True # Shows moveable tiles.
            BM.active_weapon = None
            Loc = ui.interact()
            if Loc[0] == 'move': # if player clicked on a movement tile
                    oldcords = store.warpstats[0].location
                    warpdamage = (get_distance(store.warpstats[0].location,Loc[1])*15)
                    store.warpstats[0].en -= (get_distance(store.warpstats[0].location,Loc[1])*store.warpstats[1])
                    JumpShip(store.warpstats[0],Loc[1][0],Loc[1][1]) # splits the location of movement tile into x and y and then uses warp function
                    store.warpstats[0].move_cost = store.warpstats[1] # resets move energy cost
                    store.warpstats[0].movement_tiles = get_movement_tiles(store.warpstats[0]) # resets move tiles
                    if WarpShockVar:
                        for ship in BM.ships[:]:
                            if get_distance(ship.location, booster.location) == 1:
                                ship.hp -= warpdamage
                                if ship.hp < 1: ship.destroy(phoenix)
                        warpdamage = get_distance(oldcords,Loc[1])*20
                        booster.hp -= warpdamage
                        if booster.hp < 1:
                            booster.destroy(booster)
                        show_message("The Phoenix's warp drive has caused a ripple in space.")
                    looping = False
               
            elif Loc[0] == 'deselect':
                store.warpstats[0].en += store.warpstats[3]-store.warpstats[1]
                store.warpstats[0].move_cost = store.warpstats[1]
                store.warpstats[0].movement_tiles = get_movement_tiles(store.warpstats[0])
                looping = False
        store.warpstats[0].move_cost = store.warpstats[2]
        store.warpstats[0].movement_tiles = get_movement_tiles(store.warpstats[0])
        store.warpstats[0].weapons = store.warpstats[5]
        return

Mod Enhancements
These are used to improve mod battles, there are both cosmetic and functional mods.

Visual formation mode.
Use:
This colors hexes that ships can or can't warp into. It works with the formation Place mod.

To enable:
    General overwrite:
        Overwritewarp = True

To use Blue boundries where ships can be placed, set Warpchoice = True, to use Red boundries where ships can't be placed set Warpchoice to False

Formation Place mod
Use:
To define your own placements, do:
Code: [Select]
python:
    BM.formation_range = [hexes]
As long as BM.formation_range is a list, the Visual formation mod will trigger automatically and use the hexes put in the list.
If you want to define an area, try doing something like this:

Code: [Select]
init python:
    coordset = [((12,8),(16,8)),
                 ((11,9),(18,9)),
                 ((10,10),(18,10)),
                 ((10,11),(18,11)),
                 ((9,12),(18,12)),
                 ((9,13),(18,13)),
                 ((8,14),(18,14)),
                 ((9,15),(18,15)),
                 ((9,16),(18,16))]
   
    for outer in coordset[:]:
        for a in range(outer[0][0],outer[1][0]+1):
            shamblehexlist.append((a,outer[0][1]))
This adds hexes between and includeing the hex pairs into a list that can then be used for BM.formation_range.

Pin grid to map
Use:
This lets you move/zoom the background when you move/zoom the grid. This means you can plan the mission about haveing a fixed point in the battle, for example a planet or hazard will stay in the same location rather than zooming around the map every time its dragged.

To trigger set Backgroundmode to True

Autonomus Ally ships
Use:
This lets you set any ship to act on its own AI (identical to the enemy AI). You can trigger the AI phase either before or after the enemy turn. They are able to use support on your ships or you can use them on them. This could be useful to do large scale battles between Alliance and Pact forces where the Sunrider is just a supporting ship.

There is a pre-made mod to the victory screen that lets you assign ally kills to their own list and shows up as an Assist bonus. To use this, attach killed_by_ally to ship.weapon_funcs.

To trigger, set ship.Ally = True.
To use Ally AI before the enemy ships move, set Ally_move to 1, to move after, set Ally_move to 2

Multi-battle Battles
Use:
This is a function that lets you run battles simultaneously, for example a mission where you cause a distraction, letting some other forces achieve a goal. It handles switching between phases and stores ships/covers/background and such.

The list setup is slightly complex but the actual switching is very easy.

Setup:
To use the function, you make a list containing a list for each battle phase you want. This could theoretically be 50+ but it would get very confuseing.

Fliplist = [[Phase1],[Phase2]]

Each Phase list should be: ["background", [player_ships], [enemy_ships], [covers], "phaseid"]
The easy way to set up is do create_ship as normal, put them into the list then blank player_ships and others so you can start either another list or do the main mission.

Trigger code:

This is actually very easy. Just do Fliplist = battleshift(Fliplist,phase number). The Battleshift function returns the list you feed it so there is nothing else you need to do.

Example Code:

Setup code
Taken directly from the Shamble hunting mod.
Code: [Select]
label mission55init:
    python:
        #Standard setup stuff with modified formation range.
        BM.formation_range = shamblehexlist
        Backgroundmode = True
        zoomlevel = 1
        enemy_ships = []
        destroyed_ships = []
        clean_grid()
        BM.xadj.value = 576.0
        BM.yadj.value = 816.0

    # Set up a phase list by makeing ships and setting the background
        BM.battle_bg = 'Shamble/Icyplanetspace.jpg'

        create_ship(Shambler(),(8, 2))
        create_ship(Shambler(),(5, 3))
        create_ship(Shambler(),(7, 3))
        create_ship(Shambler(),(10, 5))

        create_ship(PactElite(),(12, 2))
        enemy_ships[-1].max_en = 110
        enemy_ships[-1].move_cost = 60
        enemy_ships[-1].weapons = []
        enemy_ships[-1].register_weapon(PACTEliteMelee())
        enemy_ships[-1].weapons[0].damage = 150
        create_ship(PactElite(),(4, 7))
        enemy_ships[-1].max_en = 110
        enemy_ships[-1].move_cost = 60
        enemy_ships[-1].weapons = []
        enemy_ships[-1].register_weapon(PACTEliteMelee())
        enemy_ships[-1].weapons[0].damage = 150
        create_ship(PactElite(),(12, 11))
        enemy_ships[-1].max_en = 110
        enemy_ships[-1].move_cost = 60
        enemy_ships[-1].weapons = []
        enemy_ships[-1].register_weapon(PACTEliteMelee())
        enemy_ships[-1].weapons[0].damage = 150

        # There are more ships in the actual code
        # enemy ryders are limited to 1 space and a reduced dmg melee attack as in atmosphere.
       
        enemy_ground = enemy_ships # copy enemy_ships for the fliplist and then blank it
        enemy_ships = []
       
        create_ship(MissileFrigate(),(3, 3))
        create_ship(PactCruiser(),(4, 3))
        create_ship(MissileFrigate(),(3, 4))
        create_ship(PactCarrier(),(10, 6))
        create_ship(PactMook(),(6, 7))
        create_ship(MissileFrigate(),(1, 9))
        create_ship(PactMook(),(4, 9))
        create_ship(PactMook(),(8, 11))
        create_ship(MissileFrigate(),(4, 12))
        create_ship(PactCarrier(),(5, 12))
        create_ship(MissileFrigate(),(2, 15))

        Tship = create_ship(Transport(),sunrider.location)
        player_ships.remove(Tship)

        # Now you can make the fliplist

        Fliplist = [
                     ['Shamble/Icyplanetspace.jpg',player_ships,enemy_ships,[],'Space'],
                     ['Shamble/spaceicey.png',[Tship],enemy_ground,[],'Ground']
                     ]
The final entry in each phase list is used for the mod to check what phase it's in. It sets BM.phase to that value so you can always tell what part of the mission is active.
Trigger code
This example flips the battle between two lists every turn. The % symbol is remainder divided by x and a useful way to know when to flip a battle.
Code: [Select]
label mission55:
    python:

        if turncount != BM.turn_count:
            turncount = BM.turn_count

            if turncount % 2 = 0:
                Fliplist = battleshift(Fliplist, 2)

            if turncount != 1 and turncount % 2 == 1:
                Fliplist = battleshift(Fliplist, 1)

Auras: Visual component
Use:
This lets you show an aura effect on the battlefield, the actual effects need to be coded seperatly but with most effects its quite easy, useing move_funcs and gated actions lets you do a number of complex tasks.

The aura is an image or displayable and can use a transform (such as hoverglow)

ship.aura_size is the number of hexes range the aura is shown
ship.aura_image is the image shown per affected hex
ship.aura_alpha is the image transparency.
ship.aura_targets_self is True if the aura should display on its own host's hex

Auras can also be used on Cover objects.

Example code
Drednought Aura
Code: [Select]
init 2 python:
    class Dreadnought(Battleship):
        def __init__(self):
            super(Dreadnought, self).__init__()
            self.stype = 'Ship'
            self.name = 'Dreadnought'
            self.animation_name = 'alliancebattleship'
            self.faction = 'Player'
            self.max_hp = 2800
            self.hp = self.max_hp
            self.max_en = 180
            self.base_armor = 60
            self.armor = self.base_armor
            self.en = self.max_en
            self.max_missiles = 0
            self.missiles = self.max_missiles
            self.move_cost = 45
            self.hate = 300
            self.evasion = 0
            self.lbl = im.MatrixColor('Battle UI/label_sunrider.png',im.matrix.tint(0.4,0.2,1))
            self.portrait = None
            self.flak = 0
            self.flak_range = 0
            self.default_weapon_list = [DreadnoughtCannon()]

            # Aura attributes
            self.aura_size = 4
            self.aura_image = hoverglow("Battle UI/vanguard hex.png")
            self.aura_alpha = 0.5
The last three attributes set the aura look. This one shows red glowing hexes around the ships location.

AI: Ordering
Use:
This lets you manually order the AI of ships. The standard AI checks for ships flagged as support, ships with higher than average armor and regular ships.

The new order method is: Support, 1, 2, Lead, Standard, 3, 4 and you can set ship.Priority to call them first in their group.

This will be more useful when the ship AI is modified.

Example code:
Code: [Select]
Ship1.Group = 1
Ship1.Priority = True

Ship2.Group = 4
Ship2.Priority = False

In this example, Ship 1 will go just after support, whilst Ship 2 will move very late in the enemy's turn.

Easy Team Switch
Use:

Ships can now be switched between teams by changing the ship.faction and x_ships lists. If useing Dynamic animations, then animations will automatically line up.

There is a new function that will do it for you, change_ship(shipname) or ship.change_faction()

change_ship(ship) or ship.change_faction() will turn it PACT
change_ship(ship,True) or ship.change_faction(True) will turn it Player
change_ship(ship,faction = 'Name') or ship.change_faction(faction = 'Name') will set the faction to 'Name'

Example:
change_ship(blackjack)
or
blackjack.change_faction()

sets the Blackjack to PACT controlled

Weapon Ammo
Use:
Each weapon can be assigned ammo and its own ammo use. The ammo is tracked by the weapon rather than the ship and can be set to refill on mission start or not.

All weapons can use ammo, not just missiles and rockets. Ammo can be controlled by setting weapon.ammo and is automatically reduced by weapon.ammo_use

Code: [Select]
   # Default is set to None, setting it otherwise activates ammo mode
    Weapon.ammo = None # Controls the ammo level
    Weapon.max_ammo = None #Maximum ammo, if auto-replace, will replace to this level.
    Weapon.replace_ammo = True # Does it refill at start of mission?
    Weapon.ammo_use = 1 # ammo used per shot

Example:
From the Shambler hunting mission, unique weapon
Code: [Select]
    Shamblerocket.ammo = 0 # starts with 0 ammo
    Shamblerocket.max_ammo = 3
    Shamblerocket.reset_ammo = False # Is restored through the store
    Shamblerocket.ammo_use = 1

Weapons can be set to use a combined ammo pool if you use weapon functions to reduce the other weapon's available ammo (or missiles as needed)

On-Load functions
Use:
This lets you trigger functions on loading of games, this is helpfull if you need to check/set things like the formation range or label overrides that would otherwise reset on every load. Also good for fixing compatibility problems.

Can launch labels as well as functions, uses (Conditional, Event) where Conditional must eval to True to trigger.

Example:
The code to do a lable and a function is the same. The function can have no arguments and should just be its name in a string
Code: [Select]
after_load_funcs.append((True,"labelname"))
after_load_funcs.append(("Modname_version == 1.5","Function"))

By doing something like:
Code: [Select]
init python:
    if not Modname_version = Current_modname_version:
        after_load_funcs.append((True,"labelname"))
    Modname_version = Current_modname_version
You can call a function or label to patch problems if needed.

Dynamic Animations
Use:
Hit animations are now able to tell what direction an attack came from and what direction ships are faceing, if usedynamic == True. If ModFramework_Dynamic_animations is used, it will automatically do it for attack animations as well.

Hit animations are easy to use with custom ships, but attack animations require a bit more work. If they are not included, however the game will just use the existing ones and will not throw errors.

Modified weapon animations via weapon.attanimation and weapon.hitanimation overwrite these.

Adding custom Ships (hit):

Code: [Select]
init python:
    sila.append(("ship base class", "ship side image"))
    ship_animation_list.append(ship base class)

Example useing the Sunrider:

init python:
    sila.append(("Sunrider", "sunrider_side"))
    ship_animation_list.append(Sunrider)
Adding Custom Ships (Attacks)
Adding a custom dynamic animation is very easy and not time consuming because most of it is just flipping images.
Templates will be added in the future.

Weapon Animation Overrides
These let you fire a different label when the weapon fires and when it hits to the standard defaults, Useing the dynamic ship image from Dynamic attacks, it means you can use one label to (as an example) show laser attacks from the Legion as hitting with red beams like it shows on the attack animation.

Use:

Code: [Select]
Weapon.attanimation = 'attack label overwrite'
Weapon.hitanimation = 'weapon hit label overwrite'

Example:
Taken from the Ryuvian Missile demo: (This adjusts for ships but not their location as it is slightly old code. Look at dynamic code for weapons that can be used by both sides)

this example code is old, needlessly long and is done much better by the Dynamic labels, a better one will be put up soon
Code: [Select]
init 2 python:
    # Attack label (actually unchanged)
    RyuvianCruiserMissile.attanimation = "atkanim_ryuviancruiser_missile"

    # Hit label (changed)
    RyuvianCruiserMissile.hitanimation = "Rymissile"

label Rymissile:
    if config.skipping:
        return

    $renpy.show_screen('show_background',_layer='master')
    show screen animation_hp
   
    ###################################
    ###         Shiftimage          ###
    ###################################
    ###    Dynamic Image Checking   ###
    ###################################
   
    #This uses the dictionary that comes with M52-53_7.2_1.2.rpy to find the label for the right ship.
   
    # The code below tells you if the entry is an image, a label or a function and acts accordingly
   
    #If it isn't in the dict then it's skipped
    # In brief, if the result has Image in front then the label is used.
    # If its a string without Image in front, its assumed to be a filename
    # If its not a string, it is assumed to be a function and is run to attempt to extract an image or filename
    # It then is checked for the Image prefix and decides what it is
   
    # If it is a file then it is converted into an image and shown directly
    # If it is a defined image then it is shown at centerscreen
    # Feel free to just copy-paste if you want to use this
   
    # IF the ship is not in the directory, it can be added automatically if the correct attributes are set, otherwise there will be a plug-in on the Missile page.
   
    python:
        shiftimage = BM.target2.animation_name
       
        if shiftimage in ship_animations:
            shiftimage = ship_animations[shiftimage] # extract the image name
            if shiftimage[0:5] == "Image":
                shiftimage = ["image",shiftimage[5:]]   
        else: shiftimage = True
       
    if shiftimage == True:
        return
       
    python:
        if type(shiftimage) == str:
            imagetype = "file" # if the image is a filename
        elif type(shiftimage) == list:
            imagetype = "list"
        else:
            shiftimage = shiftimage()
            if shiftimage[0:5] == "Image":
                shiftimage = ["image",shiftimage[5:]] 
                imagetype = "list"
            else:
                imagetype = "file"
   
    if imagetype == "file":
        #This makes the image
        image shiftimage:
            shiftimage
            xanchor 0.5 yanchor 0.5
       
        show shiftimage:
            xpos 0.5 ypos 0.5

    if imagetype == "list":
        $renpy.show(shiftimage[1], at_list = [Position(xpos = 0.5, ypos = 0.5)])
       
    ###################################
    ###         Shiftimage          ###
    ###################################
    ###     Dynamic Image Done      ###
    ###################################
    ###  Boreing standard stuff now ###
    ###################################
   
    pause 0.1

    play sound1 "sound/missilefly.ogg"

    show RY_missile1:
        rotate -10
        xpos 1440 ypos 0 alpha 0
        pause 0.4
        alpha 1
        linear 0.7 xpos 620 ypos 480
        alpha 0

    show RY_missile2:
        rotate -10
        alpha 0 xpos 1640 ypos 0
        pause 0.3
        alpha 1
        linear 0.7 xpos 740 ypos 560
        alpha 0

    show RY_missile3:
        rotate -10
        xpos 1750 ypos 0 alpha 0
        pause 0.2
        alpha 1
        linear 0.7 xpos 920 ypos 500
        alpha 0

    show RY_missile4:
        rotate -10
        xpos 1930 ypos 0 alpha 0
        pause 0.1
        alpha 1
        linear 0.7 xpos 1010 ypos 540
        alpha 0

    play sound1 "sound/explosion1.ogg"

    show layer master at shake1(pausetime=0.9,repeats=12)
   
    # If its a large ship, for scale you want small exploads, if ryder you want large
    # contrary to documentation, you can set images OUTSIDE of an image block
    python:
        if BM.target2.stype != "Ryder":
            Ryexpload = im.MatrixColor("gameplay/Animations/Sunrider/sunrider_side_missilehit1.png",im.matrix.tint(0.2,0.2,1)*im.matrix.brightness(0.6))
           
        else:
            Ryexpload = im.MatrixColor("gameplay/Animations/PirateBomber/missileexplode2.png",im.matrix.tint(0.2,0.2,1)*im.matrix.brightness(0.6))
       
   
    image Ryexpload1:
        Ryexpload
        xanchor 0.5 yanchor 0.5 xpos 0.5 ypos 0.5
   
    image Ryexpload2:
        Ryexpload
        xanchor 0.5 yanchor 0.5 xpos 0.5 ypos 0.5
       
    image Ryexpload3:
        Ryexpload
        xanchor 0.5 yanchor 0.5 xpos 0.5 ypos 0.5
       
    image Ryexpload4:
        Ryexpload
        xanchor 0.5 yanchor 0.5 xpos 0.5 ypos 0.5
   
    show Ryexpload1:
        xpos 0.2
        alpha 0
        pause 0.9
        ease 0.2 alpha 1
        pause 0.2
        ease 2 alpha 0

    show Ryexpload2:
        xpos 0.4
        alpha 0
        pause 0.9
        ease 0.2 alpha 1
        pause 0.2
        ease 2 alpha 0

    show Ryexpload3:
        alpha 0
        xpos 0.25 ypos 0.4
        pause 0.9
        ease 0.2 alpha 1
        pause 0.2
        ease 2 alpha 0

    show Ryexpload4:
        alpha 0
        xpos 0.35 ypos 0.55
        pause 0.9
        ease 0.2 alpha 1
        pause 0.2
        ease 2 alpha 0
   
    pause 0.15

    show sunrider_missiletrail_hit with sunridermissilehitwipe:
        ypos 0.45
    hide sunrider_missiletrail_hit with dissolve

    pause 0.3

Story manipulation
Dynamic ship map
This lets you set buttons on the ship map dynamically, as an insert into the story. You can use any combination of variables and it will create the label as long as the eval string returns True.

It also doubles as a way to run functions when you hit the ship map.

Use:

All labels are checked for validity when the ship map is loaded. If the eval string returns True, then a ship button is created. This WILL overrite other buttons so it is best to include something like 'asa_location == None' in its check to avoid overwriting story labels.

Code:
Syntax and Options
The basic code is:
Code: [Select]
chat_labels.append(['conditions','name','loc','label'])
conditions is a string of variables, functions ext that must return True when evaluated
Example: "asaga_affection >= 4 and asaga_location = None" would let the label appear so long as she was not already showing on the ship map and her affection is greater or equal to 4

'name' is the person you want to see (it sets that person's location and their button)

Name Options
pro (Progress button)
gal (Galaxy Map)
asa (Asaga)
ava (Ava)
chi (Chigara)
ica (Icari)
cla (Claude)
sol (Sola)
kry (Kryska)

'loc' is the location the button appears:

Location Options
captainsloft
sickbay
messhall
bridge
engineering
lab
hanger

Label is the string of the label you want to go to.

Talk to Icari in the Lab
From the Phoenix Restoration Mod

Code: [Select]
init python:
    chat_labels.append(['mission11_complete and ica_location == None and chi_location == None and Boostertalk == False','ica','lab','Rebuildbooster'])

Triggers if mission 11 is done, neither Icari or Chigara are on the map and the booster repair hasen't been talked about.

Puts Icari in the Lab and jumps to the Rebuildbooster label when clicked

From Saibotlieh's asaga mission

This is a more complex example useing functions to check if its available, it puts Asaga on the Bridge so long as she has no other location, has not been spoken to about the mission and when a judge function returns True.

Code: [Select]
init python:
    chat_labels.append(["asa_location == None and MoACharacterMissionPossible('Asaga') and SL_SM_AsagaMission_Intro and MainMissionCompleted() >= 12",'asa','bridge','SL_SM_AsagaMission_Intro'])

Generic Warp code
This lets you run a generic warp animation with ~10 lines of code and jump to the label you want without a large amount of space taken up by repetitive code.

Use:

Planet("Name", "jumplabel1", Posx, Posy, "eval string")

Normally you would jump straight to the mission selection, however with this method, you first jump to a label that defined the background and info text, then bounce to the selection label.

label jumplabel1:
    image modbg2 = main background image
    image modinfo2 = info card
    #(You can just use a transparent image if you don't want anything shown)

Now you would normally jump straight to the label from the mod selection, instead you jump to a label to set modjumplabel to the label you want to end up at and then jump to transit

label missionacsepted:
    $modjumplabel = "missionstart"
    jump transit

Then the sunrider is seen warping out and into the modbg2 you set earlier.

Example:
From Shambler Hunting
Code: [Select]
init python:
    Planet("ICY MOON", "Icyselection", 1670, 250, "shamblesvar") # Define the planet

label Icyselection:
    image modbg2 = "Background/space5.jpg" # Define the background
    image modinfo2 = "Shamble/Icymoon_info.png" # Define the infocard
    jump Icemissions # Jump to next step

label Icemissions: # Choose mission screen

    $ map_back = "planetback" # Handled automatically with this code

    if Icymission1: # set a variable if you want the mission to be available
        $ galaxymission1 = True # Is mission available?
        $ mission1 = "Shamblesmission" # Jump to label for mission
        $ mission1_name = "Investigate: Pact Base" #mission name

    else: # Blank if mission is already done
        $ galaxymission1 = False
        $ mission1 = None
        $ mission1_name = None
    jump showmodplanet

label Shamblesmission: # The label the mission button jumps to
    $ modjumplabel = "aboveicymoon" # The label to visit after you warp our
    $Icymission1 = False # Disable the mission
    jump transit # Show warp and jump to mission label   

Ship Flavor text
Use:
This lets you put writeing in the status box, where buffs are shown by adding strings to ship.mod
Example:

Code: [Select]
init 2 python:
    Mochi.mod.append("Pilot: Claude Trillo")
    Mochi.mod.append("Cargo: Booze")

Would show up on the Mochi's status screen

Bug Fixes
Laser Accuracy: Lasers now benifit from accuracy research
Counter Attacks: Enemy ryders no longer counter attack AND move away from your melee ryders.

Combo Time!
These are extremely versatile on their own but all these features are designed to work together.

For example you can make auras by adding a function to ship.move_funcs that detects nearby ships and applies stealth to them or grants them an accuracy bonus.

You can combine a death function with a weapon function to move the phoenix into a destroyed ryder's hex.

You could move the Liberty within range of a cargo vessel to scan its hold and display what Cargo it is carrying in its status screen.

You can attach a slow-acting acid to a ship that deals increasing damage and disables a target ship over time by combining a weapon function and a per-turn function.

You can apply enviromental effects by putting an aura on certain covers, setting their lbl to invisible and makeing their block chance 0% and then triggering functions on ships that move into the aura's range (penalty to accuracy or evasion vs targets outside of the effect)

Future Plans:
Blank Hex targeting: Weapons will be able to fire at empty hexes, usefull for area weapons and weapons such as mines.

Persistent Item Weapons: Will be able to place Mines and other things on the map.

Custom AI modes: Several different AIs that will react to Auras and have their own methods of killing you.

Pictures!
Warp Mod


'Medicinal Booze'


Disintegration Aura (Aura area actually glows/flashes)


Ally victory screen (Yes I cheated and Repair costs can go negative  ;D)
Need to adjust the spacing on the Ally Kill text


Weapon Ammo (Look at the Sunrider Laser)


Installation:
Just drop the ModFramework.rpy file into the Sunrider/game folder. If you have any of the M52 rpy files then either delete them and the rpyc files or drop in the blank files from the google link.

To use the Dynamic animations for fireing and hitting of ships, also download and use the ModFramework_Dynamic_animations.rpy and set usedynamic to True in either the main file or the Override file

The Override file is where player moddable variables can be used to overwrite the Modframework variables to enable/tweak features, it is completely optional.

All my other current mods have been updated to work with this rather than the M52 files. Just drop the new versions in to work with this update.

If there are any bugs, PLEASE let me know, this has been tested both on my mod game and a blank game so they should be quite rare.
As the code is quite disorganized it can be hard to connect what bits do what but I would be happy to go through code for people if there is any need.

Unfortunately this framework is not compatible with the Extensive Re-balance Mod

Updates:

18/12: Ordered ship actions.
20/12: Applied holder attributes to Battleship and let melee run without a character sprite
            This lets you change a ship to player/enemy by just changing ship.faction and switching it's x_ships list.
            change_ship(ship,faction) will do this for you but Animations may need altering
22/12: Selected weapons now show damage that includes any modifiers
            Fixed a bug with the GravityGun
29/12: Enabled ammo for weapons. Ammo is tracked by each weapon specifically and can be set to replenish at start of battle or not.
2/1:     Enabled after-load functions to be used
5/1:     Weapon functions can now also be put into ship.weapon_functions to trigger on each weapon that ship controls.
13/3:   Enabled Auras to display on Covers.
            Added Dynamic animations and improved documentation with examples
            The movement range is no longer automatically unlimited and has been put down to 5. The phoenix mod will set it back to unlimited or it can be done in Override.
            Current line count over three files is... 13,475!
« Last Edit: March 13, 2016, 08:41:45 pm by The Bigfoot »
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline Drath

Re: [7.2] Mod Framework/Tools
« Reply #1 on: December 17, 2015, 05:08:35 pm »
As always, you're the man Bigfoot! :D Hope at least some of this makes it into Liberation Day. But if it doesn't, the modders should use these as tools to make more varied units and battles in future. :)

Offline Garcis :3

Re: [7.2] Mod Framework/Tools
« Reply #2 on: December 19, 2015, 04:06:46 pm »
As always, you're the man Bigfoot! :D Hope at least some of this makes it into Liberation Day. But if it doesn't, the modders should use these as tools to make more varied units and battles in future. :)
Hi I have this problem with the mod.It happens in your first fight against cosette

While running game code:
  File "game/script.rpy", line 1479, in script
    $ BM.battle()  #continue the battle
  File "game/script.rpy", line 1479, in <module>
    $ BM.battle()  #continue the battle
  File "game/ModFramework.rpy", line 189, in ModifiedBattle
    self.dispatch_handler(self.result)()
  File "game/classes.rpy", line 954, in battle_end_turn
    self.end_player_turn()
  File "game/ModFramework.rpy", line 251, in end_player_turn
    self.enemy_AI() #call the AI to take over
  File "game/ModFramework.rpy", line 460, in enemy_AI
    Sortships_AI(enemy_ships)
  File "game/ModFramework.rpy", line 391, in Sortships_AI
    if defense > average_defense and ship not in BM.support_ships:
AttributeError: 'Battle' object has no attribute 'support_ships'

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/script.rpy", line 1479, in script
    $ BM.battle()  #continue the battle
  File "C:\Users\user1\Desktop\imagenes, archibos y musica\carpetas de juegos\Sunrider\renpy\ast.py", line 785, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "C:\Users\user1\Desktop\imagenes, archibos y musica\carpetas de juegos\Sunrider\renpy\python.py", line 1445, in py_exec_bytecode
    exec bytecode in globals, locals
  File "game/script.rpy", line 1479, in <module>
    $ BM.battle()  #continue the battle
  File "game/ModFramework.rpy", line 189, in ModifiedBattle
    self.dispatch_handler(self.result)()
  File "game/classes.rpy", line 954, in battle_end_turn
    self.end_player_turn()
  File "game/ModFramework.rpy", line 251, in end_player_turn
    self.enemy_AI() #call the AI to take over
  File "game/ModFramework.rpy", line 460, in enemy_AI
    Sortships_AI(enemy_ships)
  File "game/ModFramework.rpy", line 391, in Sortships_AI
    if defense > average_defense and ship not in BM.support_ships:
AttributeError: 'Battle' object has no attribute 'support_ships'

Windows-8-6.2.9200
Ren'Py 6.99.3.404
Sunrider Mask of Arcadius  Beta 7.2

can you help me?

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #3 on: December 19, 2015, 06:05:15 pm »
can you help me?

If you re-download the Framework file from the googlemail link it should be fixed! Thanks for letting me know.

https://drive.google.com/open?id=0B0D6n1uinVVzTVJ0YzdfM2ZrU2M
« Last Edit: December 19, 2015, 07:28:13 pm by The Bigfoot »
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline techercizer

Re: [7.2] Mod Framework/Tools
« Reply #4 on: December 27, 2015, 07:07:53 pm »
I get the following error on linux when I try to provoke Icari's counterattack via Claude's Gravity Gun.

Quote
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/skirmish.rpy", line 38, in script call
    call mission_skirmish from _call_mission_skirmish
  File "game/skirmish.rpy", line 38, in script call
    call mission_skirmish from _call_mission_skirmish
  File "game/script.rpy", line 10431, in script
    $BM.battle()  #continue the battle
  File "game/script.rpy", line 10431, in <module>
    $BM.battle()  #continue the battle
  File "game/ModFramework.rpy", line 197, in ModifiedBattle
    self.dispatch_handler(self.result)()
  File "game/ModFramework.rpy", line 1838, in battle_selection
    weapon.fire(self.selected,self.target)
  File "game/classes.rpy", line 2750, in fire
    target.move_ship(result[1],BM) #result[1] is the new location to move towards
  File "game/ModFramework.rpy", line 2107, in fixedmoveship
    renpy.call_in_new_context(weapon.attanimation)
ScriptError: could not find label 'None'.

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/skirmish.rpy", line 38, in script call
    call mission_skirmish from _call_mission_skirmish
  File "game/skirmish.rpy", line 38, in script call
    call mission_skirmish from _call_mission_skirmish
  File "game/script.rpy", line 10431, in script
    $BM.battle()  #continue the battle
  File "/home/user/.local/share/Steam/steamapps/common/Sunrider/renpy/ast.py", line 785, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/home/user/.local/share/Steam/steamapps/common/Sunrider/renpy/python.py", line 1445, in py_exec_bytecode
    exec bytecode in globals, locals
  File "game/script.rpy", line 10431, in <module>
    $BM.battle()  #continue the battle
  File "game/ModFramework.rpy", line 197, in ModifiedBattle
    self.dispatch_handler(self.result)()
  File "game/ModFramework.rpy", line 1838, in battle_selection
    weapon.fire(self.selected,self.target)
  File "game/classes.rpy", line 2750, in fire
    target.move_ship(result[1],BM) #result[1] is the new location to move towards
  File "game/ModFramework.rpy", line 2107, in fixedmoveship
    renpy.call_in_new_context(weapon.attanimation)
  File "/home/user/.local/share/Steam/steamapps/common/Sunrider/renpy/game.py", line 306, in call_in_new_context
    return renpy.execution.run_context(False)
  File "/home/user/.local/share/Steam/steamapps/common/Sunrider/renpy/execution.py", line 684, in run_context
    context.run()
  File "/home/user/.local/share/Steam/steamapps/common/Sunrider/renpy/script.py", line 602, in lookup
    raise ScriptError("could not find label '%s'." % str(original))
ScriptError: could not find label 'None'.

Linux-4.2.0-22-generic-x86_64-with-debian-jessie-sid
Ren'Py 6.99.3.404
Sunrider Mask of Arcadius  Beta 7.2

Any thoughts? My ModFramework.rpy is up to date as of yesterday.

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #5 on: December 29, 2015, 06:59:25 pm »
I get the following error on linux when I try to provoke Icari's counterattack via Claude's Gravity Gun.

That... is extremely helpful. I was getting an odd error before that I couldn't track down but it wasn't crashing the game. Must have been hidden by another mod I have running.

I don't have access to my computer ATM so all I can do is change the file with a kindle. The new version should work, from what I can see it's just one line that I missed when combining it but if not then let me know and when I get home tomorrow I will have a closer look.

Sorry it took a couple of days to see the post!
« Last Edit: December 29, 2015, 07:32:12 pm by The Bigfoot »
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #6 on: March 13, 2016, 09:50:07 pm »
Updated with code examples, explanations  and ~5 new features, unlimited movement range is no longer mandatory and can be toggled for any range.

Directional Dynamic animations are now a thing, and I will update the framework for all mod ships within a few days, after I recover from Animation Insanity. (although it is fairly easy to add them yourselves)



I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline saibotlieh

Re: [7.2] Mod Framework/Tools
« Reply #7 on: March 13, 2016, 10:42:59 pm »
Updated with code examples, explanations  and ~5 new features, unlimited movement range is no longer mandatory and can be toggled for any range.

Directional Dynamic animations are now a thing, and I will update the framework for all mod ships within a few days, after I recover from Animation Insanity. (although it is fairly easy to add them yourselves)




Good work, I remember a lot of copy&paste for the few animations I created.

Also, I just remembered that I created a button for your trank gun some time ago. Have a look, maybe you like it.

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #8 on: March 13, 2016, 11:12:57 pm »
Good work, I remember a lot of copy&paste for the few animations I created.

Also, I just remembered that I created a button for your trank gun some time ago. Have a look, maybe you like it.

Thanks! Will update it in a bit  ;D. Did you ever get the secret weapon from that mod?
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline saibotlieh

Re: [7.2] Mod Framework/Tools
« Reply #9 on: March 15, 2016, 08:07:45 pm »
Thanks! Will update it in a bit  ;D. Did you ever get the secret weapon from that mod?
No worries. Did not get the secret weapon when I played the mod, noticed the existence of it too late.

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #10 on: March 15, 2016, 08:16:14 pm »
If you want to try it without going through the mission (you will miss out on ~3 scenes) then...

Code: [Select]
sunrider.weapons.append(Wcannon)
Wcannon.ammo += 3

will give you the cannon and 3 shots.
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum

Offline saibotlieh

Re: [7.2] Mod Framework/Tools
« Reply #11 on: March 20, 2016, 09:48:56 pm »
If you want to try it without going through the mission (you will miss out on ~3 scenes) then...

Code: [Select]
sunrider.weapons.append(Wcannon)
Wcannon.ammo += 3

will give you the cannon and 3 shots.
Certainly a strange weapon, but fits quite well to the mission I'd say.

I was made a button for that weapon as well, but was not completely sure about a good short name for it (Wcannon somehow does not cut it for me). Have a look at it, I can still change the text if you would like something else.

Offline The Bigfoot

Re: [7.2] Mod Framework/Tools
« Reply #12 on: March 20, 2016, 10:02:38 pm »
Wocket is perfect  ;D Thanks!
I make spaceships! - http://innomenpro.com/forums/index.php?topic=1366.0
Massive Modding tutorial here: http://innomenpro.com/forums/index.php?topic=1251.0
New Award: John Titor [Sep 17, 2015, 10:16:07 PM]:   BigFoot is the official Evil Genius fro mteh forum