Scripters cove

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

Moderators: winston, another_commander

User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

Arexack_Heretic wrote:
@ahruman: you are right, the variable won't reset after de-installation. :/
your java method seems to be checked everytime the game starts up.
JavaScript is not Java. They’re hardly even related.

While it’s called at startup and every time the player starts a new game or dies, this doesn’t change the fact that the value will be loaded from saved games. Obviously you can’t have a script to clear it if the OXP isn’t there. :-)

So… do we need a mechanism for variables that are shared between all scripts, but not saved?
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Post by Commander McLane »

Ahruman wrote:
So… do we need a mechanism for variables that are shared between all scripts, but not saved?
I think that could be a good idea.

Our general idea is: I want my OXP be able to check which other OXPs are installed. Correct? So if every OXP throws its I-am-installed-message into the pool every time the game is started and these messages can be checked by my OXP later, then this functionality is there. It has to be done on each start-up, but doesn't have to be saved.

So, yes, I think, this mechanism is exactly what is needed.

-----

Another question is when my OXP can check for the presence of other OXPs. Obviously not on loading, because OXPs are loaded in alphabetical order, so my OXP wouldn't have information on all OXPs behind it in the alphabet.

I am thinking of using existing ships in a new OXP. Of course I can c&p all the relevant dats and textures into my OXP, but that can cost a lot of Megabytes, and for players who have the relevant OXPs installed it's an unnecessary doubling.

So my question: Would it be possible to get a warning message as early as possible, even on the title screen, saying something like:
You are attempting to play Thargoidmission.oxp. This requires the thargoidcarrier2.oxp to be installed. Please install thargoidcarrier2.oxp and start Oolite again.
User avatar
Arexack_Heretic
Dangerous Subversive Element
Dangerous Subversive Element
Posts: 1876
Joined: Tue Jun 07, 2005 7:32 pm
Location: [%H] = Earth surface, Lattitude 52°10'58.19"N, longtitude 4°30'0.25"E.
Contact:

Post by Arexack_Heretic »

aren't local_variables not saved?

Didn't see your last post McL.
Yes, that is exactly what is needed.

But titlepage is not really neccesary, It could be done inside the game as well .

Code: Select all

eg: GREETINGS COMMANDER

The OXP-directorate has scanned your shipcomputer's OS.

Our findings are that you are running a version of THISOXP that requires THATOXP to be installed as well. 
Read the supplied readme-file in your shipsmailbox for instructions.


Please note that ignoring this message may result in sensor glitches and even reality dysfunctions as your witchdrive turns you inside out.
Or even when the critical junction is reached

Code: Select all

Your trial period has expired.
THIS_OXP shares data with THAT_OXP and pay 1000Credits to register.
Riding the Rocket!
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

Commander McLane wrote:
Another question is when my OXP can check for the presence of other OXPs. Obviously not on loading, because OXPs are loaded in alphabetical order, so my OXP wouldn't have information on all OXPs behind it in the alphabet.
Hmm. In JavaScript, without modification, it can be done by putting the set-up of the variable in the script itself rather than in a callback. Example:

Code: Select all

globalVariables.thisOXP_Installed = true;
canRun = true;

this.startUp = function()
{
    if (!globalVariables.otherOXP_Installed)
    {
        LogWithClass("thisOXP.requiresOtherOXP", "thisOXP cannot function without OtherOXP!");
        canRun = false;
    }
}
What this does is set the flag globalVariables.thisOXP_Installed when it is loaded, and check for globalVariables.otherOXP_Installed when startUp() is called, which is guaranteed to be after all world scripts are loaded. I can’t really see a way to do something equivalent in the old scripting model without significant hackery.

I’m thinking that for this type of thing, variables which persist even when the player dies or loads a different game would be more useful than ones that reset. I almost called it “persistentVariables” for this reason, but of course, they’re not persistent in the manner of mission variables. (If you need a variable to be shared between scripts but to reset when the player dies, the “owning” script can reset it in its reset() callback).
Arexack_Heretic wrote:
aren't local_variables not saved?
Yes, but they’re also not visible to other scripts.
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

Arexack_Heretic wrote:
Or even when the critical junction is reached

Code: Select all

Your trial period has expired.
THIS_OXP shares data with THAT_OXP and pay 1000Credits to register.
Please don’t do that. Error messages should be as informative as possible, and trying to be funny gets in the way. (It’d be particularly problematic if there was a chance of someone interpreting it as a shareware notice for Oolite.)
Last edited by JensAyton on Tue Jul 10, 2007 11:31 am, edited 1 time in total.
User avatar
Arexack_Heretic
Dangerous Subversive Element
Dangerous Subversive Element
Posts: 1876
Joined: Tue Jun 07, 2005 7:32 pm
Location: [%H] = Earth surface, Lattitude 52°10'58.19"N, longtitude 4°30'0.25"E.
Contact:

Post by Arexack_Heretic »

8)
You are right ofcourse.
both on the shareware-joke as well as the localvariable.

Just making fun here. ;)

THIS_OXP is best enjoyed with THAT_OXP installed as well.
Would be more informative, but in-game would lead to the reality dysfunction I mentined earlier.
A reference to the game-mechanics in-game would break the suspension of disbelief.
Mention on the start-page wuld be better in this case.

Anyhow, I mainly want the check so that my code can optimally use the available OXP's without too much copy/pasting.
Riding the Rocket!
User avatar
Arexack_Heretic
Dangerous Subversive Element
Dangerous Subversive Element
Posts: 1876
Joined: Tue Jun 07, 2005 7:32 pm
Location: [%H] = Earth surface, Lattitude 52°10'58.19"N, longtitude 4°30'0.25"E.
Contact:

Post by Arexack_Heretic »

If I were to want to code for vermin other than trumbles..how would I go aboot it?

I was thinking mice, space herpies, rockroaches, metallovorous grubs, etc.
And a fluffy cat (against the mice) to sit right ontop on my scanner. ;)

Maybe they could be named randomly using the in-game fabled beast generator.

"Your ship is infested with [pest_number] deadly poets."
Riding the Rocket!
User avatar
Frame
---- E L I T E ----
---- E L I T E ----
Posts: 1477
Joined: Fri Mar 30, 2007 8:32 am
Location: Witchspace

Post by Frame »

Here is How the Rock Hermit Locator works...

The Code presently look like this, but will alter a bit as i will add a penalty, in the form of destroying a players Rock Hermit Locator.

This first Part is the Rock Hermits New AI
It is like the first but basicly adds Four extra states

The new Stages are
"LOOK_FOR_ASTEROID" : Find nearest asteroid and make it global target,

"DETONATE_TARGET" : spawn a mockbouy / Dummy near the asteroid, and kill the asteroid

"LOOK_FOR_BOUYMOM" : Find mockbouy and make it global target.

"DETONATE_MOM" : simply destroy mockboy because the shipdata.plist will create 1 of 2 new boys, one with or without a beacon depending on wheter or not the player has bought the Rock Hermit Locator..

Code for Rock Hermit AI..

Code: Select all

{

	"DEFENSE_MODE" = {
       			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel); 
        		ENTER = (); 
        		EXIT = (); 
        		"RED_ALERT" = (launchDefenseShip); 
        		"YELLOW_ALERT" = ("setStateTo: IDLE"); 
        		"CONDITION_YELLOW" = ("setStateTo: IDLE"); 
        		"CONDITION_GREEN" = ("setStateTo: CHECK_FOR_DEBRIS"); 
        		"INCOMING_MISSILE" = (increaseAlertLevel); 
        		"ENERGY_FULL" = ("pauseAI: 20.0", "setStateTo: IDLE"); 
        		"TARGET_DESTROYED" = ("pauseAI: 20.0", "setStateTo: IDLE"); 
        		"TARGET_LOST" = ("pauseAI: 20.0", "setStateTo: IDLE"); 
        		"NO_TARGET" = ("pauseAI: 20.0", "setStateTo: IDLE"); 
        		UPDATE = (); 
			};    

	 
	"LOOK_FOR_ASTEROID" = {
			ENTER = ();
			UPDATE = ("scanForNearestShipWithRole: asteroid");
        		"TARGET_FOUND" = (setTargetToFoundTarget, "setStateTo: DETONATE_TARGET");
			"NOTHING_FOUND" = ("pauseAI: 20.0","setStateTo: LOOK_FOR_ASTEROID");			
			EXIT = ();
			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);
			};
        		
	"DETONATE_TARGET" = {
			ENTER = ();
			UPDATE = ("scriptActionOnTarget: spawn: mockbuoy 1","scriptActionOnTarget: becomeExplosion","setStateTo: LOOK_FOR_BOUYMOM");
        		EXIT = ();
			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);        		
        		};
        		
	"LOOK_FOR_BOUYMOM" = {
			ENTER = ();
			UPDATE = ("scanForNearestShipWithRole: mockbuoy");        		
			"TARGET_FOUND" = (setTargetToFoundTarget, "setStateTo: DETONATE_MOM");
			"NOTHING_FOUND" = ("setStateTo: LOOK_FOR_BOUYMOM");
			EXIT = ();
			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);
        		};
        		

	"DETONATE_MOM" = {
			ENTER = ();
			UPDATE = ("scriptActionOnTarget: becomeExplosion","setStateTo: IDLE");
			EXIT = ();
			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);
        		};

	"CHECK_FOR_DEBRIS" = {
   			ENTER = ();
   			UPDATE = (scanForLoot,"pauseAI: 20.0"); 
			"TARGET_FOUND" = (launchScavenger, "setStateTo: IDLE"); 
      			"NOTHING_FOUND" = ("setStateTo: CHECK_FOR_ROCKS", "pauseAI: 20.0"); 
        		EXIT = (); 
        		ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel); 
			};
    
	"CHECK_FOR_ROCKS" = {
			ENTER = (); 
			UPDATE = (scanForRocks, "pauseAI: 20.0"); 
			"TARGET_FOUND" = (launchMiner, "setStateTo: IDLE"); 
			"NOTHING_FOUND" = ("setStateTo: IDLE", "pauseAI: 20.0"); 
			EXIT = (); 
      			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
       			"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);
			};
       		
	GLOBAL = {
			ENTER = ("setStateTo: LOOK_FOR_ASTEROID");
			EXIT = ();
			ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		"INCOMING_MISSILE" = (fireECM, increaseAlertLevel);
        		UPDATE = ();
        		};
	 	
	IDLE = {
        		ATTACKED = (setTargetToPrimaryAggressor, increaseAlertLevel, "setStateTo: DEFENSE_MODE"); 
        		ENTER = (); 
        		EXIT = (); 
        		"INCOMING_MISSILE" = (increaseAlertLevel); 
        		UPDATE = (decreaseAlertLevel, "setStateTo: CHECK_FOR_DEBRIS"); 
    			};
}

Here the Code for the Mock Bouy in shipdata.plist ,
The Two objects spawned when it dies are objects copy pasted from the Navigation Bouy however the bouy that has role rockbeacon 1 has a beacon and will only be spawned if the player has The Rock Hermit Locator so i will not post that code..

Code: Select all

<key>mockmack</key>
<dict>
		<key>ai_type</key>
		<string>buoyAI.plist</string>		
		<key>bounty</key>
		<integer>0</integer>
		<key>cargo_type</key>
		<string>CARGO_NOT_CARGO</string>
		<key>death_actions</key>
		<array>		
			<string>debugOn</string>
			<string>testForEquipment: EQ_ROCKHERMIT_SCANNER</string>
			<dict>
				<key>conditions</key>
				<array>
					<string>foundEquipment_bool equal NO</string>
				</array>
				<key>do</key>
				<array>
					<string>spawn: rockbeacof 1</string>
				</array>
			</dict>
			<dict>
				<key>conditions</key>
				<array>
					<string>foundEquipment_bool equal YES</string>
				</array>
				<key>do</key>
				<array>
					<string>spawn: rockbeacon 1</string>
				</array>
			</dict>
			<string>debugOff</string>		
		</array>
		<key>energy_recharge_rate</key>
		<real>2</real>
		<key>forward_weapon_type</key>
		<string>WEAPON_NONE</string>
		<key>likely_cargo</key>
		<integer>0</integer>
		<key>max_cargo</key>
		<integer>0</integer>
		<key>max_energy</key>
		<real>250</real>
		<key>max_flight_pitch</key>
		<real>2</real>
		<key>max_flight_roll</key>
		<real>2</real>
		<key>max_flight_speed</key>
		<real>0.0</real>
		<key>missiles</key>
		<integer>0</integer>
		<key>model</key>
		<string>buoy.dat</string>
		<key>name</key>
		<string>Rock Hermit Buoy</string>
		<key>roles</key>
		<string>mockbuoy</string>
		<key>scanClass</key>
		<string>CLASS_BOUY</string>
		<key>thrust</key>
		<real>100</real>
		<key>unpiloted</key>
		<true/>
		<key>weapon_energy</key>
		<real>0.0</real>
		<key>weapon_offset_x</key>
		<real>0.0</real>
	</dict>
The last bit of entry is in the equipment.plist where the correct entries are made so that the player can buy the Rock Hermit Locator

Code: Select all

<array>
		<integer>1</integer>
		<integer>150000</integer>
		<string>Rock Hermit Locator</string>
		<string>EQ_ROCKHERMIT_SCANNER</string>
		<string>Connects to Bouy System Link to find current locations of Rock Hermits</string>
		<dict>
			<key>available_to_all</key>
			<true/>
		</dict>

The AI is not entirely foolproof if say the rockhermit comes under attack in the first second, Which is VERY unlikely, then the AI may not work... But so far it has worked on every run...

I beleive this system could be used also so you spawn a particular ship with a beacon if the player has the right Equipment to trace it its just a matter of making a duplicate of the ship with the beacon..

Usefull for say assasin missions ;-), so that you dont get lost in locating your Victims :D.

Cheers Frame...
Bounty Scanner
Number 935
User avatar
TGHC
---- E L I T E ----
---- E L I T E ----
Posts: 2157
Joined: Mon Jan 31, 2005 4:16 pm
Location: Berkshire, UK

Post by TGHC »

Excellent stuff, looking forward to the final version
The Grey Haired Commander has spoken!
OK so I'm a PC user - "you know whats scary? Out of billions of sperm I was the fastest"
User avatar
Arexack_Heretic
Dangerous Subversive Element
Dangerous Subversive Element
Posts: 1876
Joined: Tue Jun 07, 2005 7:32 pm
Location: [%H] = Earth surface, Lattitude 52°10'58.19"N, longtitude 4°30'0.25"E.
Contact:

ANY REQUESTS?

Post by Arexack_Heretic »

Any requests for sample code?

Here's the AI.plist for a mine/missile/buoy type object that forces (hostile) ships to hyperspace.

Code: Select all

GLOBAL {ENTER = ("setStateTo: PULSE"); UPDATE = (); EXIT = ();}; 
PULSE = { 
ENTER = ("pauseAI: 5"); 
UPDATE = (scanForHostiles, "pauseAI: 3"); 
"TARGET_FOUND" = (performHyperspaceExit, "pauseAI: 2"); 
"NOTHING_FOUND" = ("pauseAI: 2", becomeExplosion) 
EXIT = ();};
or without using update (which can be usefull with multiple scan stages):

Code: Select all

GLOBAL {ENTER = ("setStateTo: NEXT"); UPDATE = (); EXIT = ();}; 
CYCLE = { 
ENTER = (scanForHostiles, "pauseAI: 3"); 
"TARGET_FOUND" = (setTargetToFoundTarget, "performScriptActionOnTarget: performHyperspaceExit", "pauseAI: 2", "setStateTo: CYCLE"); 
"NOTHING_FOUND" = ("pauseAI: 2", becomeExplosion); 
UPDATE = (); 
EXIT = (); 
};
IF using multiple scanfor stages, change the nothing_found methods to setStateTo: TARGET_TYPE2(etc) and only at the last stage reset it to global or detonate.
Riding the Rocket!
User avatar
JensAyton
Grand Admiral Emeritus
Grand Admiral Emeritus
Posts: 6657
Joined: Sat Apr 02, 2005 2:43 pm
Location: Sweden
Contact:

Post by JensAyton »

On Monday, Apple posted this guide to JavaScript. Bits of it are specific to web scripting and WebKit, but it provides a good and clearly-written overview of basic JS syntax.
User avatar
Arexack_Heretic
Dangerous Subversive Element
Dangerous Subversive Element
Posts: 1876
Joined: Tue Jun 07, 2005 7:32 pm
Location: [%H] = Earth surface, Lattitude 52°10'58.19"N, longtitude 4°30'0.25"E.
Contact:

Multiple scanfor stages in AI

Post by Arexack_Heretic »

Code: Select all

GLOBAL = {
ENTER = ("pauseAI: 10", "setStateTo: SCAN_FOR_TARGET1"); EXIT = (); UPDATE = (); };

"SCAN_FOR_TARGET1" = {
ENTER = (scanForHostiles, "pauseAI: 2);
EXIT = ();
UPDATE = ("setStateTo: GLOBAL");
"TARGET_FOUND" = ("commsMessage: Uh oh, scanner shows a bogie!"); 
"NOTHING_FOUND" = ("setStateTo: SCAN_FOR_TARGET2");
};

"SCAN_FOR_TARGET2" = {
ENTER = (scanForMerchantmen, "pauseAI: 2);
EXIT = ();
UPDATE = ("setStateTo: GLOBAL");
"TARGET_FOUND" = ("commsMessage: There is a merchant closeby!"); 
"NOTHING_FOUND" = ("setStateTo: SCAN_FOR_TARGET3");
};

"SCAN_FOR_TARGET2" = {
ENTER = (scanForThargoid, "pauseAI: 2);
EXIT = ();
UPDATE = ("setStateTo: GLOBAL");
"TARGET_FOUND" = ("commsMessage: Thargoid, prepare to become toast!"); 
"NOTHING_FOUND" = ("setStateTo: GLOBAL");
};
This code scans for 3 seperate types of ship, when found displays a message. eventually the state is reset and scanning can resume.
Note, that this AI scans in a predetermined order and only perform the action on the first found target.
In order to scan for all types, include the method found in "Nothing_found" AFTER the methods in "target_found".
Also note that short of removing the scanned ship from play, there is no way to prevent the scan from rescanning the same target.


----
Edit:
Hey, that is a usefull link A-man. good find. 8)
Riding the Rocket!
User avatar
Griff
Oolite 2 Art Director
Oolite 2 Art Director
Posts: 2483
Joined: Fri Jul 14, 2006 12:29 pm
Location: Probably hugging his Air Fryer

Post by Griff »

guys, sorry to post a noob question, ahrumans recent glowing alloy oxp had a shipdata.plist file that looked like this:-

Code: Select all

{
    "griff_glowing_alloy" =
	{
        like_ship = alloy; 
        model = "griff-alloy-1.dat"; 
        roles = "alloy"; 
        shaders =
		{
            "griff-alloy-1-diffuse.png" =
			{
                vertex_shader = "ahruman-generic.vertex"; 
                fragment_shader = "griff-glow-alloy.fragment"; 
				
                textures = ("griff-alloy-1-diffuse.png", "griff-alloy-1-effects.png"); 
                uniforms =
				{
					timeElapsedSinceSpawn = "timeElapsedSinceSpawn";
				}; 
            }; 
        }; 
    }; 
}
it's a thing of rare beauty i'm sure you'd agree - is this ASCII format? are there more examples on the wiki? I'd like to start using this format but i'm stuck on the following - whats the ascii format for a true/false boolean, ie something like:-

<key>has_scoop</key>
<true/>

is it has_scoop = 1; or has_scoop ="true"; or something else entirely?
United Blobs
Competent
Competent
Posts: 45
Joined: Sat Mar 24, 2007 7:51 pm

Post by United Blobs »

http://wiki.alioth.net/index.php/Property_lists#boolean so has_scoop=1 appears to be correct.
User avatar
Commander McLane
---- E L I T E ----
---- E L I T E ----
Posts: 9520
Joined: Thu Dec 14, 2006 9:08 am
Location: a Hacker Outpost in a moderately remote area
Contact:

Post by Commander McLane »

Look at the image on the wiki page: It's

Code: Select all

"has_scoop" = 1;
And if the rule 'methods with underscores in their name need quotationmarks' is correct, shouldn't it be

Code: Select all

"like_ship" = alloy;
in Ahruman's script?
Post Reply