Jump to content
  • 3
Hammelpilaw

Scripting API requests

Suggestion

When playing online every player got some sectors wich always be kept alive. The order wich sectors will be alive is hardcoded. It would be awesome for modders to be able to change the order.

 

The reason is simple: When you got many stations in different sectors you do not need all the secors to be up because the production will be calculated when the sector gets restored from disk. But your salvage ship in another sector does not keep the sector alive, you have to calculate how many ships you need there to make its score bigger then the stations in other sectors. This is only one example, there are many situations where I wished I could modify it.

 

Some examples what Im thinking of.

 

Manually define the sector score.

function getSectorUpkeepScore(Entities, Player)  local score = 0
  for _,entity in pairs(Entities)
    if entity.factionIndex == Player.index then
      if entity.hasScript("salvage.lua") then
        score = score + 5
      end
      -- do some more stuff
    end
  end
end

 

 

Manually define the entities score

function getEntityUpkeepScore(Entity, Player)
  -- Calculate entity score
end

 

 

Also it would be great to see wich sectors are alive.

Player():getAliveSectors()
-- or
Server():getAliveSectors(playerIndex)

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

I'm trying to use the forceDock() function, but its final two arguments, which should indicate the dockee's look and up vectors, don't seem to do anything, no matter what sort of matrix I use. I'm using console print-outs to confirm that the matrices themselves are accurate, but the dockee simply never rotates. It always uses the parent's look and up vectors, as if I entered nil for those final two arguments.

Is that expected behaviour?

If not, could you please look into this? I have a great mod in the making (some nice docking mechanics!), but it's stopped totally dead in its tracks because of this behaviour.

====

Koonschi reported that this is already possible / more workable if you use strings for the axes you want your dockees to align to, eg. "x", "-z". I have found it quite tricky to find the right combinations of vectors (which are in the parent's LOCAL SPACE!) to get the orientation I need, as many of the ones I expect to function given the colours of the axes reported in Build Mode as well as console read-outs of Block positions, don't behave to expectations, but with some fiddling of letters you can find them. I reserve the right to hide the fact I may just be terrible at vector Maths. 😉

Edited by Shrooblord

Share this post


Link to post
Share on other sites
  • 0

Yet Another Request™

Add this code (or something similar) to AsyncPirateGenerator:

function AsyncPirateGenerator:setPirateFactionByLevel(_PirateLevel)
    self.pirateLevel = _PirateLevel
end

Or at least make it so I can modify the pirate level of the generator somehow. I already have this set up myself, but I think it would be a nice addition to anyone who wanted to feature the same pirate faction in a mission that spanned two sectors over a large distance.

Share this post


Link to post
Share on other sites
  • 0
local generator = AsyncPirateGenerator()
generator.pirateLevel = my_desired_pirate_level

This is all you need to modify the pirate level.

  • Like 1

Share this post


Link to post
Share on other sites
  • 0
On 11/11/2020 at 3:40 AM, koonschi said:

local generator = AsyncPirateGenerator()
generator.pirateLevel = my_desired_pirate_level

This is all you need to modify the pirate level.

Thank you! I'll take a note of that.

Share this post


Link to post
Share on other sites
  • 0

Is there an example of how to color dialogs or change the name in the upper left corner somewhere? I can't find any examples in the script or the documentation.

EDIT / UPDATE: I actually managed to figure this out through pure guesswork / conjecture based on some of the mission utility functions / names, but I still think it would be a good idea to add a resource for others somewhere in the documentation.

EDIT / UPDATE2: I just saw the updated documentation! Looks great!

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0

.borderCombo and .sortCombo are not valid when trying to :hide() them in a InventorySelection()
while .filterTextBox is valid and can be hidden. It'd be nice to be able to hide these elements too.

Share this post


Link to post
Share on other sites
  • 0

Some method to get the camera position in 3d space so i can do projections onto the 2d screen. Was planning on making lead indicators. Or alternatively a vec3/matrix method to project to screenspace so i don't have to do all the math 😛

Edited by Bubbet

Share this post


Link to post
Share on other sites
  • 0
Quote

.borderCombo and .sortCombo are not valid when trying to :hide() them in a InventorySelection()
while .filterTextBox is valid and can be hidden. It'd be nice to be able to hide these elements too.

There are some technical limitations considering the internal types of those ComboBoxes that prohibit a proper exposure to the Scripting API. I'm afraid those will never be available unless we're doing some major internal refactorings, which is unlikely.

Quote

Some method to get the camera position in 3d space so i can do projections onto the 2d screen. Was planning on making lead indicators. Or alternatively a vec3/matrix method to project to screenspace so i don't have to do all the math 😛

Exposing the camera to the Scripting API is planned.

Share this post


Link to post
Share on other sites
  • 0
On 11/25/2020 at 2:16 AM, koonschi said:

Exposing the camera to the Scripting API is planned.

All i was really asking for was something like UIRenderer():calculateEntityTargeter() but for a vec3 in the sector. But full camera modding would be pretty cool too.

Share this post


Link to post
Share on other sites
  • 0

Modding support to change the color and look of the nebulae generated in a sector, the background. Stuff like planets and dustiness is controlled by lua, why not the color and other properties of the sector?

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

I'm not sure if there's already a way to do this in structured mission, but a way to differentiate between client-only triggers and server-only triggers would be awesome.

I guess I could always wrap the declarations in onServer / onClient but that feels kind of gross.

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0

A userdata to emulate ControlAction presses, so i can release the cursor when making a Hud():createWindow() though I'm sure it has plenty of other uses.

Or some functions added to GameInput to set key presses I.E.

GameInput():setKeyDown(ControlAction.ReleaseMouse)

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

The API for torpedoes could use some work. I have a ship with two torpedo tubes that each have 6 available slots. The following code:

local _Player = Player(callingPlayer)
local _Craft = _Player.craft
local _Launcher = TorpedoLauncher(_Craft.index)
local _Shafts = {_Launcher:getShafts()}

for _, _Shaft in pairs(_Shafts) do
    print("K : " .. tostring(_) .. " - V : " .. tostring(_Shaft))
end

print("numShafts : " .. tostring(_Launcher.numShafts) .. " - maxShafts : " .. tostring(_Launcher.maxShafts))

returns 10 shafts in _Shafts, and both numShafts and maxShafts returns 10.

_Launcher:getFreeSlots(_Shaft) will also return 15 if the shaft is unavailable for use.

Trying to dynamically load the launchers based on the number of available slots will KILL the game and corrupt a save to the point where it needs to be restored from a backup.

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0

 

On 1/4/2021 at 4:06 PM, Bubbet said:

A userdata to emulate ControlAction presses, so i can release the cursor when making a Hud():createWindow() though I'm sure it has plenty of other uses.

Or some functions added to GameInput to set key presses I.E.

GameInput():setKeyDown(ControlAction.ReleaseMouse)

Emulation of KeyPresses is not possible.

On 1/9/2021 at 7:56 AM, Sathaerz said:

The API for torpedoes could use some work. I have a ship with two torpedo tubes that each have 6 available slots. The following code:


local _Player = Player(callingPlayer)
local _Craft = _Player.craft
local _Launcher = TorpedoLauncher(_Craft.index)
local _Shafts = {_Launcher:getShafts()}

for _, _Shaft in pairs(_Shafts) do
    print("K : " .. tostring(_) .. " - V : " .. tostring(_Shaft))
end

print("numShafts : " .. tostring(_Launcher.numShafts) .. " - maxShafts : " .. tostring(_Launcher.maxShafts))

returns 10 shafts in _Shafts, and both numShafts and maxShafts returns 10.

_Launcher:getFreeSlots(_Shaft) will also return 15 if the shaft is unavailable for use.

Trying to dynamically load the launchers based on the number of available slots will KILL the game and corrupt a save to the point where it needs to be restored from a backup.

If you encounter crashes in the API, please submit a bug report with a fully working example.

Share this post


Link to post
Share on other sites
  • 0

Let us add an explicit resistance to hulls. This is already possible by adding a negative weakness.

Also it would be neat if we could edit shield colors independently of resistances, but that's not that big of a deal.

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0

EDIT: Original post was so that we could make it so the "accept" button can be disabled in a mission bulletin. That would still be nice but I realized you can achieve something very similar with checkAccept.

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0

I suggest to add an explicit non-async syncronization step that would happen after client downloaded the mods and connected to a server but before any sector/entity/player scripts are created and initialized. Mods would use this step to syncronize their server-side mod configs with connecting clients and then they could use the "setGlobal" function to store them on client.

Why do we need it

Because there are cases where the standard post-initialize 'client uses invokeServerFunction("sendConfig") -> server uses invokeClientFunction("receiveConfig", config)' method doesn't work, because it's asyncronous and too late (happens after "initialize").

Examples

  • Adjust item/upgrade prices - by the time we syncronize settings Equipment Docks have already initialized items with vanilla prices.
  • Adjust system upgrade stats - by the time we syncronize settings, game has already created tooltips with vanilla values being shown.
  • Override SectorSpecifics - imagine someone created a quest that turns volcanic planet into an earth-like planet as a result. It's an actual visible impact that player could make on a galaxy. But if someone would log in while in that sector they would still see a volcanic planet because the game requested SectorSpecifics before syncronization completed.
  • And in general modifying anything that client Lua or C++ side uses during the "initialize" or before that.

As an additional bonus this will slightly decrease traffic and client RAM usage in the heavilly moded games - because some mods would syncronize configs only once (instead of once per every modded entity) and store them in one place.

How I see it

We could use something like the main.lua, but for both client and server.

Server:

SomeHelperLibrary = include("myhelperlibrary")

function synchronize()
	local config = SomeHelperLibrary.loadConfig("ModName")
	-- getting config ready to be sent (perhaps stripping unnecessary info)
	return config -- THIS will be sent to the client
end

Client:

function synchronize(config) -- we receive config and save it
	setGlobal("MyMod", config)
end

then showing updated price ("data/scripts/items/energysuppressor.lua"):

local myMod_create = create
function create(item, rarity)
	local item = myMod_create(item, rarity)

	local config = getGlobal("MyMod")
	item.price = config.energySuppressorPrice

	return item
end

 

Edited by Rinart73

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

Add iteration metamethods to the enum userdatas like KeyboardKey

  • __pairs - (Lua 5.2+) Handle iteration through table pairs when for k,v in pairs(tbl) do ... end is called (See GeneralizedPairsAndIpairs).
  • __ipairs - (Lua 5.2+) Handle iteration through table pairs when for k,v in ipairs(tbl) do ... end is called (See GeneralizedPairsAndIpairs).

Also KeyboardKey has some values in the documentation that don't exist in game like QuoteDBL

Maybe a function for getting the readable value of a keycode. I'm recreating a keybinding window for other mods to attach onto and set up binds that can be remapped by the end user.

Key pressed/released callbacks?

Edited by Bubbet

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)
function getRealBonuses(seed, rarity, permanent)
	local ok, plan = pcall(Plan)
	if not plan then return 0 end
	local transporterBlocks = plan:getBlocksByType(BlockType.Transporter)
	local transporterVolume = 0
	for k, v in pairs(transporterBlocks) do
		local block = plan:getBlock(v)
		transporterVolume = transporterVolume + length(block.box.size)
	end
	return transporterVolume
end
2021-03-17 18-31-03| T: 28
2021-03-17 18-31-03| Object: Unknown
2021-03-17 18-31-03| Execution Context (inner to outer):
2021-03-17 18-31-03| #0: makeTooltip data/scripts/systems/transportersoftware.lua
2021-03-17 18-31-03| 
2021-03-17 18-31-03| Error constructing Plan: component can only be created in context of a scene
2021-03-17 18-31-03| 
2021-03-17 18-31-03| stack traceback:
2021-03-17 18-31-03|     [C]:-1: in function ?
2021-03-17 18-31-03|     [C]:-1: in function pcall
2021-03-17 18-31-03|     C:\Users\Bubbet\AppData\Roaming\Avorion\mods\TransponderRangeFromBlocks\data/scripts/systems/transportersoftware.lua:4: in function getRealBonuses

A function for getting the current 'scene context' so i can stop this error from showing in the console/logs, considering pcall doesn't do that.

Edited by Bubbet

Share this post


Link to post
Share on other sites
  • 0

Got a late entry for 2.0 but maybe you can squeeze it in: Allowing mods to modify data/scripts/client/crafticons.lua for adding custom craft icons. Might be tough as it's only executed a handful of times before mods are loaded then never afterwards.

Share this post


Link to post
Share on other sites
  • 0
--Custom AI script.
package.path = package.path .. ";data/scripts/lib/?.lua"
include ("stringutility")
include ("randomext")

local targetEntity
local minDist = -1

--namespace PursuitAIScript
PursuitAIScript = {}

if onServer() then

    function PursuitAIScript.getUpdateInterval()
        --Per Koonschi, this needs to be run every single frame.
        return 0
    end

    function PursuitAIScript.initialize(...)
        --Immediately set the AI idle. PursuitAIScript will tell it how to behave instead of the default ship AI.
        local ship = Entity()
        local ai = ShipAI()
        local ctlUnit = ControlUnit()
        --print("PursuitAIScript AI successfully attached to " .. ship.name)

        ai:stop()
        ai:setIdle()
        for _, t in pairs({ship:getTurrets()}) do
            local xt = Turret(t)
            xt.group = 8
            local xw = Weapons(t)
            if xw.damageType ~= DamageType.Fragments and (xw.reach < minDist or minDist == -1) then
                minDist = xw.reach
            end
        end
        if minDist <= ship:getBoundingSphere().radius then
            --Make sure it is at least the bounding radius
            minDist = ship:getBoundingSphere().radius
        else
            --Make it a bit smaller than the minimum range to make sure we're always inside of it.
            minDist = math.max(ship:getBoundingSphere().radius, minDist - 200)
        end
        --print("minimum range is " .. minDist)
    end

    function PursuitAIScript.updateServer(timeStep)
        local ship = Entity()
        local ai = ShipAI()
        local ctlUnit = ControlUnit()
        local eng = Engine()

        for _, t in pairs({ship:getTurrets()}) do
            local xt = Turret(t)
            print("xt group is " .. tostring(xt.group))
        end

        if not targetEntity then
            local ships = {Sector():getEntitiesByType(EntityType.Ship)}
            local possibleTargets = {}
            for _,p in pairs(ships) do
                if ai:isEnemy(p) then
                    table.insert(possibleTargets, p)
                end
            end
            --print("PursuitAIScript AI picked " .. targetEntity.name .. " as a pursuit target.")
            targetEntity = possibleTargets[math.random(1, #possibleTargets)]
        end

        if targetEntity and valid(targetEntity) then
            --Set the aimed position of all the weapons in group 1.
            ctlUnit:setAimedPosition(targetEntity.translationf, 0)
            ctlUnit:setControlActions(ControlActionBit.Fire1, 0)
            ctlUnit:setKeyDownMask(ControlActionBit.Fire1, 0)
            --Use the AI to fly.
            local distanceToTarget = distance(targetEntity.translationf, ship.translationf)
            if distanceToTarget > minDist then
                --print("Distance to target is ... " .. distanceToTarget .. " desired is " .. minDist)
                ctlUnit:flyToLocation(targetEntity.translationf, eng.maxVelocity)
                --ai:setFlyLinear(targetEntity.translationf, minDist * 2, false)
            end
        else
            --print("PursuitAIScript AI lost track of its current target, and will pick a new one on its next update.")
            targetEntity = nil
        end
    end

end

So a while back, I was working on this custom AI script. The issue that I ran into was that it would only shoot at the exact position of the target ship, which would obviously only work for hitscan weapons like lightning guns, railguns, etc.

I had the idea to reassign weapons into different groups and control the position that the weapons were aiming based on that. However, when the first section of the script executes (that ostensibly sets all turret groups to group 8 ) there are no errors BUT executing the code immediately afterwards shows that the AI has reassigned all of the turrets to group 1 (or group 2 - I can't remember) which makes it impossible to group up turrets by a metric like projectile velocity.

It would be awesome if there was a way to hard stop the AI from attempting to reassign turret groups, especially while idle.

Be careful attaching this to a ship btw - it will spam messages like no tomorrow.

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

Oh yeah, it would be nice if we could get a way to flag a ship as not counting for a warzone (other than setting is_pirate / is_xsotan / is_persecutor) without having to mess with the warzone script ourselves. I'm not too stressed about this one, though.

Edited by Sathaerz

Share this post


Link to post
Share on other sites
  • 0
Posted (edited)

Sorry, I know I'm tossing in a lot of these but it would be awesome if we could have a way to bypass or remove the pauseTime in the event scheduler on a per-event basis. I added some events that have a % chance to simply terminate immediately and it causes a massive lack of events to happen due to incrementing the pauseTime.

I implemented my own event scheduler, but I don't want to have to maintain it every time you guys end up changing the event scheduler as well.

Ended up figuring out a better way to do this than completely reimplementing the event scheduler. Would still be a nice feature, though!

Edited by Sathaerz

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...