Join us at the Oolite Anniversary Party -- London, 7th July 2024, 1pm
More details in this thread.

Scripters cove

Discussion and information relevant to creating special missions, new ships, skins etc.

Moderators: winston, another_commander

User avatar
Diziet Sma
---- E L I T E ----
---- E L I T E ----
Posts: 6311
Joined: Mon Apr 06, 2009 12:20 pm
Location: Aboard the Pitviper S.E. "Blackwidow"

Re: Scripters cove

Post by Diziet Sma »

Thanks! I'll see what I can cobble together.
Most games have some sort of paddling-pool-and-water-wings beginning to ease you in: Oolite takes the rather more Darwinian approach of heaving you straight into the ocean, often with a brick or two in your pockets for luck. ~ Disembodied
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4755
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

Is there a way using JS to tell if a new game has just been started?
User avatar
Wildeblood
---- E L I T E ----
---- E L I T E ----
Posts: 2321
Joined: Sat Jun 11, 2011 6:07 am
Location: Western Australia

Re: Scripters cove

Post by Wildeblood »

phkb wrote:
Is there a way using JS to tell if a new game has just been started?
Context - why would you care?
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4755
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

I'd like to send an email to the player telling about their purchase of their ship.
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Scripters cove

Post by cim »

phkb wrote:
Is there a way using JS to tell if a new game has just been started?
Not strictly, no - the routine to load a saved game and the routine to start a new scenario differ only in which directory they get the oolite-save file from.

You can probably make a fair guess by looking at the clock, but I don't guarantee to take care to preserve that to the second between Oolite versions. (To the day, probably - if the day is 2084004, and you haven't already delivered that email, you can safely do so)
User avatar
Smivs
Retired Assassin
Retired Assassin
Posts: 8408
Joined: Tue Feb 09, 2010 11:31 am
Location: Lost in space
Contact:

Re: Scripters cove

Post by Smivs »

phkb wrote:
I'd like to send an email to the player telling about their purchase of their ship.
Then you can spam them with market research surveys, customer satisfaction questionaires and offers linked to the purchase. And they'll probably need reminding to leave Feedback!
Commander Smivs, the friendliest Gourd this side of Riedquat.
User avatar
Wildeblood
---- E L I T E ----
---- E L I T E ----
Posts: 2321
Joined: Sat Jun 11, 2011 6:07 am
Location: Western Australia

Re: Scripters cove

Post by Wildeblood »

Clock won't be reliable if scenarios catch on with OXPers. Folk won't always start with a new Jameson to create their oolite-save files. More likely the'll use an old one and just delete the mission variables; it wouldn't occur to me to reset the clock, and if it did why should all scenarios start at the same time?
User avatar
spara
---- E L I T E ----
---- E L I T E ----
Posts: 2676
Joined: Wed Aug 15, 2012 4:19 am
Location: Finland

Re: Scripters cove

Post by spara »

I'm trying to get my head around these new docking toys. I managed to create a highly restricted station that allows the player to dock only if specifically allowed. And player actually crashes, if he/she tries to dock without permission. However, getting disallowedDockingCollides to work was a bit of a pain as I first need to set allowsDocking to false. To my understanding that affects possible NPCs too. I'm wondering what happens, if the station launches a defense ship that tries to dock later if allowsDocking is set to false.

Is there a way to set a station to disallowedDockingCollides so that all ships without docking permission would collide? A shipdata property disallowed_docking_collides would be nice :mrgreen: .
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Scripters cove

Post by cim »

Wildeblood wrote:
Clock won't be reliable if scenarios catch on with OXPers. Folk won't always start with a new Jameson to create their oolite-save files. More likely the'll use an old one and just delete the mission variables; it wouldn't occur to me to reset the clock, and if it did why should all scenarios start at the same time?
Given that scenarios may not even allow the email OXP to load in the first place, and even if they do might have their own ideas for what initial emails the player should get - "Congratulations on your recent theft of this Boa Freighter" - that's probably more a feature than a bug if the OXP has to have specific checks for each separate scenario.
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Scripters cove

Post by cim »

spara wrote:
Is there a way to set a station to disallowedDockingCollides so that all ships without docking permission would collide? A shipdata property disallowed_docking_collides would be nice :mrgreen: .
allowsDocking false is really intended for situations like "this is a launch-only dock with some sort of high-speed launch catapult, and you're not getting your ship back in there" or "you could dock here, but not while the bay doors are closed"

I could set it up so that per-ship rejection on the dock through a method parallel to acceptDockingRequestFrom would have disallowedDockingCollides apply in that case, but that would need re-testing every frame. (That's probably acceptable as the method shouldn't be particularly intensive)
User avatar
spara
---- E L I T E ----
---- E L I T E ----
Posts: 2676
Joined: Wed Aug 15, 2012 4:19 am
Location: Finland

Re: Scripters cove

Post by spara »

cim wrote:
spara wrote:
Is there a way to set a station to disallowedDockingCollides so that all ships without docking permission would collide? A shipdata property disallowed_docking_collides would be nice :mrgreen: .
allowsDocking false is really intended for situations like "this is a launch-only dock with some sort of high-speed launch catapult, and you're not getting your ship back in there" or "you could dock here, but not while the bay doors are closed"

I could set it up so that per-ship rejection on the dock through a method parallel to acceptDockingRequestFrom would have disallowedDockingCollides apply in that case, but that would need re-testing every frame. (That's probably acceptable as the method shouldn't be particularly intensive)
A game mechanic change of crashing the player when docking without permission instead of fining would be an interesting one :twisted: .

Anyway, I solved my little problem of conditionally offering higher TL services with a simple mission screen override so I'm happy with the current status quo.
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4755
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

I'm still working on my little rename ship tweak (talked about here), but I'm going into bits of Oolite I have no experience with whatsoever.

In case your wondering, I'm trying to add some purpose to the process of renaming your ship, and giving the player the opportunity to use this strategically. Rename the ship (with a small cost), and potentially confuse any assassins waiting for you at the end of the witchspace tunnel. cim suggested a method of just overwriting the players roles, which I am testing as well, but (I think I'm correct in saying) this method would only work if the player is not carrying any parcels. If the assassins are after the player with a parcel, this wouldn't do anything.

So, my blunt force method, is to attach a JS script to any assassins in view when the player exits the wormhole. The script file has the following code in it:

Code: Select all

// if the ship targets the player, potentially untarget them
this.shipTargetAcquired = function(target) {
	if (this._debug) log(this.name, "target acquired");
	var w = worldScripts.RenameShipTweak;
	if (target == player.ship && w._confusionActive == true && this._disable == false) {
		if (this._debug) log(this.name, "player ship targetted");
		if (Math.random() < (1 / w._chanceOfSuccess)) {
			this._retarget = true;
			this.ship.target = null;
			if (w._confusedMessageSent == false) {
				log(this.name, "sending confused message");
				this.ship.commsMessage(expandDescription("[confused-message]", {shipname:w._storedShipName}), player.ship);
				w._confusedMessageSent = true;
			}
		}
	}
}
Essentially, if the ship's target is the player, and our confusion process is in operation, and the player hasn't done anything silly like attack the ship (which would set the "this._disable" to true, then we get into the nuts and bolts of the confusion. The "chanceOfSuccess" is 1 the first time the player renames the ship - this results in a 100% chance that the assassin will become confused. We then set the ship's target to null to clear their target. They just became confused. The ship might then send a message out, saying to keep looking for the original ship name.

Now, this code works. Player is targeted, ship is confused, and they un-target the player, message goes out, all is well.

Except I get this error:

Code: Select all

13:53:41.072 [script.javaScript.exception.unexpectedType]: ***** JavaScript exception (Oolite Assassin AI 1.80): TypeError: this.ship.target is null
13:53:41.072 [script.javaScript.exception.unexpectedType]:       Resources/Scripts/oolite-priorityai.js, line 2767.
Which is not in my code at all, but in the default libraries. From what I can understand, because I've set the ship's target to null in the "shipTargetAcquired", there's a flowon impact in the core code.

So, I'm guessing that the "shipTargetAcquired" is the wrong place to set the ship's target to null. Is there a better place to do this? Should I do something a little more adventurous (and scary) with the AI stuff? I'm a little lost here!
User avatar
cim
Quite Grand Sub-Admiral
Quite Grand Sub-Admiral
Posts: 4072
Joined: Fri Nov 11, 2011 6:19 pm

Re: Scripters cove

Post by cim »

So what's happening here is that the AI routine will have something like this:

Code: Select all

this.ship.target = nearbySuitableTarget;
// later...
if (this.ship.target.property == something) {
It doesn't expect anything to have updated this.ship.target in between selecting it and trying to use it, so it doesn't check if it's still defined.

The easiest way to do it is probably to override conditionScannerContainsCourier in the ship AIs. Currently it's this:

Code: Select all

PriorityAIController.prototype.conditionScannerContainsCourier = function()
{
	return (this.checkScannerWithPredicate(function(s) { 
		return (this.shipInRoleCategory(s,"oolite-courier")) || (s.isPlayer && this.shipHasRiskyContracts(s));
	}));
}
by doing something like

Code: Select all

ship.AIScript.oolite_priorityai.conditionScannerContainsCourier = function() {  
        return (this.checkScannerWithPredicate(function(s) { 
		if (s.isPlayer) {
			// do the "recently renamed" checks here, return false if is ignoring the player
			// this also means that the assassins will go after another courier instead if one happens to be about
		}
		return (this.shipInRoleCategory(s,"oolite-courier")) || (s.isPlayer && this.shipHasRiskyContracts(s));
	}));
}
(Note that overriding core AI methods like this is possible and even encouraged, but should be carefully documented on your OXP's page so that OXPs which require the core behaviour for an AI method can use appropriate methods - including if necessary declaring incompatibility at the manifest level - to coexist)

One of the other problems - even if the log error didn't occur - with using shipTargetAcquired and then breaking the lock, is that this will trigger an almost immediate reevaluation of the AI's priorities (as always happens when they lose primary target). Since probably nothing material has changed, they will then attempt again to target the player... If w._chanceOfSuccess is even slightly greater than 1, this will mean that within seconds they realise their mistake.
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4755
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

Thanks cim. That helps a lot.
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4755
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

Cim, I'm really sorry. I'm a programmer and I should be able to work this out, but I mustn't have enough caffeine in my system, or I've eaten too many dark side cookies, or something, because I can't work this out.

So, I need to override conditionScannerContainsCourier - I created a JS file with my code in it, put it in the Scripts folder, then for each assassin at the witchpoint I tried ship.setScript("assassin-confused.js");. I get this error:

Code: Select all

17:28:51.434 [script.javaScript.load.failed]: ***** Error loading JavaScript script ../AddOns/RenameShipTweak.oxp/Scripts/assassin-confused.js -- could not run script
17:28:51.561 [script.javaScript.exception.unexpectedType]: ***** JavaScript exception (RenameShipTweak 1.0.0): TypeError: ship.AIScript.oolite_priorityai is undefined
I tried a number of combinations of ship.AIScript.oolite_priorityai.conditionScannerContainsCourier = function() trying to get it to work, including (but not limited to):

Code: Select all

this.ship.AIScript.oolite_priorityai.conditionScannerContainsCourier
this.AIScript.oolite_libpriorityai.conditionScannerContainsCourier (for this one, the error was "this.AIScript is undefined")
ship.AIScript.PriorityAIController.conditionScannerContainsCourier
ship.AIScript["oolite-libPriorityAI"].conditionScannerContainsCourier
ship.AIScript.oolite_priorityAI.conditionScannerContainsCourier
ship.AIScript["Oolite Assassin AI"].conditionScannerContainsCourier
Then I had a lightbulb moment and thought, what if I've been setting the script the wrong way? Yes, there is a setAI method! So I moved my script file to the AIs folder, and tried again.

Code: Select all

19:16:43.227 [script.javaScript.exception.unexpectedType]: ***** JavaScript exception (RenameShipTweak 1.0.0): TypeError: ship.AIScript.oolite_priorityai is undefined
So, I've run out of ideas and really need some pointers. I guess, to summarise, I need to know these things: (1) Do I use the setAI or setScript method on the assassin ships? (2) Does my script need anything other than my overridden function in it? For instance, do I need a this.aiStarted = function() if I load it via setAI? (3) Have I missed anything obvious? (Actually, I think that's a given - feel free to answer that one or not!).
Post Reply