LittleBear: yes, you could do that, but it’s rather inflexible. For instance, you couldn’t have more than one script extending HOopy that way. Cmdr. Maegil’s question suggested, to me, a need for greater flexibility.
Anyway, here’s a pair of scripts (currently only usable on my computer, but hey) which implement a client-server model. Any number of “client” scripts can register with the “server”, which can then call the client scripts to, well, do whatever needs to be done. In this case, to select mission screen contents and choices. (Actually, the ability to do this is somewhat limited since choices can still only be set by a missiontext.plist key. Hmm.)
This is somewhat more programmerese-intensive JavaScript than you’re likely to need for typical mission script ports. There are ostensibly similar, but clunkier, ways of achieving the same thing. Fortunately, it’s copy-and-pasteable; just copy-and-paste everything except the last two testing methods and *poof*!, your script is a server.
Incidentally, this is quite similar to the technique I outlined earlier for the racing OXP, except there a ship would be the server.
Server script template:Code: Select all
this.name = "ahruman-test-server"
this.version = "1.0"
this.scriptRegistry = [] // empty array
// Add a script to the registry. Each client script should register itself this way.
this.registerScript = function(script)
{
if (script)
{
// Add script to scriptRegistry
this.scriptRegistry.push(script)
}
}
// Returns an array of the registered scripts.
this.registeredScripts = function()
{
return this.scriptRegistry
}
/* Calls the method "methodName" on each script, with arbitrary arguments.
Example: serverScript.callScripts("doSomething", 1, 3)
Calls doSomething(1, 3) on each registered script
which has a doSomething() method.
*/
this.callScripts = function(methodName)
{
/* Create an array variable based on the special variable "arguments",
which contains all the arguments (parameters) of the current function.
arguments looks like an Array, but it isn't. In particular, it doesn't
have the slice() method we'd otherwise use to get all but the first
element. (We want to remove the first element because that's the same
as methodNames, and we don't want to pass that to the script method.
*/
let methodArgs = []
for (let i = 1; i < arguments.length; i++)
{
methodArgs.push(arguments[i])
}
// Function which will be called for each script by forEach
function callScriptOn(script)
{
// If the script has a property called methodName...
if (script[methodName] != undefined)
{
let method = script[methodName]
// ...and the property is actually a method...
if (typeof method == "function")
{
// ...call method with object as "this" and the arguments.
method.apply(script, methodArgs)
}
}
}
// Apply callScriptOn() to all elements of scriptRegistry.
scriptRegistry.forEach(callScriptOn, this)
}
// For testing purposes, call script methods each time the player launches or docks.
this.didDock = function()
{
this.callScripts("testDockCallback", 42)
}
this.didLaunch = function()
{
this.callScripts("testLaunchCallback", "banana")
}
Example client scriptCode: Select all
this.name = "ahruman-test-client"
this.version = "1.0"
this.startUp = function()
{
if (worldScripts["ahruman-test-server"] != undefined)
{
// Server script is installed, register.
let server = worldScripts["ahruman-test-server"]
this.setUpClientMethods()
server.registerScript(this)
}
// Conserve memory by not keeping functions around that won't be called again.
delete this.startUp
delete this.setUpClientMethods
}
this.setUpClientMethods = function()
{
// Set up the methods the server will call.
this.testDockCallback = function(number)
{
LogWithClass("clientServerTest.dock", "The server tells me the player docked at docking slot " + number + ".")
}
this.testLaunchCallback = function(fruit)
{
LogWithClass("clientServerTest.launch", "The server tells me the player launched. The in-flight snack will be " + fruit + ".")
}
}