Scripters cove

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

Moderators: winston, another_commander

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 »

szaumix wrote: Fri Jun 10, 2022 1:39 am
OK so another question for those who know.
Can anyone briefly expound on auto_weapons and auto_ai in the shipdata plist? What kinds of overrides -- specifically -- can I expect with them flagged as true? I'm in the middle of a shipdata_overrides.plist rebalance of core ship specs and, more significantly, their roles. And I just want to make sure of how exact I should be.

Actually a better question might be, what is the benefit of auto_weapons and auto_ai flagged as true?
Thanks!
auto_ai in most cases is useful. Depending on the role a matching AI will be assigned. Personally, I only turn if off if a specific behavior aka custom AI is required.

auto_weapons permits a change of the weapons defined in the shipdata.plist, therefore, a pulse laser could become a military laser or even an OXP weapon. While offering more variety, I would suggest handling it with care so that not suddenly ueber-pirates or assassins flooding the game.
Scars remind us where we've been. They don't have to dictate where we're going.
User avatar
szaumix
Deadly
Deadly
Posts: 171
Joined: Sun Apr 24, 2022 4:23 am

Re: Scripters cove

Post by szaumix »

montana05 wrote: Fri Jun 10, 2022 1:57 am
auto_ai in most cases is useful. Depending on the role a matching AI will be assigned. Personally, I only turn if off if a specific behavior aka custom AI is required.

auto_weapons permits a change of the weapons defined in the shipdata.plist, therefore, a pulse laser could become a military laser or even an OXP weapon. While offering more variety, I would suggest handling it with care so that not suddenly ueber-pirates or assassins flooding the game.
About what I had suspected. I don't suppose you know if anything other than just laser strength is affected? For example laser count (Like adding an aft_weapon? Or subtracting port or starbord lasers that I'd added?)? Or missile count, or type?
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4830
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

szaumix wrote: Fri Jun 10, 2022 2:06 am
don't suppose you know if anything other than just laser strength is affected? For example laser count (Like adding an aft_weapon? Or subtracting port or starbord lasers that I'd added?)? Or missile count, or type?
auto_weapons controls the equipment given to ships, based on their role, including lasers. Side lasers aren't ever given to NPC ships by the auto_weapons key.
User avatar
szaumix
Deadly
Deadly
Posts: 171
Joined: Sun Apr 24, 2022 4:23 am

Re: Scripters cove

Post by szaumix »

Thanks fellas. It occurs to me that it would be nice if there were a function to increase or decrease possibility of any given laser strength or missile type as a decimal -- as with other equipment.

Still not sure if this is correct long ago I surmised that the laser I had was affecting the auto_weapons variable of NPCs, and the only solution to this "problem" seems to be entirely new like_ship iterations with auto_weapons disabled and laser/missile preferences preset, with role weight functioning as probability.
Alnivel
Dangerous
Dangerous
Posts: 100
Joined: Fri Jun 10, 2022 7:05 pm

Re: Scripters cove

Post by Alnivel »

Hi everyone. I hope this is the right thread to ask for advice. I stumbled upon the following problem:
Script A has a runScreen callback binded to this script. The callback calls runScreen with nobinded callbacks.
I need to call runScreen in script B so that nested callbacks have script A as this.

Now questions:
Is there any way in script B to call a function as if it was called from script A?
Are there other ways to solve the above problem?
How can I get the name of the script that is currently running? (I already have one, via new Error.stack, but is there a better one?)
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4830
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

Alnivel wrote: Fri Jun 24, 2022 1:53 pm
Is there any way in script B to call a function as if it was called from script A?
Not sure if this will work, but worth a try.

Code: Select all

this.name = "ScriptB";

this.testFunction = function() {
    var newFunc = worldScripts.ScriptA.runScreen.bind(worldScripts.ScriptA);
    newFunc();
}
Alnivel
Dangerous
Dangerous
Posts: 100
Joined: Fri Jun 10, 2022 7:05 pm

Re: Scripters cove

Post by Alnivel »

phkb wrote: Sat Jun 25, 2022 4:49 am
Alnivel wrote: Fri Jun 24, 2022 1:53 pm
Is there any way in script B to call a function as if it was called from script A?
Not sure if this will work, but worth a try.

Code: Select all

this.name = "ScriptB";

this.testFunction = function() {
    var newFunc = worldScripts.ScriptA.runScreen.bind(worldScripts.ScriptA);
    newFunc();
}
Now I see that I didn't make it clear enough that by runScreen I mean Mission.runScreen and not a function of script A, sorry.
User avatar
Old Murgh
Wiki Wizard
Wiki Wizard
Posts: 640
Joined: Sat Dec 04, 2021 11:01 pm

Re: Scripters cove

Post by Old Murgh »

Kind gents, I have another little twist I hope you could help with.

In looking to recreate my original primitive hOpy casino, without the array of other games offered by skilled maintainers, I've had some luck in boiling it down to the original simple hOopy casino, and I think the game mechanics are working just as they should. Perfect.

–Except, in this .js version, the hoopy_theme starts only once the game is selected in the menu, and then stops and restarts with each screen change which isn't too pleasant.

Code: Select all

"use strict";

this.name = "hoopy_casino";
this.author = "Paul Wilkins (updated by Eric Walch, further updated by spara)";
this.copyright = "(C) 2009 Paul Wilkins";
this.license     = "CC BY-NC-SA 3.0"; 

//add interface
this.startUpComplete = this.shipExitedWitchspace = function() {
	var casinos = system.shipsWithPrimaryRole("casinoship");
	if (casinos.length > 0) {
		for (var i = 0; i < casinos.length; i++) {
			casinos[i].setInterface("hoopy-hoops",{
				title: expandMissionText("hoopy-hoops-title"),
				category: expandMissionText("hoopy-gambling-category"),
				summary: expandMissionText("hoopy-hoops-summary"),
				callback: this.$startGambling.bind(this)
			});
		}
	}
}

//init the hoops
this.shipDockedWithStation = function (station) {
	if (player.ship.docked && station.primaryRole === 'casinoship') {
        missionVariables.hoopy_casino = 'NOT_NOW';
        this.setBoundaries();
    }
};

this.missionScreenOpportunity = function ()
{
    if (player.ship.docked && player.ship.dockedStation.primaryRole === 'casinoship') 
    {
        this.gamble();
    }
};


this.setBoundaries = function () {
        /*
        In the legacy version the random distribution was bad. One could win after analysing the odds
        during some time. This is a feature that should stay in. So we prepare the gamble table now a bit.
        */
        this.boundary1 = 1 + Math.random() - Math.random();
        this.boundary2 = 2 + Math.random() - Math.random();
        if (this.boundary1 > this.boundary2) this.boundary1 = this.boundary2;
        this.startCapital = player.credits;
};

this.$startGambling = function() {
	missionVariables.hoopy_casino = 'HOOPY_ENTER';
	this.gambleChoices('YES_HOOPY');
}

this.gamble = function () {
	/*
    if (missionVariables.hoopy_casino === 'HOOPY_REVISIT') {
        if (player.credits >= 100) {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_intro', overlay: 'hoopy_front.png', choicesKey: 'hoopy_casino_enter_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
            missionVariables.hoopy_casino = 'HOOPY_ENTER';
            return;
        }
    }*/
    if (missionVariables.hoopy_casino === 'HOOPY_GAMEON') {
        mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_choices', overlay: 'hoopy_cover.png', choicesKey: 'hoopy_casino_pick_hoop', music: "hoopy_theme.ogg"}, this.gambleChoices);
        this.hoopy_casino_hoop = Math.random() * 3;
        missionVariables.hoopy_casino = 'HOOPY_MAKE_CHOICE';
        return;
    }
    if (player.credits > this.startCapital + 2000) {
        mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_new_table', overlay: 'hoopy_front.png', choicesKey: 'hoopy_casino_new_table_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
        missionVariables.hoopy_casino = 'HOOPY_NEW_TABLE';
        this.setBoundaries();
    } else {
        if (missionVariables.hoopy_casino === 'HOOPY_WINNER') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_win', overlay: this.hoopy_casino_image, choicesKey: 'hoopy_casino_replay_winner_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
            player.credits += 100;
            missionVariables.hoopy_casino = 'HOOPY_REPLAY';
        }
        if (missionVariables.hoopy_casino === 'HOOPY_LOSER') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_loss', overlay: this.hoopy_casino_image, choicesKey: 'hoopy_casino_replay_loser_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
            player.credits -= 100;
            missionVariables.hoopy_casino = 'HOOPY_REPLAY';
        }
    }
    if (missionVariables.hoopy_casino === 'NOT_NOW') {
        delete this.hoopy_casino_hoop;
        delete this.hoopy_casino_image;
        delete missionVariables.hoopy_casino;
    }
};
this.gambleChoices = function (choice){
    if (missionVariables.hoopy_casino === 'HOOPY_ENTER') {
        if (choice === 'YES_HOOPY') {
			if (player.credits >= 100) {
				mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_desc', overlay: 'hoopy_clean.png', choicesKey: 'hoopy_casino_gamble_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
				missionVariables.hoopy_casino = 'HOOPY_GAMBLE';
			}
			else {
				missionVariables.hoopy_casino = 'HOOPY_REPLAY';
				this.gambleChoices('YES_HOOPY');
				return;
			}
        } else if (choice === 'NO_HOOPY') {
            missionVariables.hoopy_casino = 'NOT_NOW';
        }
        return;
    }
    if (missionVariables.hoopy_casino === 'HOOPY_GAMBLE') {
        if (choice === '0_HOOPY') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_desc', overlay: 'hoopy_clean.png', choicesKey: 'hoopy_casino_gamble_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
        } else if (choice === 'YES_HOOPY') {
            missionVariables.hoopy_casino = 'HOOPY_GAMEON';
        } else if (choice === 'NO_HOOPY') {
            missionVariables.hoopy_casino = 'NOT_NOW';
        }
        return;
    }
    if (missionVariables.hoopy_casino === 'HOOPY_MAKE_CHOICE') {
        missionVariables.hoopy_casino = 'HOOPY_LOSER';
        if (this.hoopy_casino_hoop < this.boundary1) {
			this.hoopy_casino_image = 'hoopy_Lwin.png';
            if (choice === 'LEFT_HOOPY') {
                missionVariables.hoopy_casino = 'HOOPY_WINNER';
            }
        }
        if (this.hoopy_casino_hoop >= this.boundary1 && this.hoopy_casino_hoop < this.boundary2) {
			this.hoopy_casino_image = 'hoopy_Cwin.png';
            if (choice === 'MIDDLE_HOOPY') {
                missionVariables.hoopy_casino = 'HOOPY_WINNER';
            }
        }
        if (this.hoopy_casino_hoop >= this.boundary2) {
			this.hoopy_casino_image = 'hoopy_Rwin.png';
            if (choice === 'RIGHT_HOOPY') {
                missionVariables.hoopy_casino = 'HOOPY_WINNER';
            }
        }
        return;
    }
    if (missionVariables.hoopy_casino === 'HOOPY_NEW_TABLE') {
        if (choice === 'NEW_TABLE_HOOPY') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_desc', overlay: 'hoopy_clean.png', choicesKey: 'hoopy_casino_gamble_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
            missionVariables.hoopy_casino = 'HOOPY_GAMBLE';
        } else if (choice === 'NO_HOOPY') {
            missionVariables.hoopy_casino = 'NOT_NOW';
        }
        return;
    }
    if (missionVariables.hoopy_casino === 'HOOPY_REPLAY') {
        if (choice === '0-WINNER_HOOPY') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_win', overlay: this.hoopy_casino_image, choicesKey: 'hoopy_casino_replay_winner_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
        }
        if (choice === '0-LOSER_HOOPY') {
			mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_loss', overlay: this.hoopy_casino_image, choicesKey: 'hoopy_casino_replay_loser_yesno', music: "hoopy_theme.ogg"}, this.gambleChoices);
        }
        if (choice === 'YES_HOOPY') {
            if (player.credits >= 100) {
                mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_again', overlay: 'hoopy_clean.png', music: "hoopy_theme.ogg"});
                missionVariables.hoopy_casino = 'HOOPY_GAMEON';
            } else {
                mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_nofunds', overlay: 'hoopy_front.png', music: "hoopy_theme.ogg"});
                missionVariables.hoopy_casino = 'NOT_NOW';
            }
        }
        if (choice === 'NO_HOOPY') {
            mission.runScreen({title: "Hoopy Casino", messageKey: 'hoopy_casino_goodbye', overlay: 'hoopy_front.png', music: "hoopy_theme.ogg"});
            missionVariables.hoopy_casino = 'NOT_NOW';
        }
	}    
};
Since I would much rather that the music begins instantly once docked at the casino and plays all the way through until space launch, so I gather I would remove all the current instances of music: "hoopy_theme.ogg", but where would I place the one I want for the play at arrival effect?

That, and I wish I could have the "Play hOopy" option appear at the very top of the menu, but I've learned to accept I can't always get what I want.
I was young, I was naïve. [EliteWiki] Jonny Cuba made me do it!
Alnivel
Dangerous
Dangerous
Posts: 100
Joined: Fri Jun 10, 2022 7:05 pm

Re: Scripters cove

Post by Alnivel »

Old Murgh wrote: Fri Jul 01, 2022 2:12 pm
Since I would much rather that the music begins instantly once docked at the casino and plays all the way through until space launch, so I gather I would remove all the current instances of music: "hoopy_theme.ogg", but where would I place the one I want for the play at arrival effect?
How about using a looped SoundSource in the shipDockedWithStation handler for play and stopping it during shipWillLaunchFromStation?

Code: Select all

this.startUpComplete = function(){
    var bgmSoundSource = new SoundSource;
    bgmSoundSource.sound = "hoopy_theme.ogg";
    bgmSoundSource.loop = true;
    this._bgmSoundSource = bgmSoundSource;
}

this.shipDockedWithStation = function (station) {
    if (player.ship.docked && station.primaryRole === 'casinoship') {
        this._bgmSoundSource.play();
    }
};

this.shipWillLaunchFromStation = function() {
    this._bgmSoundSource.stop();
};
(I would like to point out that I was only able to get the sound to work in that way after I moved it to the Sounds folder.)
Old Murgh wrote: Fri Jul 01, 2022 2:12 pm
That, and I wish I could have the "Play hOopy" option appear at the very top of the menu, but I've learned to accept I can't always get what I want.
Interface menu items are ordered by category first, so you can try changing the category name.
Not sure how good this approach is, but you can try put the interface at the top of the list by adding a (nearly) invisible ASCII control character that is "smaller" than any letter to the beginning of the category name.

Code: Select all

this.startUpComplete = this.shipExitedWitchspace = function() {
    var casinos = system.shipsWithPrimaryRole("casinoship");
    if (casinos.length > 0) {
        for (var i = 0; i < casinos.length; i++) {
            casinos[i].setInterface("hoopy-hoops",{
                title: expandMissionText("hoopy-hoops-title"),
                category: String.fromCharCode(0x1F) + expandMissionText("hoopy-gambling-category"), // Put a control character here...
                summary: expandMissionText("hoopy-hoops-summary"),
                callback: this.$startGambling.bind(this)
            });
        }
    }
}
... or add it directily in "hoopy-gambling-category" in .plist file. I'm not sure, but I think you can write the character as "\x1F" in it.
User avatar
Old Murgh
Wiki Wizard
Wiki Wizard
Posts: 640
Joined: Sat Dec 04, 2021 11:01 pm

Re: Scripters cove

Post by Old Murgh »

Alnivel wrote: Fri Jul 01, 2022 7:41 pm
How about using a looped SoundSource in the shipDockedWithStation handler for play and stopping it during shipWillLaunchFromStation? ...
You're a wizard, sir, and your username obviously appropriate.
That did exactly what I hoped.
It feels so good to copy and paste the brainwork of smarter people.

As you point out the alphabetical nature of the categories does allow for a low-tech way to sneak to the top of the queue. Since I dread messing with all that works from the missiontext.plist angle (well I couldn't make "\x1F" do anything other than print just that), the easy way is to skip ahead of "Activities" is to rename Gambling to Absorbing Gambling. Or should that be Abhorrent Gambling?

At any rate, the obstacle of the day is conquered. Thank you very much!
I was young, I was naïve. [EliteWiki] Jonny Cuba made me do it!
User avatar
Old Murgh
Wiki Wizard
Wiki Wizard
Posts: 640
Joined: Sat Dec 04, 2021 11:01 pm

Re: Scripters cove

Post by Old Murgh »

I'm trying to get a better grip on how to interpret this line, but it's not easy when one's brain isn't wired for such things.
phkb wrote: Sat Jun 04, 2022 9:57 am
To keep the dice roll function as is, you'd need to do this:

Code: Select all

this.systemWillPopulate = function ()
{
	if (Math.floor(Math.random() > 0.10)  // 90% chance
..
which was later amended to
montana05 wrote: Sat Jun 04, 2022 2:44 pm

Code: Select all

if (Math.floor(Math.random() * 10) > 0)  // returns a random integer from 0 to 9 so there is a 90% chance
The bottom one works fine for the 90% appearance, but if I'm trying to know what I'm doing, and I would like a less frequent appearance, do I interpret the above as 10% not appearing, so to achieve 40% appearance probability, do I make the 10 into 60? Or am I thinking wrong?
I was young, I was naïve. [EliteWiki] Jonny Cuba made me do it!
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 »

Old Murgh wrote: Thu Jul 07, 2022 11:48 pm
I'm trying to get a better grip on how to interpret this line, but it's not easy when one's brain isn't wired for such things.
phkb wrote: Sat Jun 04, 2022 9:57 am
To keep the dice roll function as is, you'd need to do this:

Code: Select all

this.systemWillPopulate = function ()
{
	if (Math.floor(Math.random() > 0.10)  // 90% chance
..
which was later amended to
montana05 wrote: Sat Jun 04, 2022 2:44 pm

Code: Select all

if (Math.floor(Math.random() * 10) > 0)  // returns a random integer from 0 to 9 so there is a 90% chance
The bottom one works fine for the 90% appearance, but if I'm trying to know what I'm doing, and I would like a less frequent appearance, do I interpret the above as 10% not appearing, so to achieve 40% appearance probability, do I make the 10 into 60? Or am I thinking wrong?
Have a look here: https://www.w3schools.com/js/js_random.asp

Basically, this function will return a random number between 0 and 9 so to lower the appearing you would need to change it to > 6 which would offer only a 30% chance for example.
Scars remind us where we've been. They don't have to dictate where we're going.
User avatar
Old Murgh
Wiki Wizard
Wiki Wizard
Posts: 640
Joined: Sat Dec 04, 2021 11:01 pm

Re: Scripters cove

Post by Old Murgh »

montana05 wrote: Fri Jul 08, 2022 12:14 am
Have a look here: https://www.w3schools.com/js/js_random.asp

Basically, this function will return a random number between 0 and 9 so to lower the appearing you would need to change it to > 6 which would offer only a 30% chance for example.
I think (no, hope is the word) I get it.
Because it will never return a perfect 1, am I then correct in thinking

Code: Select all

if (Math.floor(Math.random() * 10) > 4)  
will result in a 50/50 coinflip? :shock:
I was young, I was naïve. [EliteWiki] Jonny Cuba made me do it!
User avatar
cbr
---- E L I T E ----
---- E L I T E ----
Posts: 1422
Joined: Thu Aug 27, 2015 4:24 pm

Re: Scripters cove

Post by cbr »

or

Math.round(Math.random())

= 0/1
User avatar
phkb
Impressively Grand Sub-Admiral
Impressively Grand Sub-Admiral
Posts: 4830
Joined: Tue Jan 21, 2014 10:37 pm
Location: Writing more OXPs, because the world needs more OXPs.

Re: Scripters cove

Post by phkb »

My suggestion is

Code: Select all

if (Math.random() < 0.1) 
Because it removes unnecessary calculations, while still being clear what percentage is being checked, in this case a 10% chance. To make it 50% just change 0.1 to 0.5.
Post Reply