Missile Beep

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

Moderators: winston, another_commander

User avatar
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Missile Beep

Post by hoqllnq »

Greetings Commanders,

Today, I made my first OXP: Missile Beep.
(Edit: updated v1.3 here.)
(Another edit: link updated to point to the file on the wiki. This OXP is now available in the in-app OXP manager.)


It plays high pitched beeps whenever a missile is targeted at the player.

It is extremely small & simple, but it got me to look into what it takes to make a working OXP.
If the OXP is installed, it will just work. It is not buyable equipment. So I categorised it as Ambience.
Everything is based on what I saw in other OXPs.

Please let me know what I've omitted, done wrong, or could improve.

Thanks.
Last edited by hoqllnq on Wed May 17, 2017 5:42 pm, edited 4 times in total.
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

Sweet! Seems to work fine, but threw a couple of these:

Code: Select all

20:05:43.672 [script.javaScript.exception.unexpectedType]: ***** JavaScript exception (Missile Beep 1.0): TypeError: things is undefined
20:05:43.672 [script.javaScript.exception.unexpectedType]:       ../AddOns/oolite.oxp.hoqllnq.missile_beep.oxz/Scripts/missile_beep.js, line 31.
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
User avatar
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Re: Missile Beep

Post by hoqllnq »

Thanks Commander.

Can you or someone help me out? I'm not that familiar with javascript.

This the function where the exception is thrown:

Code: Select all

this._timer_hook = function()
{
	var things = player.ship.checkScanner(true);
	
	for (var i = 0;i < things.length;i++)	// <-- this is line 31
	{
		if (things[i].isMissile && things[i].target == player.ship)
		{
			this._sound_source.play();
			return;
		}
	}
	
	if (this._sound_source.isPlaying)
		this._sound_source.stop();
}
I was guessing that this happens when the scanner is empty, and checkScanner() returns null. (And therefor I can not reference its 'length' member.) I tested this, but I don't get this exception when my scanner is empty. Do you know when/why it happens / how to reproduce it?

After some more testing, I was able to get this exception by killing myself. So maybe at that time, player == null or player.ship == null?

Adding the following extra checks gets rid of the exception in the suicide case:

Code: Select all

this._timer_hook = function()
{
	var things;
 
	if (player && player.ship)
	{
		things = player.ship.checkScanner(true);
		
		if (things)
		{
			for (var i = 0;i < things.length;i++)
			{
				if (things[i].isMissile && things[i].target == player.ship)
				{
					this._sound_source.play();
					return;
				}
			}
		}
	}
	
	if (this._sound_source.isPlaying)
		this._sound_source.stop();
}
Is this the correct solution? Is my line of thinking correct as to why? Or is it overkill?

An updated OXP with the extra checks is here: oolite.oxp.hoqllnq.missile_beep-1.1.oxz

Thanks.
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

That seems to have disappeared the error messages - thanks! Cookies in the jar!

Of javascript, I know nothing!
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
User avatar
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Re: Missile Beep

Post by hoqllnq »

Wow, you're fast. Thank you for testing and confirming.
User avatar
ffutures
---- E L I T E ----
---- E L I T E ----
Posts: 2172
Joined: Wed Dec 04, 2013 12:34 pm
Location: London, UK
Contact:

Re: Missile Beep

Post by ffutures »

Do the beeps speed up as it gets closer? That would be a lovely bit of ambience.
User avatar
Diziet Sma
---- E L I T E ----
---- E L I T E ----
Posts: 6312
Joined: Mon Apr 06, 2009 12:20 pm
Location: Aboard the Pitviper S.E. "Blackwidow"

Re: Missile Beep

Post by Diziet Sma »

ffutures wrote: Sun Mar 26, 2017 10:13 pm
Do the beeps speed up as it gets closer? That would be a lovely bit of ambience.
Seconded! That would be very useful, as well as inducing a slight sense of panic in the player! :twisted:
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
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Re: Missile Beep

Post by hoqllnq »

ffutures wrote: Sun Mar 26, 2017 10:13 pm
Do the beeps speed up as it gets closer? That would be a lovely bit of ambience.
In this update, they do: oolite.oxp.hoqllnq.missile_beep-1.2.oxz

The previous version would check for incoming missiles once a second, and if one was found, play a 0.5 second beep.

To make the beep speed depend on missile distance, I had to change "everything":
* Rather than detecting just any incoming missile, I now have to find the nearest one.
* Calculate a beep-interval based on the distance to the nearest incoming missile.
* Register a FCB to turn the beep on/off when the beep-interval has expired.

It now plays 1 beep per second when the missile is at the edge of the scanner range, 10 bps when distance is zero. Maybe these numbers need some tweaking. The 'duty cycle' is always 50%, i.e. the duration of the beeps is half the period.


Edit to add:

And here is version 1.3 --> oolite.oxp.hoqllnq.missile_beep-1.3.oxz
Functionality is the same as V1.2, but I made some code changes. Hopefully improvements...

* Lower the timer interval to 0.5 sec. while missiles are present, so that the change in beeping speed is smoother. (Put it back to 1 sec. when no more incoming missiles are around.)
* Added shipAttackedWithMissile() event handler that calls the timer hook when an incoming missile is fired, so beeping starts immediately instead of at the next timer interval.

This is the entire thing:

Code: Select all

// This is the world script for Missile Beep OXP
"use strict";
this.name        = "Missile Beep";
this.description = "Missile Beep World Script";
this.version     = "1.3";
this.author      = "hoqllnq";
this.copyright   = "2017 hoqllnq";
this.licence     = "CC-BY-NC-SA 3.0";

this._timer = null;         // To periodically check for incoming missiles
this._fcb = null;           // To time the beeps
this._sound_source = null;  // To play the beeps
this._beep_time = 0;        // How long beep (or silence) has been playing
this._beep_interval = 0;    // How long beep (or silence) should last
this._beep_on = false;      // Currently beeping?

this._debug = false;        // Logging


// Initialize the timer and the sound source
this.startUp = function()
{
    if (!this._timer)
    {
        this._timer = new Timer(this, this._timer_hook.bind(this),1,1);
    }
    
    if (!this._sound_source)
    {
        this._sound_source = new SoundSource();
        this._sound_source.loop = false;
        this._sound_source.sound = "[missile_beep]";
    }
    
    if (this._debug)
        log(this.name,"Started");
}

// A missile was fired at us, it could be the nearest one,
// don't wait for timer to fire, call timer hook now to check
this.shipAttackedWithMissile = function(missile,whom)
{
    if (this._debug)
        log(this.name,"Missile fired");
    
    this._timer_hook();
}

// Periodic check for presence and distance of incoming missiles
this._timer_hook = function()
{
    var things;
    var dist;
 
    if (player && player.ship)
    {    // Find all missiles in scanner range
        things = system.entitiesWithScanClass("CLASS_MISSILE",player.ship,25600);
        
        // See if any of them are targeted at us
        for (var i = 0;i < things.length;i++)
        {
            if (things[i].target == player.ship)
            {    // Yes.
                // This is the nearest one, since the list is ordered by distance
                dist = things[i].position.distanceTo(player.ship.position);
                if (this._debug)
                    log(this.name,"Missile at " + dist);
                
                // Beep duration based on distance
                this._beep_interval = 0.05 + dist / 51200.0;
                
                // If we weren't beeping yet, start now
                if(!isValidFrameCallback(this._fcb))
                {
                    this._fcb = addFrameCallback(this._fcb_hook.bind(this));
                    this._timer.interval = 0.5;
                }
                
                return;
            }
        }
    }
    
    // No incoming missiles
    // If we were beeping, stop now.
    if (isValidFrameCallback(this._fcb))
    {
        if (this._debug)
            log(this.name,"No more incoming missiles");
        
        removeFrameCallback(this._fcb);
        this._timer.interval = 1.0;
    }
    
    if (this._sound_source.isPlaying)
        this._sound_source.stop();
    
    this._beep_time = 0;
    this._beep_on = false;
}

// Frame callback to turn beep on/off
// This does the timing for the beeping speed
this._fcb_hook = function(delta)
{
    this._beep_time += delta;
    
    // Time for next beep/silence?
    if (this._beep_time < this._beep_interval)
        return; // No.
    
    // Reset time
    this._beep_time -= this._beep_interval;
    
    // Toggle beep
    if (this._beep_on)
    {
        if (this._sound_source.isPlaying)
            this._sound_source.stop();
        
        this._beep_on = false;
    }
    else
    {
        if (this._debug)
            log(this.name,"Beep!");
        
        if (!this._sound_source.isPlaying)
            this._sound_source.play();
        
        this._beep_on = true;
    }
}
I'm happy with how it works. Testing / playing around with it, I found it quite useful. When you fire at another ship, get the 'incoming missile' warning, but no beeping, you know you've already shot the missile, no need for ECM. Conversely, when multiple ships fire multiple missiles, and you hit your ECM, and the beeping continues, then you know it's time to ECM some more and make evasive manoeuvres. Unless there are problems (or really good ideas), I will leave it like this. It fulfils its original purpose, which was continuous alert for incoming missiles, and with the variable beeping speed (thanks cmdr. ffutures!) it does it even nicer than I originally envisioned.
Last edited by hoqllnq on Mon Mar 27, 2017 9:45 pm, edited 1 time in total.
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

Cool!
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
User avatar
ffutures
---- E L I T E ----
---- E L I T E ----
Posts: 2172
Joined: Wed Dec 04, 2013 12:34 pm
Location: London, UK
Contact:

Re: Missile Beep

Post by ffutures »

Is this on the manager yet, or only manual install?
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

Currently manual only, I believe - and damned useful kit it is too!
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
User avatar
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Re: Missile Beep

Post by hoqllnq »

I shall go through the steps outlined in the all-in-one guide to add it to the wiki and the manger.
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

It'd be a good idea to update the first post with the latest version too.
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
User avatar
hoqllnq
Commodore
Commodore
Posts: 154
Joined: Sun Jan 08, 2006 7:32 pm

Re: Missile Beep

Post by hoqllnq »

This OXP is now available in the manager. It's in the Ambience category.
Edited the first post to state this, and to add a link to the current version for manual installation.
I've also added it to the sortable list. Are there more steps I should take?
Thanks.
User avatar
Cody
Sharp Shooter Spam Assassin
Sharp Shooter Spam Assassin
Posts: 16081
Joined: Sat Jul 04, 2009 9:31 pm
Location: The Lizard's Claw
Contact:

Re: Missile Beep

Post by Cody »

All is good - thanks.
I would advise stilts for the quagmires, and camels for the snowy hills
And any survivors, their debts I will certainly pay. There's always a way!
Post Reply