Page 60 of 118

Re: Scripters cove

Posted: Sat Jan 26, 2013 9:25 pm
by Thargoid
I wonder if it is a bad interaction between the condition script and the requires setup. Try temporarily removing the condition script and see if the equipment appears for sale. If so you may need to move the equipment requirements also into the script.

I haven't yet tried the condition script in my OXPs but it could be that the two restrictions are interfering with one another.

Re: Scripters cove

Posted: Sat Jan 26, 2013 9:31 pm
by cim
The problem is that passenger berths are not equipment in the same way as every other piece of equipment in the game, and are never considered to be present by the requires_equipment checks.

Since you have a condition script anyway, the simplest workaround is probably to remove the check from requires_equipment, and check for it in the condition script instead.

Code: Select all

this.allowAwardEquipment = function(eqKey, ship, context) {
   if (eqKey == "EQ_IN_SYSTEM_TAXI_LICENCE" && player.ship.passengerCapacity == 0)
      return false;
   if (player.ship.dockedStation.hasRole("taxi_station"))
      return true;
   else return false;
}

Re: Scripters cove

Posted: Sat Jan 26, 2013 9:41 pm
by spara
Thanks, that's the way to go then.

Re: Scripters cove

Posted: Wed Jan 30, 2013 9:49 am
by JazHaz
I'm trying to make an equipment item, and have made an equipment.plist. However it's not appearing in the game. Not getting any errors in my log. The only thing I can think of being wrong is the EQ entry. Can I make up my own EQ names?

Note for testing purposes I have dropped the tech level and price.

Code: Select all

(
   (
      1,
      100000,
      "Behemoth Base Lease",
      "EQ_BEHEMOTH_BASE_LEASE",
      "Lease of a Behemoth from the Navy",
       {
          "available_to_NPCs" = no;
		  "available_to_player" = yes;
		  "isPortableBetweenShips" = true;
       }
    )
)

Re: Scripters cove

Posted: Wed Jan 30, 2013 10:13 am
by Commander McLane
Your missing the available_to_all key. Without it, you'd have to define it as an optional equipment in your current ship's shipyard.plist (and in all other ships' shipyard.plist).

Re: Scripters cove

Posted: Wed Jan 30, 2013 11:55 am
by JazHaz
Ah thanks. I was wondering about that key.

Re: Scripters cove

Posted: Wed Jan 30, 2013 9:56 pm
by spara
I want to check if certain key exists in a descriptions.plist. At the moment I'm doing something like this:

Code: Select all

var key = expandDescription("[foo]");
if (key == "[foo]") 
//key not found
Not exactly a clean solution, :D as using expandDescription seems to thrown a JS warning. Is there some nice elegant way to do this check?

Behaviour of the Timer

Posted: Thu Jan 31, 2013 5:33 am
by GGShinobi
Hi all,

I modified my copy of the [wiki]Imperial Star Destroyer[/wiki]. I gave it 4 Thargoid Lasers, made it much more robust and less agile and so on :twisted: I am now also trying to give the Star Destroyer a chance of becoming a big explosion when it get's destroyed, by placing a Q-Bomb (or more precisely: a ship with role "energy-bomb") at it's last position. But the Q-Bomb I add doesn't detonate, although my Q-Mine-Detector raises an alarm. So I thought to myself " :roll: hmm, maybe the Q-Bomb gets instantly destroyed by the explosion of the Star Destroyer? :?: Let's add it after a short delay, so the explosion has run off!"

But placing a timer inside the script for the Star Destroyer (I called it's this.name = "stardestroyer") didn't work, so I thought that is because the ship is destroyed and with it the timer get's removed.

So I changed the code and moved the timing functionality into a new world script (this.name = "stardestroyer_worldscript". I wanted to add only a single function, so I made it that the Timer calls the same function that created him again, but with a different parameter. Here is the code:

stardestroyer, which is the script = "stardestroyer.js" from shipdata.plist:

Code: Select all

this.name           = "stardestroyer";
this.author         = "GGShinobi";
this.copyright      = "© 2013 GGShinobi, Creative Commons: attribution, non-commercial, sharealike.";
this.description    = "some special actions for the stardestroyer.";
this.version        = "0.0.0";
"use strict";

this.shipDied = function(whom, why) {
  // if (Math.random() > 0.77) {
    worldScripts.stardestroyer_worldscript.$starDestroyer_BigBang(this.ship.position, 5); //3.33);
  // }
}
Note that this calls "$starDestroyer_BigBang" with countdown = 5.

stardestroyer_worldscript:

Code: Select all

this.name           = "stardestroyer_worldscript";
this.author         = "GGShinobi";
this.copyright      = "© 2013 GGShinobi, Creative Commons: attribution, non-commercial, sharealike.";
this.description    = "some special actions for the stardestroyer.";
this.version        = "0.0.0";
"use strict";

this.$selfDestructCountdown;
this.$starDestroyer_BigBang = function(position, countdown) {
log("Star Destroyer", "starDestroyer_BigBang called: position" + position + " / countdown: " + countdown);
  if (countdown > 0) {
    player.commsMessage("detonation in " + countdown + " seconds!");
    this.$selfDestructCountdown = new Timer(this, $starDestroyer_BigBang(position, 0), countdown);
  } else {
    player.commsMessage("Warning! Explosion detected!");
    system.addShips("energy-bomb", 1, position, 0);
    // system.addShips("EQ_QC_MINE", 1, this.ship.position, 0);
    this.$selfDestructCountdown.stop(); this.$selfDestructCountdown.delete();
  }
}
Note that this creates a timer which is supposed to call "$starDestroyer_BigBang" again after 5 seconds (countdown), but this time with countdown = 0!

But, from my logfiles I get this:

Code: Select all

05:58:22.015 [Star Destroyer]: starDestroyer_BigBang called: position(39892, -85261.1, 456021) / countdown: 5
05:58:22.015 [Star Destroyer]: starDestroyer_BigBang called: position(39892, -85261.1, 456021) / countdown: 0
05:58:22.033 [script.javaScript.exception.unexpectedType]: ***** JavaScript exception (stardestroyer 0.0.0): TypeError: this.$selfDestructCountdown is undefined
05:58:22.033 [script.javaScript.exception.unexpectedType]:       /home/ggshinobi/.Oolite/AddOns/stardestroyerV1.3.oxp/Scripts/stardestroyer_worldscript.js, line 18.
As you can see, the second call to "$starDestroyer_BigBang", which I intended to be made after a delay of 5 seconds, is instead be done instantly, when the Timer is created!

Is this behaviour intentionally or a bug? I thought the function call that is given as parameter to the timer is called for the first time after the delay has passed... :?:

Also, did you notice any other errors or wrong assumptions I've made? :?:

What I'm gonna test next is if it works when I move the timer creation to another function.

Re: Scripters cove

Posted: Thu Jan 31, 2013 6:39 am
by Wildeblood
The problem could be that timebombAI isn't being started. It expects to be launched from a ship, not instantiated out of nothing. But perhaps not, I don't know anything about the AIs. Anyway, make sure you know what you need to do to make timebombAI start and detonate correctly, before you start to write any script. It certainly shouldn't need both world and ship scripts.

Re: Scripters cove

Posted: Thu Jan 31, 2013 7:03 am
by Thargoid
Unfortunately the second script has several errors in it, mainly that it's structure isn't correct. The structure should be the function name as the definition line (the this.myFunctionName = function(myParameters) part) with the actual code making up that function within the {} braces. You can see the structure in the first script (ignoring for a moment that part of it is commented out, presumably to temporarily disable the randomness for testing purposes) with the function being used being this.shipDied and the code to be run just below it.

You can see however that the second script (the worldScript) doesn't use that structure, hence the error that the function you're trying to set up isn't defined.

But anyway, you don't need the worldscript at all to do this. An energy bomb action is usually done via the AI command becomeEnergyBlast, so you need to either spawn a suitable entity (an energy bomb) or switch the ships AI to that of such a bomb. In this case as you're trying to make the action happen on death, the second action won't work as of course it will be dead and removed before the AI actions can fully take effect.

So the simplest way is to take your initial script, and adjust it to

Code: Select all

this.shipDied = function(whom, why) {
   if (Math.random() > 0.77) {
      this.ship.spawn("energy-bomb",1);
   }
where energy-bomb is one of the roles of the trunk q-bomb. Use that function definition to replace the one in your first script, keeping the header information (this.name etc) from your code above.

However here I would also say that personally I find such actions very annoying, and with a chance of 77% any such ship would get swiftly removed from my ooniverse. There used to be another OXP ship (whose name I forget as it's a long while ago) which tended to become a cascade explosion when shot up, and it extremely quickly became frustrating as the clouds and devastation were too common and screwed with gameplay by destroying too much of the system infrastructure. It very quickly went into the bit-bucket...[/color]

Re: Scripters cove

Posted: Thu Jan 31, 2013 7:49 am
by Eric Walch
Thargoid wrote:
....any such ship would get swiftly removed from my ooniverse. There used to be another OXP ship (whose name I forget as it's a long while ago) which tended to become a cascade explosion when shot up, and it extremely quickly became frustrating as the clouds and devastation were too common and screwed with gameplay by destroying too much of the system infrastructure. It very quickly went into the bit-bucket...
Purple Haze probably. I removed the code lines from the script. Without knowing how to do, I probably would have eradicated the ship also from my universe. But, the main problem was there probably that there was no delay, so you has no chance of getting into safety. Yesterday, it just happened that a random hits target turned 'blue'. There I did escape and it stays fun. A good delay timer in combination with a warning (message or a blinking mine lolipop) may help to not delete the oxp a.s.a.p. :)

Re: Scripters cove

Posted: Thu Jan 31, 2013 8:13 am
by GGShinobi
Thanks Wildeblood and Thargoid for your answers and the solution, I will try that! But I still don't understand what's going on:
Thargoid wrote:
You can see however that the second script (the worldScript) doesn't use that structure, hence the error that the function you're trying to set up isn't defined.


this.$selfDestructCountdown is not a function, but a global variable.. at least that's what I intended. :?

Maybe I'm wrong, but I understand that the cause for the error message
this.$selfDestructCountdown is undefined
is as follows:
  • upon dying, the ship calls
    worldScripts.stardestroyer_worldscript.$starDestroyer_BigBang(this.ship.position, 5);
    This call succeeds, as you can see from the output
    05:58:22.015 [Star Destroyer]: starDestroyer_BigBang called: position(39892, -85261.1, 456021) / countdown: 5
  • inside $starDestroyer_BigBang, the test if (countdown > 0) succeds, therefore
    this.$selfDestructCountdown = new Timer(this, $starDestroyer_BigBang(position, 0), countdown);
    is executed, meaning the variable is being assigned a new Timer.
  • Mysteriously, the function specified inside the timer is called immediately and not, as I intended, after 5 seconds. You can see that from this output:
    05:58:22.015 [Star Destroyer]: starDestroyer_BigBang called: position(39892, -85261.1, 456021) / countdown: 0
    which shows that the timestamp is the same as the one from the previous call.
  • this second call to $starDestroyer_BigBang has countdown == 0 as parameter, therefore the test fails and the else-branch is being executed. This includes the cleanUp for the timer:
    this.$selfDestructCountdown.stop(); this.$selfDestructCountdown.delete();
  • then, for some other mysterious reason, a few moments later, something else tries to use the variable / the Timer, but it has already been deleted, which causes the error message
    this.$selfDestructCountdown is undefined
Am I wrong? :?:
Thargoid wrote:
But anyway, you don't need the worldscript at all to do this. An energy bomb action is usually done via the AI command becomeEnergyBlast, so you need to either spawn a suitable entity (an energy bomb) or switch the ships AI to that of such a bomb.
I thought the system.addShips("energy-bomb", 1, position, 0); would do the trick - thought the added ship came with it's AI... :roll: :?:
Eric Walch wrote:
Thargoid wrote:
....any such ship would get swiftly removed from my ooniverse. There used to be another OXP ship (whose name I forget as it's a long while ago) which tended to become a cascade explosion when shot up, and it extremely quickly became frustrating as the clouds and devastation were too common and screwed with gameplay by destroying too much of the system infrastructure. It very quickly went into the bit-bucket...
Purple Haze probably. I removed the code lines from the script. Without knowing how to do, I probably would have eradicated the ship also from my universe. But, the main problem was there probably that there was no delay, so you has no chance of getting into safety. Yesterday, it just happened that a random hits target turned 'blue'. There I did escape and it stays fun. A good delay timer in combination with a warning (message or a blinking mine lolipop) may help to not delete the oxp a.s.a.p. :)
Don't worry, I'm just doing some customizations for my own pleasure - the stardestroyer, as it comes shipped, is no real threat as long as you stay out of its' turret range. But I want to fear it! :twisted: :D
Btw, the chance that I "hit the reactor core" is only 33% not 77% - or am I wrong at this, too? :shock:
if (Math.random() > 0.77)

EDIT: Please don't forget that spara also asked a question (which I can't answer):
spara wrote:
I want to check if certain key exists in a descriptions.plist. At the moment I'm doing something like this:

Code: Select all

var key = expandDescription("[foo]");
if (key == "[foo]") 
//key not found
Not exactly a clean solution, :D as using expandDescription seems to thrown a JS warning. Is there some nice elegant way to do this check?

Re: Scripters cove

Posted: Thu Jan 31, 2013 10:19 am
by Commander McLane
GGShinobi wrote:
this.$selfDestructCountdown is not a function, but a global variable.. at least that's what I intended. :?
First, simply typing a random combination of letters (even if it starts with "this.") into a script at some place doesn't turn that random combination of letters into a global variable. Assigning a value to it would turn it into a variable:

Code: Select all

this.$selfDestructCountdown = 0;
this.$selfDestructCountdown = false;
this.$selfDestructCountdown = "This is a string.";
this.$selfDestructCountdown = [125433.67, 86753242.44674, 1234234.367];
are all possible. But:

Second, why would you even need a global variable in the first place? It doesn't serve any discernible purpose. You're (re-)defining it a couple of lines later as a timer (which is something else than a variable) anyway.

Third, then your timer calls the function that defines itself. In other words, what your timer does is to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, ad infinitum. That doesn't make any sense at all.

Re: Scripters cove

Posted: Thu Jan 31, 2013 10:53 am
by Wildeblood
Commander McLane wrote:
Third, then your timer calls the function that defines itself. In other words, what your timer does is to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, ad infinitum. That doesn't make any sense at all.
It does actually work though. I've done it before when I was in a hurry. But it's not something I'd leave in a script other people would see. :mrgreen:

Re: Scripters cove

Posted: Thu Jan 31, 2013 11:43 pm
by GGShinobi
Commander McLane wrote:
GGShinobi wrote:
this.$selfDestructCountdown is not a function, but a global variable.. at least that's what I intended. :?
First, simply typing a random combination of letters (even if it starts with "this.") into a script at some place doesn't turn that random combination of letters into a global variable. Assigning a value to it would turn it into a variable
Whoops, then I was actually mistaken there. I'm still learning JavaScript, and I thought that writing this.$selfDestructCountdown would be a variable declaration. Thanks for pointing out my mistake! Does JavaScript treat this line as a function call, then? :?:
Commander McLane wrote:
Second, why would you even need a global variable in the first place? It doesn't serve any discernible purpose. You're (re-)defining it a couple of lines later as a timer (which is something else than a variable) anyway.
Initially, the code was much simpler. In the beginning, I had no world script at all. What you see is the final result in a long line of trial and error, and declaring the variable outside of the function was my attempt to make sure that it still existed when the Timer countdown recursively called the same function again.
Commander McLane wrote:
Third, then your timer calls the function that defines itself. In other words, what your timer does is to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, which then goes on to define another new timer with the same name after countdown seconds, ad infinitum. That doesn't make any sense at all.
I think you are mistaken here. If you look closely at the line that creates the new Timer

Code: Select all

this.$selfDestructCountdown = new Timer(this, $starDestroyer_BigBang(position, 0), countdown);
you'll see that the function is called again (recursively) by the timer, just as you said, but with a different second parameter (0 instead of 5). This ensures that inside of the function, the second time the else-branch is taken, and avoids an endless loop.

What I'm still wondering about is: Why is the function that I pass to the timer as parameter seemingly called immediately, and not, as I intended, after the countdown (5 seconds) has passed? :?:

I'll test the "spawn" instead of "addShips" now :) I hope it works, and if, I hope I can also get it to detonate not immediately but after some delay...