Page 1 of 1

amending ship scripts

Posted: Thu Nov 19, 2009 11:50 am
by Commander McLane
Is it possible to amend a ship script on the fly rather than replace it?

More specifically: If a ship has already let's say

Code: Select all

this.shipBeingAttacked = function()
{
     some code
     ...
}
in its script, can I somehow add

Code: Select all

{
     more code
     ...
}
without replacing and therefore deleting

Code: Select all

{
     some code
     ...
}
:?:

Posted: Thu Nov 19, 2009 11:55 am
by Thargoid
It sounds like a risky thing to do, unless you know exactly what each of the code sections are going to do. One may for example perform a return, or send the script to a different function, at which point the subsequent code would get ignored completely.

But if it were me I would probably copy the existing function into a new one (<scriptname>.shipBeingAttacked = <scriptname>.originalShipBeingAttacked or somesuch), add your code as newShipBeingAttacked and then replace the original function with one that simply calls the two new functions in turn.

Posted: Thu Nov 19, 2009 12:08 pm
by Kaks
This should more or less do what you asked:

Code: Select all

P.target.script.originalAttacked = P.target.script.beingAttacked;

P.target.script.beingAttacked = function(){

      new stuff

  this.originalAttacked();

      more new stuff

};
I'd check both name and version of the particular ship script to get some idea of what was inside the original beingAttacked() function.

Of course, name & version could be lies: as a general software thing, changing version numbers tends to be forgotten when making changes to the actual code.

Posted: Thu Nov 19, 2009 2:47 pm
by Eric Walch
That should work. But to be completely at the save side I would not use this.originalAttacked(); but this.mcLaneAttacked();, (or any other unique name) just for the case there was another oxp that already had changed the script and also used the name this.originalAttacked(); :lol:

Posted: Thu Nov 19, 2009 3:29 pm
by JensAyton
You can actually do this (it’s often called monkey patching) without adding a new property to the target, thus removing the risk of name conflicts:

Code: Select all

this.patchTarget = function()
{
    var originalAttacked = player.ship.target.beingAttacked;
    player.ship.target.beingAttacked = function()
    {
        // Do stuff
        originalAttacked();
    }
}
Or, more generally:

Code: Select all

this.applyHeadPatch = function(target, property, patch)
{
    var original = target[property];
    target[property] = function()
    {
        // Depending on what you’re doing you might want to swap the order,
        // in which case it’s a tail patch.
        
        patch.apply(this, arguments);
        original.apply(this, arguments);
    }
}
...
this.patchTarget = function()
{
    this.applyHeadPatch(player.target.script, "beingAttacked", function()
    {
        // Do stuff
    });
}
Documentation: Function.apply(), arguments

Oh, and don’t use P as a shortcut for player in scripts! It’s only defined when the debug console is in use.

Posted: Fri Nov 20, 2009 7:13 am
by Commander McLane
Thanks all! Will try how it works. And if it seems that it may break things, I will of course not use it.

What I want is to simulate a requested-but-not-yet-existing shipHittingOther event handler for an NPC by inserting a script line into the ship script of the opponent, which will call the shipHittingOther function when it gets hit itself, therefore I need to access the shipBeingAttacked function in the opponent's script, without completely overwriting it.

Posted: Thu Nov 26, 2009 8:16 am
by Commander McLane
Ahruman wrote:
You can actually do this (it’s often called monkey patching) without adding a new property to the target, thus removing the risk of name conflicts:

Code: Select all

this.patchTarget = function()
{
    var originalAttacked = player.ship.target.beingAttacked;
    player.ship.target.beingAttacked = function()
    {
        // Do stuff
        originalAttacked();
    }
}
Shouldn't that be

Code: Select all

this.patchTarget = function()
{
    var originalAttacked = player.ship.target.beingAttacked;
    player.ship.target.script.beingAttacked = function()
    {
        // Do stuff
        originalAttacked();
    }
}
?

Posted: Thu Nov 26, 2009 9:43 am
by Kaks
Nope! :P

It's actually more likely to work if it's

Code: Select all

this.patchTarget = function()
{
    var originalAttacked = player.ship.target.script.beingAttacked;
    player.ship.target.script.beingAttacked = function()
    {
        // Do stuff
       if (originalAttacked) originalAttacked();
    }
}
In the versions you & Ahruman wrote originalAttacked would always be undefined, and - thinking about it - some ships' scripts might not have a .beingAttacked function to begin with! ;)

Posted: Thu Nov 26, 2009 10:59 am
by Commander McLane
I had the problem with the undefined again, because I wanted to amend the world script shipWillDockWithStation from a ship script, when an escape pod was scooped. Of course originalShipWillDockWithStation was always undefined when I actually docked, because at this point the escape pod with the ship script had of course seized to exist. :shock: So I had to define worldScripts.personalities.originalShipWillDockWithStation, and now it's working fine.

By the way: this is quite a complicated workaround for giving a ship two different specific escape pods, which both have to be spawned. :roll:

Posted: Thu Nov 26, 2009 1:59 pm
by JensAyton
Commander McLane wrote:
I had the problem with the undefined again, because I wanted to amend the world script shipWillDockWithStation from a ship script, when an escape pod was scooped.
Wouldn’t it be easier to just have a world script check a condition and do what you need when it’s appropriate? You could then set a flag like:

Code: Select all

worldScripts["my-super-duper-script"].doInterestingStuff = true;
In general, patching should be your last resort, not your first. :-)

Posted: Thu Nov 26, 2009 2:33 pm
by Commander McLane
Generally I agree. But in this case a ship script of a personalities ship in set A has to access the world script, which will be shipped with the original OXP. While I of course could put it in the world script, I won't be able to do so with upcoming new sets of characters. I don't want to re-distribute the original OXP, because of a small change in its script.

But it will all stay in the family. I have no intention to amend something outside the personalities OXPs.