Scripters cove

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

Moderators: another_commander, winston

User avatar
Redspear
---- E L I T E ----
---- E L I T E ----
Posts: 2637
Joined: Thu Jun 20, 2013 10:22 pm

Re: Scripters cove

Post by Redspear »

OK so I'm almost certainly doing something stupid but here's the plan...

Upon ejecting, the player finds the replacement ship has several damaged pieces of equipment (assuming they were present on the original ship).
So, I need to:
  • activate the script once the player ejects
  • test for presence of undamaged equipment items that I wish to be affected
  • change condition of those items to damaged
I've attempted as much like so:

Code: Select all

this.shipLaunchedEscapePod = function()
{
	if (player.ship.equipmentStatus("EQ_ECM") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_ECM") = "EQUIPMENT_DAMAGED";}

	if (player.ship.equipmentStatus("EQ_FUEL_SCOOPS") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_FUEL_SCOOPS") = "EQUIPMENT_DAMAGED";}

	if (player.ship.equipmentStatus("EQ_ENERGY_UNIT") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_ENERGY_UNIT") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_DOCK_COMP") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_DOCK_COMP") = "EQUIPMENT_DAMAGED";}	
	
	if (player.ship.equipmentStatus("EQ_GAL_DRIVE") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_GAL_DRIVE") = "EQUIPMENT_DAMAGED";}	
	
	if (player.ship.equipmentStatus("EQ_SCANNER_SHOW_MISSILE_TARGET") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_SCANNER_SHOW_MISSILE_TARGET") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_MULTI_TARGET") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_MULTI_TARGET") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_ADVANCED_COMPASS") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_ADVANCED_COMPASS") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_ADVANCED_NAVIGATIONAL_ARRAY") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_ADVANCED_NAVIGATIONAL_ARRAY") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_TARGET_MEMORY") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_TARGET_MEMORY") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_INTEGRATED_TARGETING_SYSTEM") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_INTEGRATED_TARGETING_SYSTEM") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_SHIELD_BOOSTER") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_SHIELD_BOOSTER") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_NAVAL_SHIELD_BOOSTER") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_NAVAL_SHIELD_BOOSTER") = "EQUIPMENT_DAMAGED";}
	
	if (player.ship.equipmentStatus("EQ_WORMHOLE_SCANNER") == "EQUIPMENT_OK")
		{player.ship.setEquipmentStatus("EQ_WORMHOLE_SCANNER") = "EQUIPMENT_DAMAGED";}
		
}
No error reports but also no apparent effect.
Same (lack of) result using escapePodSequenceOver.

Can anyone please tell me where I'm going wrong? :?
User avatar
stranger
---- E L I T E ----
---- E L I T E ----
Posts: 351
Joined: Thu Apr 05, 2018 5:31 am
Location: Vladivostok, Russia

Re: Scripters cove

Post by stranger »

Techically you have no ship with ECM etc between ejecting escape pod and arrival to station. You need set equipment state after having new ship.
Try this approach like in my Hard Eject:

Code: Select all

this.shipLaunchedEscapePod = function()
    {
    this.$escapeFlag = 1;        // eject recorded
    }

this.shipDockedWithStation = function()
	{
    	if (this.$escapeFlag == 1)    // eject detected
		{
		// your code here
		this.$escapeFlag = 0;	// don't forget to reset escape flag!
		}
	}
User avatar
montana05
---- E L I T E ----
---- E L I T E ----
Posts: 1166
Joined: Mon May 30, 2016 3:54 am
Location: lurking in The Devils Triangle (G1)

Re: Scripters cove

Post by montana05 »

Maybe not what you are looking for but player.ship.takeInternalDamage(); is (randomly) damaging equipment as well.
Scars remind us where we've been. They don't have to dictate where we're going.
User avatar
Redspear
---- E L I T E ----
---- E L I T E ----
Posts: 2637
Joined: Thu Jun 20, 2013 10:22 pm

Re: Scripters cove

Post by Redspear »

montana05 wrote: Sat Jan 30, 2021 12:14 am
Maybe not what you are looking for but player.ship.takeInternalDamage(); is (randomly) damaging equipment as well.
Thanks but I think I might have solved it... (totally would have tried that 5 minutes ago :lol: )

stranger wrote: Fri Jan 29, 2021 11:57 pm
Techically you have no ship with ECM etc between ejecting escape pod and arrival to station. You need set equipment state after having new ship.
Try this approach like in my Hard Eject:
That was indeed part of the problem (although I would have thought that using escapePodSequenceOver would have prevented that being an issue) and resulted in error reports activating (at least the script was actually running!), so thanks for putting me on the right track.

Turns out that

Code: Select all

player.ship.setEquipmentStatus("EQ_ECM") = "EQUIPMENT_DAMAGED";
is bad form.


It should be

Code: Select all

player.ship.setEquipmentStatus("EQ_ECM", "EQUIPMENT_DAMAGED");
which worked a treat.

Thanks both :D
User avatar
tsoj
Deadly
Deadly
Posts: 199
Joined: Wed May 18, 2016 8:19 pm
Location: Berlin
Contact:

Re: Scripters cove

Post by tsoj »

A quick question: On the wiki there is an example on how to use station.shipyard:

Code: Select all

var ship_count = system.mainStation.shipyard.count;
I found that .count is undefined but .length works. Should I edit the wiki or am I missing something?
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4612
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

tsoj wrote: Tue Feb 16, 2021 2:46 pm
I found that .count is undefined but .length works. Should I edit the wiki or am I missing something?
Yep, looks like an oversight on my part. Please update the wiki when you get a chance.
User avatar
tsoj
Deadly
Deadly
Posts: 199
Joined: Wed May 18, 2016 8:19 pm
Location: Berlin
Contact:

Re: Scripters cove

Post by tsoj »

I had the idea to write and OXP that balances the ship price based on its properties (something close to this). I've run into a small and a big issue.

The small issue is that when I get a ship from the shipyard I only get the shipdata.plist info about the ship. Because I need the mass of a ship I temporarily create a ship with ship = system.addShips("["+shipdataKey+"]", 1, Vector3D(100000000, 0, 0))[0]; and then delete it afterwards ship.remove(true);.
This seems pretty inelegant, I couldn't think of a better solution though, but maybe someone else can.

The bigger issue where I haven't found a workaround yet is, that I need to change the price of the player-ship. I've only found the javascript read-only variable price, but I took a peak at the source code, and it doesn't seem like there is a trivial solution.
Maybe having a callback that gets called when the tradeInValue function gets executed so that one can give an alternative calculation of the tradeInValue that replaces the default calculation? Is something like this even possible?
I couldn't think of any workaround that comes without big issues. For example, re-awarding credits or taking credits away after a ship purchase, could cause a negative credit score or that I couldn't buy a ship, even though my adjusted trade-in value is enough.
Last edited by tsoj on Thu Feb 18, 2021 1:48 am, edited 1 time in total.
User avatar
montana05
---- E L I T E ----
---- E L I T E ----
Posts: 1166
Joined: Mon May 30, 2016 3:54 am
Location: lurking in The Devils Triangle (G1)

Re: Scripters cove

Post by montana05 »

You can get the mass with ship.mass for the prices I can suggest removeShipFromShipyard and addShipToShipyard, I never tried o modify the price of a ship with that but it might be worth a look.
Scars remind us where we've been. They don't have to dictate where we're going.
User avatar
tsoj
Deadly
Deadly
Posts: 199
Joined: Wed May 18, 2016 8:19 pm
Location: Berlin
Contact:

Re: Scripters cove

Post by tsoj »

montana05 wrote: Thu Feb 18, 2021 12:53 am
You can get the mass with ship.mass for the prices I can suggest removeShipFromShipyard and addShipToShipyard
Yes, that is actually my plan :). It seems to work, if I buy a ship from the shipyard I have to pay the adjusted price. Now, additionally to the already mentioned problems I found another issue: ship.canAwardEquipment returns often true, even though in the shipyard it says that it can't be added to the ship. Is the equipment list in shipyard.plist only applicable to the player-ship?

Anyway, if anybody dares to look at some questionable JavaScript code: https://gitlab.com/tsoj/oolite_balancedshipprices (very much still WIP)
User avatar
montana05
---- E L I T E ----
---- E L I T E ----
Posts: 1166
Joined: Mon May 30, 2016 3:54 am
Location: lurking in The Devils Triangle (G1)

Re: Scripters cove

Post by montana05 »

tsoj wrote: Thu Feb 18, 2021 1:47 am
I found another issue: ship.canAwardEquipment returns often true, even though in the shipyard it says that it can't be added to the ship. Is the equipment list in shipyard.plist only applicable to the player-ship?
Not sure about that, a first wild guess would be that there might be a condition-script attached to the equipment.
Scars remind us where we've been. They don't have to dictate where we're going.
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4612
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

tsoj wrote: Thu Feb 18, 2021 1:47 am
Is the equipment list in shipyard.plist only applicable to the player-ship?
Given that the shipyard file defines ships that can be purchased by the player, yes, it's only applicable to player ships. You theoretically can't have a player ship without a shipyard.plist entry.
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4612
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

tsoj wrote: Thu Feb 18, 2021 1:47 am
Anyway, if anybody dares to look at some questionable JavaScript code
I found that with player ship definitions, at least for core equipment, it's better to try something like this:

Code: Select all

   var myShipDef = Ship.shipDataForKey("ship_data_key");
   var equipKey = "EQ_FUEL_SCOOPS";
   var found = "N/A";
   if (!myShipDef._oo_shipyard) found = "Data error - no shipyard entry found on ship definition";
   if (found === "N/A" && myShipDef._oo_shipyard.standard_equipment.extras && myShipDef._oo_shipyard.standard_equipment.extras.indexOf(equipKey) >= 0) found = "Standard";
   if (found === "N/A" && myShipDef._oo_shipyard.optional_equipment && myShipDef._oo_shipyard.optional_equipment.indexOf(equipKey) >= 0) found = "Optional";
That avoids the need to actually create a ship of that type just so you can try the ship.canAwardEquipment function.
User avatar
tsoj
Deadly
Deadly
Posts: 199
Joined: Wed May 18, 2016 8:19 pm
Location: Berlin
Contact:

Re: Scripters cove

Post by tsoj »

EDIT: I created a git pull request
---------------------------------------
What would you think about a function like Ship.shipDataForKey but like this: function setShipDataForKey(datakey : String, newShipData : Object)?

Unfortunately I didn't manage to compile Oolite on my machine and I also don't really know Obj-C, but I thought about these changes in the code:

Adding to OOShipRegistry.m (and to the respective header file):

Code: Select all

- (void) setShipInfoForKey:(NSString *)key with:(NSDictionary *)newShipData
{
	[_shipData release];
	_shipData = OODeepCopy(newShipData);
	/* EDIT: ^this would be a bug, I meant to only change the shipData for a specific key.
	But I'm not sure how to do it, does "objectForKey" return a pointer to
	the NSDisctionary in _shipData or to a copy? if it returns a pointer to the original data, maybe we could do
	it like this:*/
	[[_shipData objectForKey:key] release];
	[_shipData objectForKey:key] = OODeepCopy(newShipData);
}
----------------------------------------------------

And in OOJSShip.m:

Add this

Code: Select all

static JSBool ShipStaticSetShipDataForKey(JSContext *context, uintN argc, jsval *vp); 
here

----------------------------------------------------

Add this

Code: Select all

{ "setShipDataForKey",	ShipStaticSetShipDataForKey,	2 },
here

-----------------------------------------------------

And add this at the bottom of the file:

Code: Select all

static JSBool ShipStaticSetShipDataForKey(JSContext *context, uintN argc, jsval *vp)
{
	OOJS_NATIVE_ENTER(context);
	OOShipRegistry			*registry = [OOShipRegistry sharedRegistry];

	if (argc >= 2)
	{
		NSString *key = OOStringFromJSValue(context, OOJS_ARGV[0]);
		NSDictionary *newShipData = OOJSNativeObjectFromJSObject(context, JSVAL_TO_OBJECT(OOJS_ARGV[1]));
		[registry setShipInfoForKey:key with:newShipData]
		OOJS_RETURN_BOOL(YES);	
	}
	else
	{
		OOJSReportBadArguments(context, @"Ship", @"setShipInfoForKey", MIN(argc, 2U), OOJS_ARGV, nil, @"ship role");
		return NO;
	}
	OOJS_NATIVE_EXIT
}
User avatar
Phasted
Competent
Competent
Posts: 51
Joined: Wed Jun 09, 2010 3:56 pm

Re: Scripters cove

Post by Phasted »

Say, here's a brain-tickler: My world-script needs to create a timer on a ship (station) script... Do I leave the this parameter as-is, referring to the world-script or should I change it to station.script?
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4612
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

If the script that is starting the timer runs through a worldScript function, and you are happy with there only being one timer in play, this is fine.

For example:

Code: Select all

this.startUpComplete = function() {
  // in this instance "this" refers to the current worldScript
  this._myTimer = new Timer(this, this.$myTimerFunction, 1, 1);
}

this.$myTimerFunction = function $myTimerFunction() {
  // ...do stuff...
}
If, however, you want a separate timer per station, you can still refer to this, but you would have to add your scripts to the ship script of the station.

For example, to :

Code: Select all

this.startUpComplete = function() {
  // find the station you want to attach your script to
  var stations = system.stations;
  for (var i = 0; i < stations.length; i++) {
    if (stations[i].{property} == {value} { // you'd put in whatever criteria here that would allow you to identify the correct station.
      // found it!
      stations[i].script.$myTimerFunction = this.$myTimerFunction;
      stations[i].script.$myTimerStarter = this.$myTimerStarter;
      stations[i].script.$myTimerStarter();
    }
  }
}

this.$myTimerStarter = function $myTimerStarter() {
  // in this instance, "this" refers to the stations ship script
  this._myTimer = new Timer(this, this.$myTimerFunction, 1, 1);
}

this.$myTimerFunction = function $myTimerFunction() {
  // ...do stuff...
}
Post Reply