Scripts/exhibitions.js |
"use strict";
this.name = "exhibitions";
this.author = "Norby";
this.copyright = "2013 Norbert Nagy";
this.licence = "CC BY-NC-SA 3.0";
this.description = "Ship exhibitions near witchpoints where player can earn Visitor Levels.";
//customizable properties
this.$ExhibitionsAllShipsInPrivateExhibition = false; //show NPC ships in Private Exhibition (cheat)
this.$ExhibitionsLog = false; //verbose log
this.$ExhibitionsMaxShipsInLargeExhibitions = 144; //should be square number and min. 64
this.$ExhibitionsMinFPS = 20; //split Private Exhibition to get more than this frames per second
this.$ExhibitionsSpace = 150; //m space between ships in exhibition matrix
//internal properties, should not touch
this.$ExhibitionsEndDate = []; //store the last valid date of exhibitions
this.$ExhibitionsFCB = null; //FrameCallBack to fill up and rotate exhibition
this.$ExhibitionsRoles = //for large exhibitions, without escort, hunter, thargoid, trader, player and pirate
["interceptor","miner","police","scavenger","shuttle","buoy","cargopod","missile"];
this.$ExhibitionsJ = 0; //index in player ships during exhibition creation, 0 mean no active exhibition
this.$ExhibitionsLastMenu = 0; //set marker to the lastly used exhibition menu line
this.$ExhibitionsLastStation = null; //Private Exhibition will before this station, update when dock into a new one
this.$ExhibitionsMenuFCB = null; //FrameCallBack for exhibitions menu
this.$ExhibitionsMO = null; //store initial orientation in menu
this.$ExhibitionsPerm = false; //permission to rotate ships in current exhibition
this.$ExhibitionsPermReqSent = false; //permission request sent
this.$ExhibitionsPosition = [null, null, null, null]; //pos, ori, vR, vU of exhibitions, will adjusted to player
this.$ExhibitionsSalon = 0; //Salon mean Private Exhibition in short, this variable avoid recreating ships after jump
this.$ExhibitionsSalonCost = 100; //must match with the cost of Private Exhibition Control in equipment.plist
this.$ExhibitionsSalonDelta = 0; //count delta to determine FPS in Private Exhibition
this.$ExhibitionsSalonDeltaC = 0; //counter to determine FPS in Private Exhibition
this.$ExhibitionsSalonJ = 0; //index in player ships during Private Exhibition creation
this.$ExhibitionsSalonO = null; //store Salon initial orientation
this.$ExhibitionsSalonP = null; //store Salon central position
this.$ExhibitionsSalonR = null; //store Salon initial vectorRight
this.$ExhibitionsSalonRot = false; //rotating Salon
this.$ExhibitionsSalonU = null; //store Salon initial vectorUp
this.$ExhibitionsSalonFCB = null; //FrameCallBack to fill up and rotate Salon
this.$ExhibitionsSalonShips = []; //store salon ships to fine if destroyed by player
this.$ExhibitionsSalonPart = 1; //actual part in splitted salon
this.$ExhibitionsSalonPartMax = 1; //salon splitted into how many parts
this.$ExhibitionsShips = []; //store ships to fine if destroyed by player
this.$ExhibitionsShipKeys = []; //store ship keys
this.$ExhibitionsSystems = []; //store system IDs of exhibitions
this.$ExhibitionsStartDate = []; //store start date of exhibitions
this.$ExhibitionsType = []; //store types of introduced exhibitions
this.$ExhibitionsTypes = [["All exhibitions","ship"], //0. line in this array mean all exhibitions
["Large exhibitions","many"], //special type for $ExhibitionsRoles
["Escort exhibitions","escort"], //type-role pairs, max. about 10 fit into the menu
["Hunter exhibitions","hunter"],
["Trader exhibitions","trader"],
["Pirate meetings","pirate"]];
this.$ExhibitionsTimer = null; //wait for Gallery startUp finished
this.$ExhibitionsTimerPerm = null; //timer for permission
this.$ExhibitionsU = null; //store initial vectorUp
this.$ExhibitionsVisited = []; //store of the visited exhibitions
this.$ExhibitionsVisKey = []; //startdate+systemid of visited exhibitions (unique key)
this.$ExhibitionsVisitor = ["a Novice Visitor.", "an Unexpected Visitor.", "a Poor Visitor.",
"a Below Average Visitor.", "an Average Visitor.", "an Above Average Visitor.",
"a Competent Visitor.", "a Trustworthy Visitor!", "an Expected Visitor!",
"the only Elite Visitor in this Ooniverse!"]; //string of visitor level
//equipment events
this.activated = function () { //attached to Private Exhibition Control equipment
var e = worldScripts["exhibitions"];
if( e.$ExhibitionsSalonRot ) {
e.$ExhibitionsSalonRot = false;
player.consoleMessage("Stop Private Exhibition rotation");
} else {
e.$ExhibitionsSalonRot = true;
player.consoleMessage("Start Private Exhibition rotation");
}
}
this.mode = function () { //attached to Private Exhibition Control equipment
var e = worldScripts["exhibitions"];
if( e.$ExhibitionsSalonPartMax > 1 ) { //step to the next part in splitted salon
var p = e.$Exhibitions_SalonShips();
if( e.$ExhibitionsSalonPart < e.$ExhibitionsSalonPartMax )
e.$ExhibitionsSalonPart++; //next part
else e.$ExhibitionsSalonPart = 1; //first part
var s = e.$ExhibitionsSalonShips;
for( var i = 0; i < s.length; i++ ) {
if( s[i] && s[i].isValid ) s[i].remove(true); //remove other parts of salon
}
delete e.$ExhibitionsSalonShips;
e.$ExhibitionsSalonShips = [];
var sp = Math.floor( p.length / e.$ExhibitionsSalonPartMax ); ///ships in one part
var imin = 0;
if( e.$ExhibitionsSalonPart > 1 )
imin = Math.floor( ( e.$ExhibitionsSalonPart - 1 ) * sp );
var imax = p.length; //last part show last ship also
if( e.$ExhibitionsSalonPart < e.$ExhibitionsSalonPartMax )
imax = Math.floor( e.$ExhibitionsSalonPart * sp ) - 1;
if( e.$ExhibitionsLog )
log("Exhibitions", "Private Exhibition ships:"+p.length+" part:"+e.$ExhibitionsSalonPart
+"/"+e.$ExhibitionsSalonPartMax+" sp:"+sp+" imin:"+imin+" imax:"+imax);
for( var i = imin; i <= imax && i < p.length; i++ ) {
e.$Exhibitions_Salon2( i ); //create ships in actual part
}
player.consoleMessage("Private Exhibit "+e.$ExhibitionsSalonPart //+"/"+e.$ExhibitionsSalonPartMax
+": Showing "+(i-imin)+" of "+p.length+" ships");
} else player.consoleMessage("Private Exhibition show "+e.$ExhibitionsSalonShips.length+" ships");
}
//world script events
this.startUp = function() {
this.$ExhibitionsJ = 0; //index in player ships during exhibition creation
this.$ExhibitionsLastMenu = 0; //set marker to the lastly used exhibition menu line
if( player.ship && player.ship.docked )
this.$ExhibitionsLastStation = player.ship.dockedStation;
this.$ExhibitionsPerm = false; //permission to rotate ships in current exhibition
this.$ExhibitionsPermReqSent = false; //permission request sent
this.$ExhibitionsSalon = missionVariables.$ExhibitionsSalon; //recreate ships after load game if ordered before
this.$ExhibitionsSalonDelta = 0; //count delta to determine FPS in Salon
this.$ExhibitionsSalonDeltaC = 0; //counter to determine FPS in Salon
this.$ExhibitionsSalonJ = 0; //index in player ships during Salon creation
this.$ExhibitionsSalonRot = false; //rotating Salon
this.$ExhibitionsSalonShips = []; //store ships to fine if destroyed by player
this.$ExhibitionsSalonPartMax = 1;
this.$ExhibitionsShips = []; //store ships to fine if destroyed by player
this.$ExhibitionsSystems = []; //store system IDs of exhibitions
var mv = missionVariables.$ExhibitionsSystems;//load advertised exhibitions from savegame
if( !mv ) this.$ExhibitionsSystems = []; else this.$ExhibitionsSystems = mv.split(",");
mv = missionVariables.$ExhibitionsStartDate;
if( !mv ) this.$ExhibitionsStartDate = []; else this.$ExhibitionsStartDate = mv.split(",");
mv = missionVariables.$ExhibitionsEndDate;
if( !mv ) this.$ExhibitionsEndDate = []; else this.$ExhibitionsEndDate = mv.split(",");
mv = missionVariables.$ExhibitionsType;
if( !mv ) this.$ExhibitionsType = []; else this.$ExhibitionsType = mv.split(",");
if( !(this.$ExhibitionsSystems.length > 0) ) //make new list if empty (first run)
this.$Exhibitions_Create(clock.days);
mv = missionVariables.$ExhibitionsVisited;
if( !mv ) this.$ExhibitionsVisited = [];
else if( (mv+"").indexOf(",") ) this.$ExhibitionsVisited = (mv+"").split(","); //need +"" for bugfix
else this.$ExhibitionsVisited = [mv];
mv = missionVariables.$ExhibitionsVisKey;
if( !mv ) this.$ExhibitionsVisKey = [];
else if( (mv+"").indexOf(",") ) this.$ExhibitionsVisKey = (mv+"").split(","); //need +"" for bugfix
else this.$ExhibitionsVisKey = [mv];
if( this.$ExhibitionsLog ) { //log first list also
log("Exhibitions", "ExhibitionsSystems ("+this.$ExhibitionsSystems.length+"): "+this.$ExhibitionsSystems);
log("Exhibitions", "ExhibitionsStartDate ("+this.$ExhibitionsStartDate.length+"): "+this.$ExhibitionsStartDate);
log("Exhibitions", "ExhibitionsEndDate ("+this.$ExhibitionsEndDate.length+"): "+this.$ExhibitionsEndDate);
log("Exhibitions", "ExhibitionsType ("+this.$ExhibitionsType.length+"): "+this.$ExhibitionsType);
log("Exhibitions", "ExhibitionsVisited ("+this.$ExhibitionsVisited.length+"): "+this.$ExhibitionsVisited);
log("Exhibitions", "ExhibitionsVisKey ("+this.$ExhibitionsVisKey.length+"): "+this.$ExhibitionsVisKey);
}
this.$ExhibitionsTimer = new Timer(this, this.$Exhibitions_Timed, 1);//need wait for gallery startUp finished
if( player.ship && player.ship.docked ) this.shipDockedWithStation( player.ship.dockedStation ); //set interface
else if( system ) this.shipDockedWithStation( system.mainStation );//fallback
}
this.dayChanged = function(newday) {
if(!system || system.isInterstellarSpace) return;
this.$Exhibitions_Create(newday); //make new ones
var openex = false;
if( this.$ExhibitionsJ > 0 ) openex = true;
if( this.$Exhibitions_CheckSystem() ) //create ships if there are an exhibition in this system today
if( !openex ) player.consoleMessage("Exhibition open at witchpoint!",5);
for( var x = 0; x < this.$ExhibitionsEndDate.length; x++) { //remove expired items from all array
if( this.$ExhibitionsEndDate[ x ] < newday ) {
this.$ExhibitionsSystems.splice(x,1);
this.$ExhibitionsStartDate.splice(x,1);
this.$ExhibitionsEndDate.splice(x,1);
this.$ExhibitionsType.splice(x,1);
x--;
}
}
}
this.playerBoughtEquipment = function(equipmentKey) {
if(equipmentKey === ("EQ_SALON_CONTROL")) {
this.$ExhibitionsSalon = 1; //recreate ships after load game
clock.addSeconds(86400*(1+Math.random()));
this.$Exhibitions_Salon();
}
}
this.playerEnteredNewGalaxy = function(galaxyNumber) { //make new exhibitions
this.$ExhibitionsEndDate = []; //store the last valid date of exhibitions
this.$ExhibitionsSystems = []; //store system IDs of exhibitions
this.$ExhibitionsStartDate = []; //store start date of exhibitions
this.$ExhibitionsType = []; //store types of introduced exhibitions
this.$Exhibitions_Create(clock.days); //recreate exhibitions
}
this.playerWillSaveGame = function(message) {
missionVariables.$ExhibitionsVisited = this.$ExhibitionsVisited;
missionVariables.$ExhibitionsVisKey = this.$ExhibitionsVisKey;
missionVariables.$ExhibitionsSalon = this.$ExhibitionsSalon;
missionVariables.$ExhibitionsSystems = this.$ExhibitionsSystems;
missionVariables.$ExhibitionsStartDate = this.$ExhibitionsStartDate;
missionVariables.$ExhibitionsEndDate = this.$ExhibitionsEndDate;
missionVariables.$ExhibitionsType = this.$ExhibitionsType;
}
this.shipDockedWithStation = function(station)
{
if( this.$ExhibitionsLastStation != station ) {
this.$ExhibitionsLastStation = station; //save lastly docked station to check if changed
this.$Exhibitions_SalonRemove();//to can buy new salon placed before this new station
}
if( isValidFrameCallback( this.$ExhibitionsFCB ) )
removeFrameCallback( this.$ExhibitionsFCB );
this.$ExhibitionsPerm = false; //permission to rotate ships in current exhibition
this.$ExhibitionsPermReqSent = false; //permission request sent
var len = 0;
if( this.$ExhibitionsVisited ) len = this.$ExhibitionsVisited.length;
var exs = len;
var exv = "";
if( len > 0 ) exv += " - you are "+(this.$ExhibitionsVisitor[ this.$Exhibitions_VisitorLevel() ]);
station.setInterface("Exhibitions",{
title: "Exhibitions ("+exs+" visited)"+exv,
category: "Ship Systems",
summary: "Check incoming ship meetings to extend your Gallery with new ships and increase your Visitor Level.",
callback: this.$Exhibitions_Interface.bind(this)
});
}
this.shipKilledOther = function(whom, damageType) {
if( this.$ExhibitionsShips && this.$ExhibitionsShips.indexOf(whom) > -1 ) {
player.consoleMessage("GalCop fined you "+formatCredits(10000, false, true)
+" for destroyng an Exhibition ship", 10);
player.credits -= 100000;
player.score--;
}
if( this.$ExhibitionsSalonShips && this.$ExhibitionsSalonShips.indexOf(whom) > -1 ) {
player.consoleMessage("GalCop fined you "+formatCredits(10000, false, true)
+" for destroying a Private Exhibition ship", 10);
player.credits -= 10000;
player.score--;
}
}
this.shipTargetAcquired = function(target) { //flag
var e = worldScripts["exhibitions"];
if( e.$ExhibitionsJ > 0 && e.$ExhibitionsShips && e.$ExhibitionsShips.indexOf(target) > -1 ) {
var si = e.$ExhibitionsSystems.indexOf(system.ID+"");//need +"" for bugfix
if( si > -1 ) {
var key = e.$ExhibitionsStartDate[si]+""+galaxyNumber+""+system.ID; //unique for each exhibitions
if( e.$ExhibitionsVisKey.indexOf(key) == -1 ) { //new visit
var rep = e.$Exhibitions_VisitorLevel();
if( !e.$ExhibitionsVisited ) this.$ExhibitionsVisited = []; //for sure
if( !e.$ExhibitionsVisKey ) this.$ExhibitionsVisKey = []; //for sure
var len = e.$ExhibitionsVisited.length;
e.$ExhibitionsVisited.push(clock.days+": "+system.name+" in "+(galaxyNumber+1)+" galaxy");
e.$ExhibitionsVisKey.push(key);
var msg = "You visited your "+(len+1)+" exhibition.";
player.consoleMessage(msg, 10);
if( e.$ExhibitionsLog ) log("Exhibitions", msg+" "+key);
var rep2 = e.$Exhibitions_VisitorLevel();
if( rep2 > rep ) {
msg = "Congratulations. You are "+e.$ExhibitionsVisitor[ rep2 ];
player.commsMessage(msg, 10);
if( e.$ExhibitionsLog ) log("Exhibitions", msg);
}
}
}
//request permission for rotate ships
if( !this.$ExhibitionsPerm ) {
if( !this.$ExhibitionsTimerPerm && !this.$ExhibitionsPermReqSent ) {
this.$ExhibitionsPermReqSent = true;
player.consoleMessage("Permission requested to rotate ships in this exhibition", 10);
var t = Math.ceil(Math.random() * 30); //max. 30 seconds
this.$ExhibitionsTimerPerm = new Timer(this, this.$Exhibitions_TimedPerm, t);
} else {
player.consoleMessage("Please wait. You will get permission soon.", 5);
}
}
}
}
this.shipWillEnterWitchspace = function() {
delete this.$ExhibitionsShips;
this.$ExhibitionsShips = [];
if( isValidFrameCallback( this.$ExhibitionsFCB ) )
removeFrameCallback( this.$ExhibitionsFCB );//stop rotate
this.$ExhibitionsLastStation = null; //clear last station
this.$ExhibitionsSalon = false; //do not recreate ships in salon after hyperjump
this.$ExhibitionsSalonDeltaC = 0; //count delta to determine FPS in Salon
delete this.$ExhibitionsSalonShips;
this.$ExhibitionsSalonShips = [];
this.$ExhibitionsSalonPartMax = 1;
if( isValidFrameCallback( this.$ExhibitionsSalonFCB ) )
removeFrameCallback( this.$ExhibitionsSalonFCB );//stop rotate
player.ship.removeEquipment("EQ_SALON_CONTROL");
}
this.shipWillExitWitchspace = function() { //use this event due to shipExitedWitchspace is not working in v1.77
this.$ExhibitionsPerm = false; //permission to rotate ships in current exhibition
this.$ExhibitionsPermReqSent = false;
if(system && !system.isInterstellarSpace) this.$Exhibitions_CheckSystem(); //create ships after hyperjump
}
this.shipWillLaunchFromStation = function() {
player.ship.hudHidden = false;
this.$ExhibitionsPerm = false; //permission to rotate ships in current exhibition
this.$ExhibitionsPermReqSent = false; //permission request sent
if( this.$ExhibitionsJ > 0 ) {
if( !isValidFrameCallback( this.$ExhibitionsFCB ) )
this.$ExhibitionsFCB = addFrameCallback( this.$Exhibitions_FCB ); //add ships and rotate
} else this.$Exhibitions_CheckSystem(); //recreate ships after load game
}
//Exhibitions methods
this.$Exhibitions_CheckSystem = function() {
var e = worldScripts["exhibitions"];
var x = e.$ExhibitionsSystems.indexOf( system.ID+"" );//need +"" for bugfix
if( e.$ExhibitionsLog ) log("Exhibitions", " CheckSystem:"+system.ID+" "+x+" "+e.$ExhibitionsJ+" "
+clock.days+" "+e.$ExhibitionsStartDate[ x ]+"-"+e.$ExhibitionsEndDate[ x ]+" s"+e.$ExhibitionsSystems[x]);
if( x != -1 && clock.days >= e.$ExhibitionsStartDate[ x ]
&& clock.days <= e.$ExhibitionsEndDate[ x ] ) {
if( e.$ExhibitionsJ == 0 ) e.$Exhibitions_Show( x ); //only if not shown before
return( true );
} else e.$Exhibitions_Remove(); //remove if last day elapsed
return( false ); //no exhibition
}
this.$Exhibitions_Create = function( days ) {
if(!system || system.isInterstellarSpace) return;
var tlen = this.$ExhibitionsTypes.length;
var dlen = this.$ExhibitionsStartDate.length;
var maxstartdate = 0;
if( dlen > 0 ) maxstartdate = this.$ExhibitionsStartDate.sort()[dlen-1];
if( maxstartdate == 0 ) {
maxstartdate = 2084002;
if( galaxyNumber == 0 ) {
this.$ExhibitionsSystems.push("55"); //long exhibition in Leesti for demonstration, need in "" for bugfix
this.$ExhibitionsStartDate.push( 2084001 );
this.$ExhibitionsEndDate.push( 2084060 );
this.$ExhibitionsType.push( 1 ); //large exhibition
}
}
var maxdate = days + 100; //new exhibitions introduced 100 days before
if( !( dlen > 0 && maxstartdate > maxdate ) ) {
for( var i = maxstartdate; i < maxdate; i++ ) {
var r = system.scrambledPseudoRandomNumber(i);
var t = Math.floor(r * (tlen)); //one open in every day, equal odds for each type
var sy = Math.floor(r * 256) + ""; //need +"" for bugfix, 1/tlen odds for no opening
if( t > 0 && this.$ExhibitionsSystems.indexOf(sy) == -1 ) {
this.$ExhibitionsSystems.push( sy );
this.$ExhibitionsStartDate.push( i );
this.$ExhibitionsEndDate.push( i + 1 + Math.floor(r * 60) );//open max. 2 months
this.$ExhibitionsType.push( t );
}
}
}
}
this.$Exhibitions_FCB = function( delta ) {
var e = worldScripts["exhibitions"];
var p = e.$ExhibitionsShipKeys;
if( e.$ExhibitionsJ < p.length ) {
e.$Exhibitions_Show2( e.$ExhibitionsJ++ ); //spawn Salon ships in cycle
if( e.$ExhibitionsJ >= p.length ) {
var x = e.$ExhibitionsSystems.indexOf( system.ID+"" );//need +"" for bugfix
var type = e.$ExhibitionsTypes[ e.$ExhibitionsType[ x ] ][1]; //escort, hunter, trader, pirate
player.consoleMessage("Exhibition of "+type+" ships is open at witchpoint", 10);
}
} else {
if( e.$ExhibitionsPerm ) {
var enc = worldScripts["gallery"].$GalleryEncounters;
var s = e.$ExhibitionsShips;
var m = null;
for( var i = 0; i < s.length; i++ ) {
m = s[i];
if( enc.indexOf(m.dataKey) == -1 && m.orientation //rotate new ship
|| player.ship && player.ship.target == s[i] ) {//or current target
m.orientation = m.orientation.rotateY( delta ).rotateZ( delta );
}
}
}
}
}
this.$Exhibitions_Interface = function() {
player.ship.hudHidden = true;//to shift down the menu
this.$ExhibitionsLastMenu = 0;
var g = worldScripts["gallery"];
if( g && isValidFrameCallback( g.$GalleryFCB ) ) removeFrameCallback( g.$GalleryFCB ); //need for bugfix
if( !isValidFrameCallback( this.$ExhibitionsMenuFCB ) )
this.$ExhibitionsMenuFCB = addFrameCallback( this.$Exhibitions_MenuFCB ); //will call ex.menu
}
this.$Exhibitions_Menu = function() { //exhibitions menu
var e = worldScripts["exhibitions"];
var g = worldScripts["gallery"];
var c = [];
if(e.$ExhibitionsLog) log("Exhibitions", "Visitor:"+e.$Exhibitions_VisitorLevel()
+" "+e.$ExhibitionsVisitor[e.$Exhibitions_VisitorLevel()]);
var len = 0;
if( e.$ExhibitionsVisited ) len = e.$ExhibitionsVisited.length;
var exs = "You have not visited any exhibitions yet.";
if( len > 0 ) {
exs = "You visited "+len+" exhibition";
if( len > 1 ) exs += "s";
exs += ". You are "+(e.$ExhibitionsVisitor[ e.$Exhibitions_VisitorLevel() ]);
}
var msg = [];
for( var i = 0; i < e.$ExhibitionsTypes.length; i++ ) { //make menu for each type, start from 1 (not from 0!)
c.push(e.$ExhibitionsTypes[i][0]);
var ex = "";
var k = 0;
for( var j = 0; j < e.$ExhibitionsType.length && k < 23 - e.$ExhibitionsTypes.length ; j++ ) {
if( i == 0 || i == e.$ExhibitionsType[j] ) {//list one type into type specific menus
k++;
ex += e.$ExhibitionsStartDate[j] + " - " + e.$ExhibitionsEndDate[j] + " "
+ System.infoForSystem(galaxyNumber, e.$ExhibitionsSystems[j]).name;
if( i == 0 ) ex += " - " + e.$ExhibitionsTypes[e.$ExhibitionsType[j]][1] + " ships\n";
else ex += "\n";
}
}
msg.push(ex);
}
var pur = "purchasable ships";
if( e.$ExhibitionsAllShipsInPrivateExhibition ) pur = "all ships";
c.push("Private Exhibition of "+pur);
msg.push("You need "+formatCredits(e.$ExhibitionsSalonCost, false, true)+" to order your private exhibition.");
c.push("Gallery of encounters");
msg.push("Go to Gallery");
c.push("Exit");
msg.push("Bye");
var startori = 0;
var ti = "Exhibitions";
if( e.$ExhibitionsLastMenu > 0 ) ti = c[e.$ExhibitionsLastMenu-10]+" "+clock.days+"-";
else { e.$ExhibitionsMO = null; startori = 1; }
msg[-10] = [ exs+"\n\nYou can choose exhibitions below. You will find them near witchpoints."
+" Target at least one ship within to increase your Visitor Level."
+" If you are lucky, you will find new ship types. You can add these to your Gallery by targeting them."
+"\n\nIn the Private Exhibition menu, you can order an exhibition of "+pur+"."
+"\nYou can go to the Gallery or exit when finished."];
var ms = msg[e.$ExhibitionsLastMenu-10];
if( e.$ExhibitionsLastMenu == 0 ) e.$ExhibitionsLastMenu = 10;
var ch = { "_10" : c[0],
"_11" : c[1],
"_12" : c[2],
"_13" : c[3],
"_14" : c[4],
"_15" : c[5],
"_16" : c[6],
"_17" : c[7],
"_18" : c[8],
"_19" : c[9],
"_20" : c[10],
"_21" : c[11],
"_22" : c[12],
"_23" : c[13],
"_24" : c[14],
"_25" : c[15],
"_26" : c[16],
"_27" : c[17],
"_28" : c[18],
"_29" : c[19],
"_30" : c[20],
"_31" : c[21],
"_32" : c[22],
"_33" : c[23],
"_34" : c[24],
"_35" : c[25]
};
if( isValidFrameCallback( e.$ExhibitionsMenuFCB ) ) removeFrameCallback( e.$ExhibitionsMenuFCB );
mission.runScreen({
title: ti,
message: ms,
model: "["+player.ship.dataKey+"]",
modelPersonality: 0,
spinModel:false,
background: "gallery_bg.png",
initialChoicesKey: "_"+e.$ExhibitionsLastMenu,
choices: ch
},function(choice) {
var ch = 10;
if( choice ) ch = choice.substr(1); //cut starting "_"
e.$ExhibitionsLastMenu = 1 * ch;
if(e.$ExhibitionsLog) log("Exhibitions", "LastMenu: "+e.$ExhibitionsLastMenu);
if( e.$ExhibitionsLastMenu - 10 < c.length - 3 ) { //exhibition types, draw menu again
if( !isValidFrameCallback( e.$ExhibitionsMenuFCB ) )
e.$ExhibitionsMenuFCB = addFrameCallback( e.$Exhibitions_MenuFCB );
} else switch( e.$ExhibitionsLastMenu - 10 ) {
case (c.length - 3) : //Salon
e.$Exhibitions_SalonMenu();
break;
case (c.length - 2) : //Go to Gallery
g.$Gallery_Interface2( g.$GalleryShowAll ); //show from the lastly viewed ship
break;
case (c.length - 1) : //Exit
break;
}
});
var m = mission.displayModel;
if( m ) {
if( !e.$ExhibitionsMO ) e.$ExhibitionsMO = m.orientation; //save orientation in opening screen
var w = oolite.gameSettings.gameWindow; //correction if not in widescreen
var wide = Math.max( 0.01, ( w.width / w.height ) / g.$GalleryDefaultZoom );
m.position = Vector3D(m.position.x, m.position.y, m.position.z * wide * 0.9); //zoom more closer
m.orientation = e.$ExhibitionsMO.rotateZ( -Math.PI/2 ).rotateX( -Math.PI/2 )
.rotateY( - Math.PI/4 * ( e.$ExhibitionsLastMenu + 5 - startori ) );
}
}
this.$Exhibitions_MenuFCB = function( delta ) { //FrameCallBack for exhibitions menu
var e = worldScripts["exhibitions"];
if( isValidFrameCallback( e.$ExhibitionsMenuFCB ) ) removeFrameCallback( e.$ExhibitionsMenuFCB );
e.$Exhibitions_Menu();
}
this.$Exhibitions_Remove = function() { //remove ships
this.$ExhibitionsJ = 0; //index in ships during creation
var s = this.$ExhibitionsShips;
for( var i = 0; i < s.length; i++ ) {
if( s[i] && s[i].isValid ) s[i].remove(true);
}
this.$ExhibitionsPosition = [null, null, null, null];
if( isValidFrameCallback( this.$ExhibitionsFCB ) )
removeFrameCallback( this.$ExhibitionsFCB );
}
this.$Exhibitions_Salon = function() {
if(!system || system.isInterstellarSpace) return;
this.$ExhibitionsSalonJ = 0; //index in player ships during Salon creation
var st = player.ship; //at load game or in-fly debug
if( player.ship.docked ) st = player.ship.dockedStation;
this.$ExhibitionsSalonO = st.orientation;
this.$ExhibitionsSalonP = st.position.add(st.vectorForward.multiply( 10300 )); //Salon central position
this.$ExhibitionsSalonR = st.vectorRight; //store initial vectorRight
this.$ExhibitionsSalonU = st.vectorUp; //store initial vectorUp
player.ship.awardEquipment("EQ_SALON_CONTROL");//need after load game
if( !isValidFrameCallback( this.$ExhibitionsSalonFCB ) )
this.$ExhibitionsSalonFCB = addFrameCallback( this.$Exhibitions_SalonFCB );
}
this.$Exhibitions_Salon2 = function( j ) {
if(!system || system.isInterstellarSpace) return;
var e = worldScripts["exhibitions"];
var g = worldScripts["gallery"];
var p = e.$Exhibitions_SalonShips();
var space = e.$ExhibitionsSpace;//between ships
var st = player.ship; //at load game or in-fly debug
if( player.ship.docked ) st = player.ship.dockedStation;
var sq = Math.ceil(Math.sqrt(p.length));
// for( var j = 0; j < p.length; j++ ) { //SalonFCB make this cycle to allow fast forwarding game clock parallelly
var key = p[j];
var row = Math.floor(j/sq);
var pos = e.$ExhibitionsSalonP.add( e.$ExhibitionsSalonR.multiply( space * ( j - sq * row - sq / 2 + 0.5 ) ) )
.add( e.$ExhibitionsSalonU.multiply( space * ( row - sq / 2 + 0.5 ) ) );//square align
var ships = system.addShips("["+key+"]", 1, pos, 5);
if( ( !ships || !ships[0] ) && key.indexOf("-player") > -1 ) { //handle unsuccesful ship creation
key = key.slice(0, key.indexOf("-player")); //remove -player
ships = system.addShips("["+key+"]", 1, pos, 5);
if( ships ) e.$Exhibitions_SalonAdd( ships[0], key, st, e, space, j );
} else if( ships && ships[0] ) e.$Exhibitions_SalonAdd( ships[0], key, st, e, space, j );
// }
}
this.$Exhibitions_SalonAdd = function( ship, key, st, e, space, j ) {
if( !ship ) { //handle unsuccesful ship creation
if(e.$ExhibitionsLog) log("Exhibitions", "Failed addShips ["+key+"] to Private Exhibition.");
} else {
if(e.$ExhibitionsLog) log("Exhibitions", "["+key+"] added to Private Exhibition.");
if( ship.escorts && ship.escorts.length > 0 )
for( var i = 0; i < ship.escorts.length; i++ ) ship.escorts[i].remove(true);
ship.beaconCode = null; //fix for escorted mothership in escort contracts
if(ship.beaconLabel) ship.beaconLabel = "";
ship.bounty = 0;
ship.displayName = "[Private Exhibition] " + ship.displayName;
ship.setAI("nullAI.plist");
ship.setScript("exhibitions-ship-script.js"); //must deactivate the original script
ship.target = null;
ship.clearDefenseTargets();
// ship.scanClass = "CLASS_CARGO";
if( st ) ship.orientation = e.$ExhibitionsSalonO.rotateX(3*Math.PI/2);
var cr = ship.collisionRadius; //shift out large ships from the square plane
if( cr > space ) {
var c2 = 1; //prevent collision of two neighbour baseship
if( Math.floor( j / 2 ) == j / 2 ) c2 = -1;
var mul = c2 * (cr + 4 * space);
if(e.$ExhibitionsLog) log("Exhibitions", ship.displayName+" too large, shifted out "+j+" "+c2+" "+mul);
ship.position = ship.position.add( st.vectorForward.multiply( mul ) );
}
e.$ExhibitionsSalonShips.push(ship);
}
}
this.$Exhibitions_SalonFCB = function( delta ) {
var e = worldScripts["exhibitions"];
var p = e.$Exhibitions_SalonShips();
if( e.$ExhibitionsSalonJ < p.length ) {
if( e.$ExhibitionsSalonJ == 0 ) { //add active police as defenders of salon
var role = "police";
if( 6 <= system.techLevel ) role = "interceptor";
var eg = system.addShips(role, 1+Math.floor(system.government/2), e.$ExhibitionsSalonP, 2000);
if( eg ) for( var i = 0; i < eg.length; i++ ) {
if( eg[i] && eg[i].isValid ) eg[i].displayName = "[Private Exhibition Guard] "+eg[i].displayName;
}
}
e.$Exhibitions_Salon2( e.$ExhibitionsSalonJ++ ); //spawn Salon ships in cycle
} else {
if( e.$ExhibitionsSalonDeltaC > 0 ) {
if(e.$ExhibitionsLog) log("Exhibitions", "C:"+e.$ExhibitionsSalonDeltaC+" delta:"+delta
+" deltasum:"+e.$ExhibitionsSalonDelta);
e.$ExhibitionsSalonDeltaC++;
e.$ExhibitionsSalonDelta += delta;
}
if( e.$ExhibitionsSalonJ == p.length ) {
e.$ExhibitionsSalonJ++; //send message once only
player.consoleMessage(p.length+" ships arrived. Take off to view Private Exhibition.",10);
e.$ExhibitionsSalonRot = false; //rotating Salon
}
if( e.$ExhibitionsSalonJ > p.length && e.$ExhibitionsSalonDeltaC == 0
&& player.ship && !player.ship.docked ) { //wait for undock
e.$ExhibitionsSalonDelta = delta; //start count delta to determine FPS for Salon split
e.$ExhibitionsSalonDeltaC = 1;
}
if( e.$ExhibitionsSalonPartMax == 1 && e.$ExhibitionsSalonDelta > 2 ) { //after 2 seconds of measurement
var fps = e.$ExhibitionsSalonDeltaC / e.$ExhibitionsSalonDelta; ///frames per second
e.$ExhibitionsSalonDelta = delta;
// e.$ExhibitionsSalonDeltaC = 1;//restart measurement
e.$ExhibitionsSalonDeltaC = 0;//stop measurement
var split = "";
if( fps < e.$ExhibitionsMinFPS //too few FPS
&& player.ship && player.ship.position && e.$ExhibitionsSalonP
&& player.ship.position.distanceTo(e.$ExhibitionsSalonP) < 25000 ) { //not so far
e.$ExhibitionsSalonPartMax = Math.ceil( e.$ExhibitionsMinFPS / fps ); ///round up
var sp = Math.floor( p.length / e.$ExhibitionsSalonPartMax ); ///ships in one part
var sq = Math.ceil(Math.sqrt(p.length));
if( sp < sq ) //at least one row of ships in one part
e.$ExhibitionsSalonPartMax = Math.ceil( p.length / sq ); ///
e.$ExhibitionsSalonPart = 0; //will show the first part
split = ", split into "+e.$ExhibitionsSalonPartMax+" parts";
var button = "b";
if( oolite.gameSettings.keyConfig ) //from Oolite v.1.77.1
button = String.fromCharCode( oolite.gameSettings.keyConfig.key_mode_equipment );
player.consoleMessage("Private Exhibition split into "+e.$ExhibitionsSalonPartMax
+" parts. Prime Private Exhibition Control and press '"+button+"' to show next part", 10);
e.mode(); //hide parts of salon
}
if(e.$ExhibitionsLog)
log("Exhibitions", "Private Exhibition "+p.length+" ships, "+fps+" FPS"+split);
}
var s = e.$ExhibitionsSalonShips;
var m = null;
for( var i = 0; i < s.length; i++ ) {
m = s[i];
if( m && m.isValid && m.orientation && player.ship && //rotate all ships in salon
( e.$ExhibitionsSalonRot && player.ship.target != s[i] //or current target only
|| !e.$ExhibitionsSalonRot && player.ship.target == s[i] ) )
m.orientation = m.orientation.rotateZ( delta/1.5 );
}
}
}
this.$Exhibitions_SalonMenu = function() {
var e = worldScripts["exhibitions"];
var g = worldScripts["gallery"];
var pur = "purchasable ships";
if( e.$ExhibitionsAllShipsInPrivateExhibition ) pur = "all ships";
var msg = "You can order a Private Exhibition of "+pur
+" before this station for "+formatCredits(e.$ExhibitionsSalonCost, false, true)
+", but you need to allow 1-2 days for this to be set up. If you have an existing Private Exhibition,"
+" it will be renewed with this purchase."
+"\n\nYou will get a Private Exhibition Control primable equipment to start and stop rotation of ships"
+" in your Private Exhibition, or you can start and stop rotation of a single ship by targeting it."
+" Do not destroy ships in your Private Exhibition. If you do, you will be fined."
+" Private Exhibition will be closed if you dock with another station or jump into another system.";
mission.runScreen({
title: "Order a Private Exhibition",
message: msg,
model: "["+player.ship.dataKey+"]",
modelPersonality: 0,
spinModel:false,
background: "gallery_bg.png",
choices: {"_0":"No thanks","_1":"OK. I will pay and wait for ships!"}
},function(choice) {
e.$ExhibitionsLastMenu = 0; //will display initial message
switch(choice) {
case "_0":
if( !isValidFrameCallback( e.$ExhibitionsMenuFCB ) )
e.$ExhibitionsMenuFCB = addFrameCallback( e.$Exhibitions_MenuFCB );
break;
case "_1":
var saloncost = e.$ExhibitionsSalonCost; //must match with the cost in equipment.plist
if( player.ship.equipmentStatus("EQ_SALON_CONTROL") == "EQUIPMENT_OK" ) {
player.consoleMessage("Old Private Exhibition closed.",3);
e.$Exhibitions_SalonRemove();
}
if( player.credits >= saloncost ) {
player.credits -= saloncost;
player.ship.awardEquipment("EQ_SALON_CONTROL");
e.playerBoughtEquipment("EQ_SALON_CONTROL"); //do as if just bought one
//no FCBE setup so will exit from ex.menu
} else {
//display not enough money message
mission.runScreen({
title: "Order a Private Exhibition",
message: "You need "+formatCredits(e.$ExhibitionsSalonCost, false, true)
+" to order your Private Exhibition.",
model: "["+player.ship.dataKey+"]",
modelPersonality: 0,
spinModel:false,
background: "gallery_bg.png",
choices: {"_0":"Ok"}
},function(choice) {
//back to the exhibitions menu
if( !isValidFrameCallback( e.$ExhibitionsMenuFCB ) )
e.$ExhibitionsMenuFCB = addFrameCallback(e.$Exhibitions_MenuFCB);
});
}
break;
}
});
var w = oolite.gameSettings.gameWindow;
var wide = Math.max( 0.01, ( w.width / w.height ) / g.$GalleryDefaultZoom ); //correction if not in widescreen
var m = mission.displayModel;
if( m ) {
m.position = Vector3D(m.position.x, m.position.y, m.position.z * wide * 0.9); //zoom more closer
m.orientation = m.orientation.rotateZ( Math.PI/2 );
}
}
this.$Exhibitions_SalonShips = function() {
var g = worldScripts["gallery"];
if( worldScripts["exhibitions"].$ExhibitionsAllShipsInPrivateExhibition )
return( g.$GalleryAllObjects ); //cheat: all existing ships
else return( g.$GalleryKeysForRole[ 1 ] ); //player ships
}
this.$Exhibitions_SalonRemove = function() {
this.$ExhibitionsSalon = 0; //do not recreate ships after docked into a new station
this.$ExhibitionsSalonDeltaC = 0; //count delta to determine FPS in Salon
this.$ExhibitionsSalonJ = 0; //index in player ships during Salon creation
this.$ExhibitionsSalonO = null; //store Salon initial orientation
this.$ExhibitionsSalonP = null; //store Salon central position
this.$ExhibitionsSalonR = null; //store Salon initial vectorRight
this.$ExhibitionsSalonRot = false; //rotating Salon
this.$ExhibitionsSalonU = null; //store Salon initial vectorUp
var s = this.$ExhibitionsSalonShips;
for( var i = 0; i < s.length; i++ ) {
if( s[i] && s[i].isValid ) s[i].remove(true); //remove previous salon
}
delete this.$ExhibitionsSalonShips;
this.$ExhibitionsSalonShips = [];
this.$ExhibitionsSalonPartMax = 1;
if( isValidFrameCallback( this.$ExhibitionsSalonFCB ) )
removeFrameCallback( this.$ExhibitionsSalonFCB );
player.ship.removeEquipment("EQ_SALON_CONTROL"); //to can buy again
}
this.$Exhibitions_Show = function( x ) { //create ships
if(!system || system.isInterstellarSpace) return;
var e = worldScripts["exhibitions"];
var type = e.$ExhibitionsTypes[ e.$ExhibitionsType[ x ] ][1]; //escort, hunter, trader, pirate
var enc = worldScripts["gallery"].$GalleryEncounters;
e.$ExhibitionsShips = [];
e.$ExhibitionsShipKeys = [];
var sdk = [];
if (0 < oolite.compareVersion("1.79")) { //slow and limited method, use before Oolite v1.79
if( type == "many" ) { //from $ExhibitionsRoles
for( var i = 0; i < e.$ExhibitionsRoles.length; i++ ) {
var ships = system.addShips( e.$ExhibitionsRoles[i], //sum of 64 ship created
Math.ceil( 64 / e.$ExhibitionsRoles.length ), [0,0,0], 1000000 );
if( ships ) for( var i = 0; i < ships.length; i++ )
if( ships[i] && ships[i].isValid && sdk.indexOf(ships[i].dataKey) == -1 )
sdk.push( ships[i].dataKey );
}
if(e.$ExhibitionsLog) log("Exhibitions", type+": "+sdk);
sdk = sdk.concat(enc); //player and encountered ships at the end, show if anothers is not enough
} else {
var ships = system.addShips(type, 64, [0,0,0], 1000000);
if( ships ) for( var i = 0; i < ships.length; i++ )
if( ships[i] && ships[i].isValid && sdk.indexOf(ships[i].dataKey) == -1 )
sdk.push( ships[i].dataKey );
if(e.$ExhibitionsLog) log("Exhibitions", type+": "+sdk);
}
if( !sdk || sdk.length < 1 ) { //fallback to player ships
var ships = system.addShips("player", 64, [0,0,0], 1000000);
if( ships ) for( var i = 0; i < ships.length; i++ )
if( ships[i] && ships[i].isValid && sdk.indexOf(ships[i].dataKey) == -1 )
sdk.push( ships[i].dataKey );
if(e.$ExhibitionsLog) log("Exhibitions", "player: "+sdk);
}
} else { // Oolite v1.79 or later
if( type == "many" ) { //from $ExhibitionsRoles
for( var i = 0; i < e.$ExhibitionsRoles.length; i++ ) {
sdk = sdk.concat(Ship.keysForRole( e.$ExhibitionsRoles[i] ));
}
if(e.$ExhibitionsLog) log("Exhibitions", type+": "+sdk);
sdk = sdk.concat(enc); //player and encountered ships at the end, show if anothers is not enough
} else {
sdk = Ship.keysForRole( type );
if(e.$ExhibitionsLog) log("Exhibitions", type+": "+sdk);
}
if( !sdk || sdk.length < 1 ) {
sdk = Ship.keysForRole( "player" );//fallback to player ships
if(e.$ExhibitionsLog) log("Exhibitions", "player: "+sdk);
}
}
if( (!sdk || sdk.length < 1 ) && player.ship ) sdk = player.ship.dataKey;//last resort
if( !sdk || sdk.length < 1 ) { //should not happed
log("Exhibitions", "$Exhibitions_Show() failed. Can not find any dataKey to show");
return; //give up and exit to prevent errors
}
var maxnewship = 2; //a few new ship added into every exhibition only else reserves run out too early
var shipno = 12 + 52 * system.scrambledPseudoRandomNumber(e.$ExhibitionsType[ x ]); //max. 64 = 8*8
if( type == "many" ) shipno = Math.max(64, system.pseudoRandomNumber * e.$ExhibitionsMaxShipsInLargeExhibitions);
for( var i = 0; e.$ExhibitionsShipKeys.length < shipno && i < sdk.length; i++ ) {
var key = sdk[i];
if( ( key && enc.indexOf(key) != -1 || maxnewship-- > 0 )
&& key.indexOf("station") == -1 && key.indexOf("rock-hermit") == -1 ) {
//still not sure if this is a ship, further checking
if( Ship.shipDataForKey ) { //new fast method in 1.79 since 2014.05.19
var s = Ship.shipDataForKey(key);
if(this.$ExhibitionsLog) log("Exhibitions", j+". "+key+" shipDataForKey "+s);
if( s && s.max_flight_speed && s.max_flight_speed > 0 )
e.$ExhibitionsShipKeys.push(key); //ok, add it
} else { //old way for Oolite 1.77
if( key.indexOf("spacebar") == -1 ) //must check every problematic key
e.$ExhibitionsShipKeys.push(key); //maybe ok, add it
}
}
}
if( sdk && sdk.length < shipno ) //duplicate until contain enough ships
while( e.$ExhibitionsShipKeys.length < shipno && e.$ExhibitionsShipKeys.length < 1000 )
e.$ExhibitionsShipKeys = e.$ExhibitionsShipKeys.concat(e.$ExhibitionsShipKeys);
e.$ExhibitionsShipKeys.splice( shipno ); //shrink before short, can appear ships from the end of the alphabet also
e.$ExhibitionsShipKeys.sort();
if(e.$ExhibitionsLog) log("Exhibitions", "ExhibitionsShipKeys: "+e.$ExhibitionsShipKeys);
this.$ExhibitionsJ = 0; //index in player ships during exhibition creation
if( !isValidFrameCallback( this.$ExhibitionsFCB ) )
this.$ExhibitionsFCB = addFrameCallback( this.$Exhibitions_FCB ); //add ships and rotate
//add active police/pirate as defenders of exhibition
var role = "police";
if( 6 <= system.techLevel ) role = "interceptor";
if(type == "pirate") role = "pirate";
var base = 1;
if(type == "many") base += 1;
var pos = Vector3D(0,0,10000);
var ori = Quaternion(0, 0, 0, 0);
var vr = Vector3D(1, 0, 0);
var vu = Vector3D(0, 1, 0);
if( player.ship && player.ship.position ) {
if( player.ship.position.distanceTo([0,0,0]) < 25600 )
pos = player.ship.position.add(player.ship.vectorForward.multiply( 10000 ));
ori = player.ship.orientation;
vr = player.ship.vectorRight; //store initial vectorRight
vu = player.ship.vectorUp; //store initial vectorUp
}
this.$ExhibitionsPosition = [pos, ori, vr, vu];
var eg = system.addShips(role, base+Math.floor(system.government/4), pos, 2000);
if( eg ) for( var i = 0; i < eg.length; i++ ) {
if( eg[i] && eg[i].isValid ) eg[i].displayName = "[Exhibition Guard] "+eg[i].displayName;
}
}
this.$Exhibitions_Show2 = function( j ) {
if(!system || system.isInterstellarSpace) return;
var e = worldScripts["exhibitions"];
var p = e.$ExhibitionsShipKeys;
var space = e.$ExhibitionsSpace;//between ships
var sq = Math.ceil(Math.sqrt(p.length));
// for( var j = 0; j < p.length; j++ ) { //FCB make this cycle
var key = p[j];
var row = Math.floor(j/sq);
var pos = null;
if( e.$ExhibitionsPosition && e.$ExhibitionsPosition[0] ) pos = e.$ExhibitionsPosition[0]
.add( e.$ExhibitionsPosition[2].multiply( space * ( j - sq * row - sq / 2 + 0.5 ) ) )
.add( e.$ExhibitionsPosition[3].multiply( space * ( row - sq / 2 + 0.5 ) ) );//square align
else pos = [ space * ( j - sq * row - sq / 2 + 0.5 ), space * ( row - sq / 2 + 0.5 ), 10000 ];//fallback
var ships = system.addShips("["+key+"]", 1, pos, 5);
if( ( !ships || !ships[0] ) && key.indexOf("-player") > -1 ) { //handle unsuccesful ship creation
key = key.slice(0, key.indexOf("-player")); //remove -player
ships = system.addShips("["+key+"]", 1, pos, 5);
if( ships ) e.$Exhibitions_ShowAdd( ships[0], key, e, space, j );
} else if( ships && ships[0] ) e.$Exhibitions_ShowAdd( ships[0], key, e, space, j );
// }
}
this.$Exhibitions_ShowAdd = function( ship, key, e, space, j ) {
if( !ship ) { //handle unsuccesful ship creation
if(e.$ExhibitionsLog) log("Exhibitions", "Failed addShips ["+key+"] to the Exhibition.");
} else {
if(e.$ExhibitionsLog) log("Exhibitions", "["+key+"] added to the Exhibition.");
if( ship.escorts && ship.escorts.length > 0 )
for( var i = 0; i < ship.escorts.length; i++ ) ship.escorts[i].remove(true);
ship.beaconCode = null; //fix for escorted mothership in escort contracts
if(ship.beaconLabel) ship.beaconLabel = "";
ship.bounty = 0;
ship.displayName = "[Exhibition] " + ship.displayName;
ship.setAI("nullAI.plist");
ship.setScript("exhibitions-ship-script.js"); //must deactivate the original script
ship.target = null;
ship.clearDefenseTargets();
// ship.scanClass = "CLASS_CARGO";
var cr = ship.collisionRadius; //shift out large ships from the square plane
if( cr > space ) {
var c2 = 1; //prevent collision of two neighbour baseship
if( Math.floor( j / 2 ) == j / 2 ) c2 = -1;
var mul = c2 * (cr + 4 * space);
if(e.$ExhibitionsLog) log("Exhibitions", ship.displayName+" too large, shifted out "+j+" "+c2+" "+mul);
ship.position = ship.position.add( [0, 0, mul ] );
}
// if(e.$ExhibitionsLog) log("Exhibitions", "playerori:"+player.ship.orientation);
if( e.$ExhibitionsPosition && e.$ExhibitionsPosition[1] )
ship.orientation = e.$ExhibitionsPosition[1].rotateX( Math.PI/2 );
else if( player.ship && player.ship.orientation ) //fallback
ship.orientation = player.ship.orientation.rotate( Vector3D(1,0,0), Math.PI/2 );
if( !e.$ExhibitionsShips ) e.$ExhibitionsShips = [ship];
else e.$ExhibitionsShips.push(ship);
}
}
this.$Exhibitions_Timed = function() { //need wait for Gallery startUp finished to get filled ship dataKey arrays
var e = worldScripts["exhibitions"];
if( e.$ExhibitionsTimer ) {
e.$ExhibitionsTimer.stop();
delete e.$ExhibitionsTimer;
}
if(e.$ExhibitionsSalon) e.$Exhibitions_Salon(); //recreate after load game if ordered before
e.$Exhibitions_CheckSystem(); //recreate exhibition after load game if any
}
this.$Exhibitions_TimedPerm = function() { //
var e = worldScripts["exhibitions"];
if( e.$ExhibitionsTimerPerm ) {
e.$ExhibitionsTimerPerm.stop();
delete e.$ExhibitionsTimerPerm;
}
if( e.$ExhibitionsPerm ) { //end of permitted time for rotation
e.$ExhibitionsPerm = false;
e.$ExhibitionsPermReqSent = false;
player.consoleMessage("Permission revoked. You can request again by targeting another ship in the exhibition", 10);
} else if( e.$ExhibitionsPermReqSent ) { //end of wait for permission
e.$ExhibitionsPerm = true;
e.$ExhibitionsPermReqSent = false;
player.consoleMessage("Permission granted. You can rotate ships in the exhibition for 5 minutes", 10);
e.$ExhibitionsTimerPerm = new Timer(e, e.$Exhibitions_TimedPerm, 300);
}
}
this.$Exhibitions_VisitorLevel = function() {
var e = worldScripts["exhibitions"];
var len = 0;
if( e.$ExhibitionsVisited ) len = e.$ExhibitionsVisited.length;
var rep = 0;
if( len < 2 ) rep = 0;
else if( len < 4 ) rep = 1;
else if( len < 8 ) rep = 2;
else if( len < 16 ) rep = 3;
else if( len < 32 ) rep = 4;
else if( len < 64 ) rep = 5;
else if( len < 100 ) rep = 6;
else if( len < 300 ) rep = 7;
else if( len < 1000 ) rep = 8;
else rep = 9; //Elite Visitor
return( rep );
} |
Scripts/gallery.js |
"use strict";
this.name = "gallery";
this.author = "Norby";
this.copyright = "2013 Norbert Nagy";
this.licence = "CC BY-NC-SA 3.0";
this.description = "Show installed ships and objects in an interface screen.";
//customizable properties
this.$GalleryAll = true; //Gallery of all objects (cheat)
this.$GalleryDefaultZoom = 1.5; //default size of ships
this.$GalleryMaxIt = 5; //max. iteration in Oolite v1.77, reduce if cause "Universe is full" or crash to desktop
this.$GalleryLog = false; //verbose log
this.$GalleryRoles = ["all","player", //main roles, you can add more but must leave these first two untouched
"escort","hunter","interceptor","miner","pirate","police","trader","scavenger","shuttle","thargoid",
"asteroid","boulder","buoy","cargopod","missile","station"];
this.$GallerySpeed = 2; //move and zoom speed
//internal properties, should not touch
this.$GalleryAllObjects = []; //store all ship and object keys
this.$GalleryAllNames = []; //all ship names for search
this.$GalleryEncounters = []; //store encountered ship keys for savegame also
this.$GalleryEncNames = []; //encountered ship names for search
this.$GalleryFCB = null; //FrameCallBack for rotating ship model
this.$GalleryFCB2 = null; //FrameCallBack for menu
this.$GalleryFCB3 = null; //FrameCallBack to fill up other role
this.$GalleryKey = null; //store last dataKey
this.$GalleryKeyi = []; //selected key indexes in the GalleryKeysForRole array
this.$GalleryKeysi = 0; //actual index in all Keys
this.$GalleryKeysForRole = []; //dataKeys for the selected role
this.$GalleryLastMenu = 0; //set marker to the lastly used menu line
this.$GalleryLastEnc = []; //lastly encountered dataKeys
this.$GalleryMore = true; //show more menu
this.$GalleryMove = 0; //move showed ship
this.$GalleryOri = null; //store last orientation
this.$GalleryOthers = [];
this.$GalleryPrevZ = 0; //store previous z position
this.$GalleryRole = 0; //selected role
this.$GalleryRotate = 0; //rotating showed ship around Y axis
this.$GalleryShift = 0; //store move multiplier calculated from ship size
this.$GalleryShiftX = 0; //store move position
this.$GalleryShiftY = 0; //store move position
this.$GalleryShiftZ = 0; //store move position
this.$GalleryShowAll = false; //show all ships and objects selected in search
this.$GalleryTimer = null; //help avoid timelimit
this.$GalleryTRole = 0; //actual role in timer
this.$GalleryTRI = 0; //Timer Role Iteration
this.$GalleryTrash = []; //store created ships to remove later
this.$GalleryZoom = 0; //zoom showed ship
//following arrays comes from Technical Reference Library OXP by spara
this.$GalleryClassifiedScanClasses = ["CLASS_MILITARY", "CLASS_POLICE", "CLASS_THARGOID"];
this.$GalleryClassifiedRoles = ["constrictor", "kephalan", "odonatean", "scorpax", "bigTrader", "monkpatrol", "griff_blackmonk_defenceship", "monkhit1", "monkhit2", "monkhold1", "monkhold2", "ev_green_gecko", "sin-pirate"];//classify constrictor, aliens oxp, bigTrader ships, black monks, green gecko oxp and capisastra oxp.
//world script events
this.startUp = function() {
this.$GalleryAllObjects = []; //store all ship and object keys
this.$GalleryAllNames = []; //all ship names for search
var ge = missionVariables.$GalleryEncounters; //load encountered ships from savegame
if( !ge ) this.$GalleryEncounters = []; else this.$GalleryEncounters = ge.split(",");//need at least 2 item exists
if(this.$GalleryLog)
log("Gallery", "Loaded Encounters ("+this.$GalleryEncounters.length+"): "+this.$GalleryEncounters);
this.$GalleryEncNames = []; //encountered ship names for search
this.$GalleryFCB = null; //FrameCallBack for rotating ship model
this.$GalleryLastMenu = 0; //set marker to the lastly used menu line
var ge = missionVariables.$GalleryLastEnc; //load order of encounters from savegame
if( !ge ) this.$GalleryLastEnc = [];
else if( (ge+"").indexOf(",") ) this.$GalleryLastEnc = (ge+"").split(","); //need +"" for bugfix of a single item
else this.$GalleryLastEnc = [ge];
if(this.$GalleryLog)
log("Gallery", "Loaded LastEnc ("+this.$GalleryLastEnc.length+"): "+this.$GalleryLastEnc);
this.$GalleryMore = true; //show more menu
this.$GalleryMove = 0; //move showed ship
this.$GalleryRole = 0; //starting role in Roles array
this.$GalleryRotate = 0; //rotating showed ship around Y axis
this.$GallerySet = false; //settings menu
this.$GalleryShiftX = 0; //store move position
this.$GalleryShiftY = 0; //store move position
this.$GalleryShiftZ = 0; //store move position
this.$GalleryShowAll = false; //show all ships and objects selected in search
this.$GalleryTrash = []; //store created ships to remove later
this.$GalleryZoom = 0; //zoom showed ship
if (0 < oolite.compareVersion("1.79")) { //slow and limited method, use before Oolite v1.79
//can cause long wait in startUp, "Universe is full" or crash to desktop before the spinning cobra if not enough memory
log("Gallery", "Fallback to a slow and inaccurate method without Oolite v1.79");
this.$GalleryKeysForRole[ 0 ] = [];
this.$GalleryKeysForRole[ 0 ] = this.$GalleryKeysForRole[ 0 ].concat(this.$GalleryEncounters);
var all = false;
if( this.$GalleryAll || worldScripts["exhibitions"]
&& worldScripts["exhibitions"].$ExhibitionsAllShipsInPrivateExhibition ) all = true;
for( var i = 1; i < this.$GalleryRoles.length && all || i == 1; i++ ) { //main roles
var maxk = this.$GalleryMaxIt; //how many iteration max., reduce if cause "Universe is full" or crash to desktop
var prevlen = 0;
var num = 16; //how many ships created at one time
if( i == 1 ) num = 64; //more if player role
for( var k = 1; k <= maxk; k++ ) {
if( this.$GalleryKeysForRole[ i ] ) prevlen = this.$GalleryKeysForRole[ i ].length;
var ships = system.addShips(this.$GalleryRoles[i], num, [0,0,0], 1000000);
// this.$GalleryTrash = this.$GalleryTrash.concat(ships);
if(ships) for( var j = 0; j < ships.length; j++ ) { //created ships
if( ships[j] ) {
var key = ships[j].dataKey;
if( !this.$GalleryKeysForRole[ i ] ) {
this.$GalleryKeysForRole[ i ] = [key];
} else if( this.$GalleryKeysForRole[ i ].indexOf(key) == -1 )
this.$GalleryKeysForRole[ i ].push(key);//add new key
ships[j].remove(true);//can not remove everything and reach Universe limit
//all ship remove must be called with true parameter to avoid call shipDied
//event which will drop the following error in the case of constrictor!
//TypeError: killer is null in oolite-constrictor.js, line 72
// if(this.$GalleryLog) log("Gallery", i + ". main role: " + this.$GalleryRoles[i]
// +" "+k+". try, "+(j+1)+". key: "+key
// +" GalleryKeysForRole["+i+"]:"+this.$GalleryKeysForRole[ i ]);
}
}
if(this.$GalleryLog) log("Gallery", i + ". main role: " + this.$GalleryRoles[i]
+" "+k+". try: "+this.$GalleryKeysForRole[ i ] );
if( //k == 1 && this.$GalleryKeysForRole[ i ].length < num / 3 ||//too few object in this role
prevlen == this.$GalleryKeysForRole[ i ].length) maxk = 0;//exit from cycle
}
if(this.$GalleryKeysForRole[ i ]) {
this.$GalleryKeysForRole[ i ].sort();
if(this.$GalleryLog) log("Gallery", i + ". role after "+(k-1)+" try: " + this.$GalleryRoles[i]
+ " ("+this.$GalleryKeysForRole[ i ].length+"): " + this.$GalleryKeysForRole[ i ] );
this.$GalleryKeysForRole[ 0 ] = this.$GalleryKeysForRole[ 0 ].concat(this.$GalleryKeysForRole[ i ]);
}
}
this.$GalleryKeysForRole[ 0 ].sort();
for( var i = 1; i < this.$GalleryKeysForRole[ 0 ].length; i++ ) { //remove duplicated keys
if(this.$GalleryKeysForRole[0][i] == this.$GalleryKeysForRole[0][i-1]) {
this.$GalleryKeysForRole[0].splice(i,1); //remove this item
i--;
}
}
if(this.$GalleryLog) log("Gallery", "All dataKeys ("+this.$GalleryKeysForRole[ 0 ].length
+"): " + this.$GalleryKeysForRole[ 0 ] );
// this.$GalleryTRole = 1;
// this.$GalleryTRI = 1;
// this.$GalleryTimer = new Timer(this, this.$Gallery_Timed, 1); //cycle in timer
if( !this.$GalleryEncounters || this.$GalleryEncounters.length == 0 )
this.$GalleryEncounters = this.$GalleryKeysForRole[ 1 ]; //store playable ships
else {
for( var i = 1; i < this.$GalleryKeysForRole[ 1 ].length; i++ ) {
var key = this.$GalleryKeysForRole[ 1 ][i];
if( this.$GalleryEncounters.indexOf( key ) == -1 )
this.$GalleryEncounters.push( key );
}
}
} else { //Oolite v1.79 or later
var sdk = Ship.keysForRole( "player" ); //playable and encountered ships only
if(this.$GalleryEncounters && this.$GalleryEncounters.length > 0) {
for( var i = 1; i < this.$GalleryEncounters.length; i++ ) {
var key = this.$GalleryEncounters[i];
if( sdk.indexOf( key ) == -1 ) sdk.push( key );
}
}
this.$GalleryEncounters = sdk;
if( this.$GalleryAll ) var sdk = Ship.keys(); //all dataKeys
this.$GalleryKeysForRole[ 0 ] = sdk.sort(); //all or playable+encountered dataKeys
this.$GalleryKeyi[ 0 ] = 0;
if(this.$GalleryLog) log("Gallery", "All dataKeys ("+this.$GalleryKeysForRole[ 0 ].length+"): "
+ this.$GalleryKeysForRole[ 0 ] );
for( var i = 1; i < this.$GalleryRoles.length; i++ ) { //main roles
var roleKeys = Ship.keysForRole( this.$GalleryRoles[i] ).sort();
if( !roleKeys || !roleKeys.length || roleKeys.length < 1 )
this.$GalleryRoles.splice(i,1); //remove empty role
else {
/* - validate check removed (too slow), check when try to show the item only
for( var j = 0; j < roleKeys.length; j++ ) {
var key = roleKeys[j];
var ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
if( ( !ships || !ships[0] ) && key.indexOf("-player") > -1 ) { //handle unsuccesful ship creation
key = key.slice(0, key.indexOf("-player")); //remove -player
ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
if( !ships || !ships[0] ) { //handle unsuccesful ship creation
roleKeys.splice(j,1); //remove item
j--;
if(this.$GalleryLog) log("Gallery", "Failed addShips ["+key+"], removed.");
} else ships[0].remove(true); //ok without -player
} else {
if( ships && ships[0] ) {
var ship = ships[0];
if( ship.roles ) for( var k = 0; k < ship.roles.length; k++ ) {
if( ship.roles[k] && ship.roles[k].indexOf("subent") > -1 ) {
//skip subentities in Griff_Shipset_Replace_v1.34.oxp
roleKeys.splice(j,1); //remove item
j--;
k = ship.roles.length;//exit from cycle
var msg = "Subentity ["+key+"] removed.";
if(this.$GalleryLog) log("Gallery", msg);
if(ship != player.ship) ship.remove(true);
}
}
ship.remove(true); //ok
} else if(this.$GalleryLog) log("Gallery", "Failed addShips ["+key+"], removed.");
}
}
*/
if( this.$GalleryAll ) this.$GalleryKeysForRole[ i ] = roleKeys;
else {
this.$GalleryKeysForRole[ i ] = [];
for( var k = 1; k < roleKeys.length; k++ ) {
var key = roleKeys[k];
if( this.$GalleryKeysForRole[ 0 ].indexOf( key ) != -1 )
this.$GalleryKeysForRole[ i ].push( key ); //get playable or encountered keys only
}
}
this.$GalleryKeyi[ i ] = 0;
if(this.$GalleryLog) log("Gallery", i + ". role: " + this.$GalleryRoles[i]
+ " ("+this.$GalleryKeysForRole[ i ].length+"): " + this.$GalleryKeysForRole[ i ] );
}
}
if(this.$GalleryLog) var roles = Ship.roles(); //all roles
if(this.$GalleryLog) for( var j = 0; j < roles.length; j++ ) {
// if( roles[j] && roles[j][0] != "[" ) { //many roles start with "["
var roleKeys = Ship.keysForRole( roles[j] );
if(this.$GalleryLog) log("Gallery", (j+1)+". "+roles[j]+" ("+roleKeys.length+"): "+roleKeys);
// }
}
// if( !isValidFrameCallback( this.$GalleryFCB3 ) )
// this.$GalleryFCB3 = addFrameCallback( this.$Gallery_OtherRole );//bug: give all keys, not others only
}
this.$GalleryAllObjects = this.$GalleryKeysForRole[ 0 ].sort(); //store all ships
// this.$GalleryEncounters.sort();//Gallery_EncSort() is better after GalleryEncNames is filled
//get encountered ship names
for( var j = 0; j < this.$GalleryEncounters.length; j++ ) {
var key = this.$GalleryEncounters[j];
if( Ship.shipDataForKey ) { //new fast method in 1.79 since 2014.05.19
var s = Ship.shipDataForKey(key);
if(this.$GalleryLog) log("Gallery", j+". "+key+" shipDataForKey "+s);//debug
if( s && s.name && s.name.length > 0 ) this.$Gallery_AddEncName(j, s.name); //check and store name
} else { //old slower way to get ship names, need validate check also
var ships = system.addShips("["+key+"]", 1, [0,0,0], 1000000);
if( ( !ships || !ships[0] ) && key.indexOf("-player") > -1 ) { //handle unsuccesful ship creation
key = key.slice(0, key.indexOf("-player")); //remove -player
ships = system.addShips("["+key+"]", 1, [0,0,0], 1000000);
if( !ships || !ships[0] ) { //handle unsuccesful ship creation
this.$GalleryEncounters.splice(j,1); //remove item
j--;
// if(this.$GalleryLog)
log("Gallery", "Failed addShips ["+key+"], removed.");
} else {
this.$Gallery_AddEncName(j, ships[0].name); //check and store name
ships[0].remove(true); //ok without -player
}
} else {
if( ships && ships[0] ) {
var ship = ships[0];
if( ship.roles ) for( var k = 0; k < ship.roles.length; k++ ) {
if( ship.roles[k] && ship.roles[k].indexOf("subent") > -1 ) {
//skip subentities in Griff_Shipset_Replace_v1.34.oxp
this.$GalleryEncounters.splice(j,1); //remove item
j--;
k = ship.roles.length;//exit from cycle
var msg = "Subentity ["+key+"] removed.";
// if(this.$GalleryLog)
log("Gallery", msg);
if(ship != player.ship) ship.remove(true);
}
}
this.$Gallery_AddEncName(j, ship.name); //check and store name
ship.remove(true); //ok
} else //if(this.$GalleryLog)
log("Gallery", "Failed addShips ["+key+"], removed.");
}
}
}
if(this.$GalleryLog) log("Gallery", " Gallery ("+this.$GalleryEncounters.length+"): "+this.$GalleryEncounters);//debug
this.$Gallery_EncSort();
this.$GalleryKeysForRole[ 0 ] = this.$GalleryEncounters;//always start in enc. array
if(this.$GalleryLog) log("Gallery", " Gallery ("+this.$GalleryEncounters.length+"): "+this.$GalleryEncounters);//debug
if( player.ship && player.ship.docked ) this.shipDockedWithStation( player.ship.dockedStation ); //set interface
else if( system ) this.shipDockedWithStation( system.mainStation );//fallback
}
this.commsMessageReceived = function(message, sender) {
this.$Gallery_Encounter( sender );
}
this.distressMessageReceived = function(aggressor, sender) {
this.$Gallery_Encounter( aggressor );
this.$Gallery_Encounter( sender );
}
this.playerTargetedMissile = function(missile) {
this.$Gallery_Encounter( missile );
}
this.playerWillSaveGame = function(message) {
missionVariables.$GalleryEncounters = this.$GalleryEncounters; //store encountered ships into savegame
missionVariables.$GalleryLastEnc = this.$GalleryLastEnc; //store order of encounters into savegame
}
this.shipAttackedOther = function(other) {
this.$Gallery_Encounter( other );
}
this.shipAttackedWithMissile = function(missile, whom) {
this.$Gallery_Encounter( missile );
this.$Gallery_Encounter( whom );
}
this.shipBeingAttacked = function(whom) {
this.$Gallery_Encounter( whom );
}
this.shipBeingAttackedUnsuccessfully = function(whom) {
this.$Gallery_Encounter( whom );
}
this.shipCloseContact = function(otherShip) {
this.$Gallery_Encounter( otherShip );
}
this.shipCollided = function(otherShip)
{
this.$Gallery_Encounter( otherShip );
}
this.shipDockedWithStation = function(station)
{
if( isValidFrameCallback( this.$GalleryFCB ) )
removeFrameCallback( this.$GalleryFCB );
var len = this.$GalleryLastEnc.length;
var s = "";
if( len > 1 ) s = "s";
station.setInterface("Gallery",{
title: "Gallery of encounters ("+this.$GalleryLastEnc.length+" item"+s+" stored)",
category: "Ship Systems",
summary: "Shows a gallery of ships and other space objects that you have encountered, with public technical data where available.",
callback: this.$Gallery_Interface.bind(this)
});
if( this.$GalleryAll ) {
station.setInterface("GalleryAll",{
title: "Gallery of all objects ("+this.$GalleryAllObjects.length+" objects)",
category: "Ship Systems",
summary: "Shows a gallery of all ships and other space objects, with public technical data where available.",
callback: this.$Gallery_InterfaceAll.bind(this)
});
}
}
this.shipEnteredStationAegis = function(station) {
this.$Gallery_Encounter( station );
}
this.shipFiredMissile = function(missile, target) {
this.$Gallery_Encounter( missile );
this.$Gallery_Encounter( target );
}
this.shipKilledOther = function(whom, damageType) {
this.$Gallery_Encounter( whom );
}
this.shipScoopedOther = function(whom) {
this.$Gallery_Encounter( whom );
}
this.shipTakingDamage = function(amount, whom, type) {
this.$Gallery_Encounter( whom );
}
this.shipTargetAcquired = function(target) {
this.$Gallery_Encounter( target );
}
this.shipWillLaunchFromStation = function() {
player.ship.hudHidden = false;
if( isValidFrameCallback( worldScripts["gallery"].$GalleryFCB ) )
removeFrameCallback( worldScripts["gallery"].$GalleryFCB );
}
//Gallery methods
this.$Gallery_AddEncName = function( j, n ) { //save name for search, check for empty and duplicated name
if( n && n.length > 0 ) {
var x = this.$GalleryEncNames.indexOf(n);
if( x > -1 ) { //duplicated name, add number in parenthesis to the name
for( var i = 1; i < 10000; i++ ) {
var n2 = n + " (" + i + ")";
if( this.$GalleryEncNames.indexOf(n2) == -1 ) i = 10000;//exit
}
this.$GalleryEncNames[j] = n2;
} else this.$GalleryEncNames[j] = n;//save name
} else this.$GalleryEncNames[j] = this.$GalleryEncounters[j];//datakey if name is empty
if(this.$GalleryLog) log("Gallery", j+". "+this.$GalleryEncounters[j]+": "+this.$GalleryEncNames[j]);
}
this.$Gallery_Encounter = function( ship ) { //save the keys of encountered ships
if( !ship || !ship.isValid || !player.ship || !player.ship.isValid ) return;
var key = ship.dataKey;
if( key && key != "telescopemarker" && key.indexOf("customshields") == -1
&& ( !this.$GalleryEncounters || this.$GalleryEncounters.indexOf( key ) == -1 ) ) {
if(this.$GalleryLog) log("Gallery", key+" encountered.");
if( !this.$GalleryEncounters ) this.$GalleryEncounters = [ key ];
else this.$GalleryEncounters.push( key ); //do not sort: EncNames array will be in wrong order!
if( !this.$GalleryLastEnc ) this.$GalleryLastEnc = [ key ];
else this.$GalleryLastEnc.push( key ); //do not sort at all: this array hold the order of encounters
var j = this.$GalleryEncounters.length - 1; //last item
this.$Gallery_AddEncName( j, ship.name ); //do not use displayName to avoid randomshipnames OXP
// this.$GalleryEncNames.push( ship.name );
player.consoleMessage(this.$GalleryEncNames[j]+" is now added to your ship's Gallery.",10); //as the "+(j+1)+". space object
this.$Gallery_EncSort();//sort after consoleMessage only!
// if( !this.$GalleryShowAll ) this.$GalleryKeysForRole[0] = this.$GalleryEncounters;//needed but EncSort do it
if( this.$GalleryAll ) for( var i = 2; i < this.$GalleryRoles.length; i++ ) { //main roles
if( ship.roles && ship.roles.indexOf( this.$GalleryRoles[i] ) != -1 ) {
if( !this.$GalleryKeysForRole[ i ] ) this.$GalleryKeysForRole[ i ] = [key];
else this.$GalleryKeysForRole[ i ].push( key );
this.$GalleryKeysForRole[ i ].sort();
}
}
}
}
this.$Gallery_EncSort = function() {
var g = worldScripts["gallery"];
var e = g.$GalleryEncounters;
var n = g.$GalleryEncNames;
var k = []; //dataKeys for names
for( var i = 0; i < n.length; i++ ) {
if( n[i] && n[i].length > 0 ) k[ n[i] ] = e[i];
else {
e[i] = null;
n[i] = null;
}
}
g.$GalleryEncNames.sort();
n = g.$GalleryEncNames;
var e2 = [];
for( var i = 0; i < n.length; i++ ) e2[i] = k[ n[i] ];
g.$GalleryEncounters = e2;
if( !g.$GalleryShowAll ) g.$GalleryKeysForRole[ 0 ] = g.$GalleryEncounters;
}
this.$Gallery_FCB = function( delta ) { //FrameCallBack updating ship in sell salvage screen
var m = mission.displayModel;
if( m && m.isValid ) {
var g = worldScripts["gallery"];
switch( g.$GalleryRotate ) {
case 0:
m.orientation = m.orientation.rotateY( delta/1.5 );
break;
case 2:
m.orientation = m.orientation.rotateY( -delta/1.5 );
break;
case 4:
m.orientation = m.orientation.rotateX( delta/1.5 );
break;
case 6:
m.orientation = m.orientation.rotateX( -delta/1.5 );
break;
}
g.$GalleryOri = mission.displayModel.orientation;
//Move and zoom, camera is at [0,0,0] facing [1,0,0,0]
switch( g.$GalleryMove ) {
case 1:
g.$GalleryShiftX += g.$GallerySpeed * g.$GalleryShift * delta;
break;
case 3:
g.$GalleryShiftX -= g.$GallerySpeed * g.$GalleryShift * delta;
break;
case 5:
g.$GalleryShiftY += g.$GallerySpeed * g.$GalleryShift * delta;
break;
case 7:
g.$GalleryShiftY -= g.$GallerySpeed * g.$GalleryShift * delta;
break;
}
if( g.$GalleryZoom == 1 ) g.$GalleryShiftZ -= 3 * g.$GallerySpeed * g.$GalleryShift * delta;
else if( g.$GalleryZoom == 3 ) g.$GalleryShiftZ += 3 * g.$GallerySpeed * g.$GalleryShift * delta;
var w = oolite.gameSettings.gameWindow;
var wide = Math.max( 0.01, ( w.width / w.height ) / g.$GalleryDefaultZoom ); //correction if not in widescreen
mission.displayModel.position = Vector3D(g.$GalleryShiftX, g.$GalleryShiftY, g.$GalleryShiftZ * wide);
}
}
this.$Gallery_FCB2 = function( delta ) { //FrameCallBack for menu
var g = worldScripts["gallery"];
if( isValidFrameCallback( g.$GalleryFCB2 ) ) removeFrameCallback( g.$GalleryFCB2 );
g.$Gallery_Interface2( g.$GalleryShowAll );
}
this.Gallery_GetShipData = function(ship, all) {
var equip="";
var s="";
s=ship.forwardWeapon;
if( s!=null && s.equipmentKey != "EQ_WEAPON_NONE" ) equip+="Forward "+s.name;
var shipno = 0;
var r = worldScripts["rocketmenu"];
if( r ) {
shipno = r.$RocketMenu_Name.indexOf(ship.dataKey); //RocketShip with extra weapons
}
if( shipno > 0 ) {
var pul = r.$RocketMenu_Pulse[shipno];
if( pul > 0 ) {
if( equip.length > 0 ) equip+="\n";
if( pul > 1) equip+=pul+" ";
equip+="Auto Pulse Laser";
if( pul > 1) equip+="s";
}
var ham = r.$RocketMenu_Hammer[shipno];
if( ham > 0 ) {
if( equip.length > 0 ) equip+="\n";
if( ham > 1) equip+=ham+" ";
equip+="Hammer Laser";
if( ham > 1) equip+="s";
}
var Sniper = r.$RocketMenu_Sniper[shipno];
if( Sniper > 0 ) {
if( equip.length > 0 ) equip+="\n";
if( Sniper > 1) equip+=Sniper+" ";
equip+="Sniper Laser";
if( Sniper > 1) equip+="s";
}
var pha = r.$RocketMenu_Sapper[shipno];
if( pha > 0 ) {
if( equip.length > 0 ) equip+="\n";
if( pha > 1) equip+=pha+" ";
equip+="Sapper";
if( pha > 1) equip+="s";
}
}
s=ship.aftWeapon;
if( s!=null && s.equipmentKey != "EQ_WEAPON_NONE" ) {
if( equip.length > 0 ) equip+="\n"; //Anaconda has aft weapon only
equip+="Aft "+s.name;
}
s=ship.portWeapon;
if( s!=null && s.equipmentKey != "EQ_WEAPON_NONE" ) equip+="\nPort "+s.name;
s=ship.starboardWeapon;
if( s!=null && s.equipmentKey != "EQ_WEAPON_NONE" ) equip+="\nStarboard "+s.name;
if( shipno > 0 ) {
var bt = r.$RocketMenu_Turrets[shipno];
if( bt > 0) { //RocketShip with turrets
if( equip.length > 0 && !ship.portWeapon && !ship.starboardWeapon) equip+="\n";
else equip+=", ";
if(bt < 1) equip += (bt*10)+" Mini";
else if(bt > 99) equip += Math.floor(bt/100)+" Strong";
else equip += bt+" Ball";
equip += " Turret";
if( bt > 1) equip+="s";
}
if(ship.dataKey.indexOf("rocketcruiser") > -1) equip+=", 2 Main Turrets"; //rocketcruiser-player
}
if(equip.length > 0) equip+="\n";
else if( ship.isPiloted || all ) equip+="No Laser\n";
var eqs = "";
/* var n = ""; //equipment list removed to make space
var eq = ship.equipment;
var i=-1;
while(eq[++i]) {
n = eq[i].name;
if( n.length > 0 ) eqs += n + ", ";
else { //skip noname eqs awarded by NumericHUD to avoid timeLimit error
for( var j = i + 10; j < eq.length; j+=10 ) {
if( eq[j].name.length != 0 ) {
i = j - 10; //end of skip
j = eq.length;
}
}
while( i < eq.length && eq[i].name.length == 0 ) i++;
i--;
}
}
eqs = eqs.substr( 0, eqs.length - 2 ); //cut last comma
if( eqs.length > 0 ) equip+=eqs+"\n\n";
else equip+="\n";//empty line before desc if no eqs
*/ var desc = "";
if( ship.scriptInfo && ship.scriptInfo.buydesc )//show ship description if any
desc="\""+ship.scriptInfo.buydesc+"\"\n";
var sh = 0;
if( ship == player.ship ) sh += ship.maxForwardShield;
else {
var w = worldScripts["NPC-shields"];
if( w && ship.script ) {
if( !ship.script.maxShieldStrength ) w.shipSpawned(ship); //add npc shield
sh += ship.script.maxShieldStrength;
}
var w = worldScripts["customshields"];
if( w && ship.script ) {
if( !ship.script.customshieldsmaxforwardshieldlevel ) w.shipSpawned(ship); //add customshield
sh += ship.script.customshieldsmaxforwardshieldlevel;
}
}
if( ship.dataKey.indexOf("escape-capsule") > -1 ) sh = 0; //no shield on escape pod
else if( worldScripts["shieldequalizercapacitors"] ) {
if( ship.equipmentStatus("EQ_BIGSHCAP") == "EQUIPMENT_OK"
&& ship.equipmentStatus("EQ_FORWARD_SHIELD_CAPACITOR") == "EQUIPMENT_OK" ) sh += 256;
else if( ship.equipmentStatus("EQ_FORWARD_SHIELD_CAPACITOR") == "EQUIPMENT_OK" ) sh += 64;
}
var psd = "";//ship.displayName+
var hd = "";
if(!ship.hasHyperspaceMotor ) hd = " No Hyperdrive";
var speed = ship.maxSpeed;
if( ship.script && ship.script.name === "rocketships" )
speed = Math.round(ship.maxSpeed/3*2)+"+"+Math.round(ship.maxSpeed/3);
if( speed > 0 ) psd += "Speed: "+speed+" mLS Thrust: "+ship.maxThrust+" ";
if( all || speed > 0 && ship.isPiloted ) {
psd += "\nPitch: "+Math.round(ship.maxPitch*100)/100+
" Roll: "+Math.round(ship.maxRoll*100)/100+
" Yaw: "+Math.round(ship.maxYaw*100)/100+hd+
// " Version: "+this.$shipVersion(ship)+
// " Service "+ship.serviceLevel+
"\nCargo: "+ship.cargoSpaceCapacity;
if( ship.extraCargo > 0 ) psd += "+"+parseInt(ship.extraCargo); //need Oolite v1.79
else if( ship.scriptInfo && ship.scriptInfo.cargoext && parseInt(ship.scriptInfo.cargoext) > 0 )
psd += "+"+parseInt(ship.scriptInfo.cargoext);
psd += "t ";
}
var sp = "";
var sph = Math.round(ship.collisionRadius*ship.collisionRadius*Math.PI);
if( sph < 1000000 ) sp = sph;
else sp = Math.round(sph/100000)/10+"k";//base sphere too large to fit in the line so show in km^2
var en = "";
var r = "";
if(all) en = "Energy: "+ship.maxEnergy;
else {
if( ship.isPiloted ) {
var eb = Math.max(1, Math.floor(ship.maxEnergy/64));
en = "EBank";
if( eb > 1 ) en += "s";
en += ": "+eb;
}
}
if( ship.isPiloted || all ) {
var er = 0;
if( ship.energyRechargeRate > 0 ) er = parseInt(ship.energyRechargeRate); //need Oolite v1.79
else if( ship.scriptInfo && ship.scriptInfo.recharge && parseInt(ship.scriptInfo.recharge) > 0 )
er = parseInt(ship.scriptInfo.recharge);
if( er > 0 ) {
var ers = "";
if( er < 2.5 ) ers = "Poor";
else if( er < 3.5 ) ers = "Medium";
else if( er < 4.5 ) ers = "Good";
else if( er < 10 ) ers = "Excellent";
else ers = "Extreme";
if( all ) ers += " ("+er+")";
r = " Recharge: "+ers;
}
if( sh > 0 ) r += "\nShields: "+Math.max(2, Math.floor(sh/64));
if( ship.missileCapacity > 0 ) {
if( sh > 0 ) r += " "; else r += "\n";
r += "Missile";
if( ship.missileCapacity > 1 ) r += "s";
r += ": "+ship.missileCapacity;
}
}
psd += "Mass: "+Math.max(Math.round(ship.mass)/1000, 1)+ //min.1t
"t\nSize: "+Math.round(ship.boundingBox.x)+"*"+
Math.round(ship.boundingBox.y)+"*"+Math.round(ship.boundingBox.z)+
"m Radius: "+Math.round(ship.collisionRadius)+"m"+//" Sphere: "+sp+"m^2"+
"\n"+en+r;
// if( ship.scriptInfo && ship.scriptInfo.hardarmour && parseInt(ship.scriptInfo.hardarmour) > 0 )
// psd += "\nHard Armour deflect "+parseInt(ship.scriptInfo.hardarmour)+" points from any damage";
//removed, redundant with Hard Armour Equipment and give more free space
psd += "\n"+equip;
if( worldScripts["gallery"].$GalleryMore ) psd = desc + psd;
if( ship.price > 0 ) psd += "\nPrice: "+formatCredits(ship.price, false, true);
return(psd);
}
this.$Gallery_Interface = function() { //encounters only
player.ship.hudHidden = true;//to shift down the menu
var g = worldScripts["gallery"];
g.$GalleryShowAll = false;
g.$GalleryKeysForRole[ 0 ] = g.$GalleryEncounters; //fill up default key array
var e = worldScripts["exhibitions"];
if( e && isValidFrameCallback( e.$ExhibitionsMenuFCB ) )
removeFrameCallback( e.$ExhibitionsMenuFCB ); //need for bugfix
this.$Gallery_LastEncounters( false, true ); //not all, init
// this.$Gallery_Search( false, true ); //not all, init
// this.$Gallery_Interface2( false );
}
this.$Gallery_InterfaceAll = function() { //all ships
player.ship.hudHidden = true;//to shift down the menu
var g = worldScripts["gallery"];
g.$GalleryShowAll = true;
g.$GalleryKeysForRole[ 0 ] = g.$GalleryAllObjects; //fill up default key array
this.$Gallery_Search( true, true ); //all, init
// this.$Gallery_Interface2( true );
}
this.$Gallery_Interface2 = function( all ) {
if( player.ship && player.ship.docked && system ) {
player.ship.hudHidden = true;//to shift down the menu
var g = worldScripts["gallery"];
if( !g.$GalleryKeyi[g.$GalleryRole] ) g.$GalleryKeyi[g.$GalleryRole] = 0; //prevent a bug
var key = g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]];
if(!key) {
g.$GalleryKeyi[g.$GalleryRole] = 0;
key = g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]];
if(!key) {
g.$GalleryRole = 0;
key = g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]];
if(!key) {
g.$GalleryKeyi[g.$GalleryRole] = 0;
key = g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]];
if(!key) return; //no key found
}
}
}
if( key == player.ship.dataKey ) var ship = player.ship;
else {
if( !all &&
( g.$GalleryPlayerShips && g.$GalleryPlayerShips.indexOf(key) == -1 ) &&
( g.$GalleryEncounters && g.$GalleryEncounters.indexOf(key) == -1 ) ) {
if(this.$GalleryLog) log("Gallery", key+" not encountered so removed. ");
this.$Gallery_RemoveCurrentShip(g, all); //will retry also
return;
}
var ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
if( !ships ) { //need to handle unsuccesful ship creation
var p = key.indexOf("-player");
if( p > -1 ) var key = key.slice(0, p); //remove -player part
ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
if( !ships ) { //need to handle unsuccesful ship creation
var msg = "Failed addShips with role ["+key+"], removed.";
if(this.$GalleryLog) log("Gallery", msg);
this.$Gallery_RemoveCurrentShip(g, all); //will retry also
return;
}
}
var ship = ships[0];
if( ship.roles ) for( var i = 0; i < ship.roles.length; i++ ) {
if( ship.roles[i] && ship.roles[i].indexOf("subent") > -1 ) {
i = ship.roles.length; //found, will exit from cycle
//skip subentities in Griff_Shipset_Replace_v1.34.oxp
var msg = "Subentity ["+key+"] removed.";
if(this.$GalleryLog) log("Gallery", msg);
if(ship != player.ship) ship.remove(true);
this.$Gallery_RemoveCurrentShip(g, all); //will retry also
return;
}
}
}
if(this.$GalleryLog) log("Gallery", "dataKey: "+key+ " Keyi:"+g.$GalleryKeyi[g.$GalleryRole]+
" Gallery ("+g.$GalleryKeysForRole.length+"): "+g.$GalleryKeysForRole );
var c = [key,
"Previous",
"Role: "+g.$GalleryRoles[g.$GalleryRole]+
" ("+g.$GalleryKeysForRole[g.$GalleryRole].length+")",
"Previous role",
"Search",
["Rotate Y+","Rotate stop","Rotate Y-","Rotate stop","Rotate X+","Rotate stop","Rotate X-","Rotate stop"],
["Move stop","Move X+","Move stop","Move X-","Move stop","Move Y+","Move stop","Move Y-"],
["Zoom stop","Zoom +","Zoom stop","Zoom -"],
"Exit",
"Hide Menu",
"Menu"];
if( !all && !g.$GalleryValidateTarget(ship) ) {
var msg = "No public details.";
if(this.$GalleryLog) log("Gallery", key+" showed without data.");
} else {
var msg = g.Gallery_GetShipData(ship, all);
if(this.$GalleryLog) log("Gallery", msg);
}
if(ship != player.ship) ship.remove(true); //will really disappear after the end of the function
var title = ship.displayName;
var x = g.$GalleryEncounters.indexOf(key);
if( x > -1 ) title = g.$GalleryEncNames[x]; //show (1), (2), etc. after duplicated names
if( all ) name = key;
else name = title;
if( !name || name.length < 1) name = "..."; //for sure
var ch = { "_0" : name,
"_10" : c[10]
};
if( g.$GalleryMore ) {
if( all ) ch = { "_0" : name,
"_1" : c[1],
"_2" : c[2],
"_3" : c[3],
"_4" : c[4],
"_5" : c[5][g.$GalleryRotate],
"_6" : c[6][g.$GalleryMove],
"_7" : c[7][g.$GalleryZoom],
"_8" : c[8],
"_9" : c[9]
};
else ch = { "_0" : name,
"_1" : c[1],
// "_2" : c[2], //without role menus
// "_3" : c[3],
"_4" : c[4],
"_5" : c[5][g.$GalleryRotate],
"_6" : c[6][g.$GalleryMove],
"_7" : c[7][g.$GalleryZoom],
"_8" : c[8],
"_9" : c[9]
};
}
mission.runScreen({
title: title,
message: msg,
model: "["+key+"]",
modelPersonality: 0,
spinModel:false,
background: "gallery_bg.png",
initialChoicesKey: "_"+g.$GalleryLastMenu,
choices: ch
},function(choice) {
switch(choice) {
case "_0":
if( ++g.$GalleryKeyi[g.$GalleryRole] >= g.$GalleryKeysForRole[g.$GalleryRole].length
|| !g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]] )
g.$GalleryKeyi[g.$GalleryRole] = 0;
g.$GalleryLastMenu = 0;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_1":
if( --g.$GalleryKeyi[g.$GalleryRole] < 0 )
g.$GalleryKeyi[g.$GalleryRole] =
g.$GalleryKeysForRole[g.$GalleryRole].length - 1;
g.$GalleryLastMenu = 1;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_2":
if( ++g.$GalleryRole >= g.$GalleryRoles.length )
// || !g.$GalleryKeysForRole[g.$GalleryRole][g.$GalleryKeyi[g.$GalleryRole]] )
g.$GalleryRole = 0;
while( g.$GalleryRole > 0 &&
!g.$GalleryKeysForRole[g.$GalleryRole]
|| g.$GalleryKeysForRole[g.$GalleryRole].length < 1 ) { //skip empty roles
if( ++g.$GalleryRole >= g.$GalleryRoles.length ) g.$GalleryRole = 0;
}
g.$GalleryLastMenu = 2;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_3":
if( --g.$GalleryRole < 0 ) g.$GalleryRole = g.$GalleryRoles.length - 1;
while( g.$GalleryRole > 0 &&
!g.$GalleryKeysForRole[g.$GalleryRole]
|| g.$GalleryKeysForRole[g.$GalleryRole].length < 1 ) { //skip empty roles
g.$GalleryRole--;
}
g.$GalleryLastMenu = 3;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_4":
g.$GalleryLastMenu = 0;
g.$Gallery_Search( all, false ); //use textEntry from Oolite v1.79
break;
case "_5":
if( ++g.$GalleryRotate >= c[5].length ) g.$GalleryRotate = 0;
g.$GalleryLastMenu = 5;
mission.displayModel.orientation = g.$GalleryOri;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_6":
if( ++g.$GalleryMove >= c[6].length ) g.$GalleryMove = 0;
g.$GalleryLastMenu = 6;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_7":
if( ++g.$GalleryZoom >= c[7].length ) g.$GalleryZoom = 0;
g.$GalleryLastMenu = 7;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_8": //exit
break;
case "_9": //Hide Menu
g.$GalleryMore = false;
g.$GalleryLastMenu = 10;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
case "_10": //Menu
g.$GalleryMore = true;
g.$GalleryLastMenu = 9;
if( !isValidFrameCallback( g.$GalleryFCB2 ) )
g.$GalleryFCB2 = addFrameCallback( g.$Gallery_FCB2 );
break;
}
});
if( g.$GalleryLog ) log("Gallery", key +" "+ g.$GalleryKey);
if( key != g.$GalleryKey ) { //save position if new model
g.$GalleryKey = key;
g.$GalleryShiftX = mission.displayModel.position.x;
g.$GalleryShiftY = mission.displayModel.position.y;
if( g.$GalleryPrevZ < 1 || g.$GalleryShiftZ < 1 )
g.$GalleryShiftZ = mission.displayModel.position.z;
else {
g.$GalleryShiftZ = mission.displayModel.position.z * g.$GalleryShiftZ / g.$GalleryPrevZ; ///
g.$GalleryPrevZ = mission.displayModel.position.z;
}
// g.$GalleryOri = mission.displayModel.orientation;
} else mission.displayModel.orientation = g.$GalleryOri;
g.$GalleryShift = Math.max( ship.collisionRadius * 0.7 , //fix for adder and moray
0.5 * mission.displayModel.position.z
- Math.max( ship.boundingBox.x, ship.boundingBox.y ) ) / 5;
if( g.$GalleryLog ) log("Gallery", mission.displayModel.position+ " shift:"+ g.$GalleryShift);
// camera is at [0,0,0] facing [1,0,0,0]
mission.displayModel.orientation = //fix flashing shaders in 1.81
mission.displayModel.orientation.rotateX( 0.001 );
if( !isValidFrameCallback( g.$GalleryFCB ) )
g.$GalleryFCB = addFrameCallback( g.$Gallery_FCB );
g.$Gallery_FCB(0);//needed to set position immediately
}
}
this.$Gallery_LastEncounters = function( all, init ) {
var g = worldScripts["gallery"];
// g.$GalleryLastEnc = g.$GalleryEncounters;//debug
var bgkey = player.ship.dataKey;
var c = [];
var title = g.$Gallery_SearchHeadTitle( all );
if( !g.$GalleryLastEnc || g.$GalleryLastEnc.length == 0 ) { //skip last encounters menu if none
var msg = "You have not found any object yet, but you can search in purchasable ships.";
// g.$Gallery_Search( false, true ); //not all, init
} else {
var len = g.$GalleryLastEnc.length;
var s = "";
if( len > 1 ) s = "s";
var msg = "You have so far encountered a total of "+len+" space object"+s
+". Below are the latest items added to your gallery. Select the gallery item that you wish to view.";
// var msg = g.$Gallery_SearchHeadMsg( all )+" Last encounters:";
var i = len - 1;
bgkey = g.$GalleryLastEnc[ i ];
for( var j = 0; i >= 0 && j < 23; j++ ) { //in reverse order
var ei = g.$GalleryEncounters.indexOf( g.$GalleryLastEnc[ i ] );
if( ei > -1 ) {
c[ j ] = g.$GalleryEncNames[ ei ];
} else j--;
i--;
}
}
var ch = {
"_10" : c[0],
"_11" : c[1],
"_12" : c[2],
"_13" : c[3],
"_14" : c[4],
"_15" : c[5],
"_16" : c[6],
"_17" : c[7],
"_18" : c[8],
"_19" : c[9],
"_20" : c[10],
"_21" : c[11],
"_22" : c[12],
"_23" : c[13],
"_24" : c[14],
"_25" : c[15],
"_26" : c[16],
"_27" : c[17],
"_28" : c[18],
"_29" : c[19],
"_30" : c[20],
"_31" : c[21],
"_32" : c[22],
"_S" : "Search" //max. 23 llines fit into the screen after two line msg and one empty line
};
if( isValidFrameCallback( worldScripts["gallery"].$GalleryFCB ) )
removeFrameCallback( worldScripts["gallery"].$GalleryFCB );
mission.runScreen({
title: title,
message: msg,
background: "gallery_bg.png",
model: "["+bgkey+"]",
modelPersonality: 0,
spinModel:false,
// initialChoicesKey: "_"+g.$GalleryLastMenu,
choices: ch
},function( choice ) {
g.$GalleryRole = 0;
if( choice == "_S" ) {
g.$Gallery_Search( all, false ); //use textEntry from Oolite v1.79
return;
}
var text = "";
if( choice ) text = c[ choice.substr(1) - 10 ]; //cut starting "_"
g.$Gallery_SearchKey(text.toLowerCase(), all);
});
var m = mission.displayModel;
if( m ) {
var w = oolite.gameSettings.gameWindow; //correction if not in widescreen
var wide = Math.max( 0.01, ( w.width / w.height ) / g.$GalleryDefaultZoom );
m.position = Vector3D(m.position.x, m.position.y, m.position.z * wide );
}
// }
}
this.$Gallery_OtherRole = function() { //separated from startUp for faster boot
var g = worldScripts["gallery"];
var k = g.$GalleryKeysForRole[ 0 ]; //do one check/frame = 60 check/sec, need about 10 sec to finish
var i = g.$GalleryKeysi++;
var o = g.$GalleryOthers;
// var k = Ship.keys(); //all dataKeys
// var o = [];
// for( var i = 0; i < k.length; i++ ) { //find keys not in main rules
var ki = k[i];
var ok = true;
for( var j = 0; j < g.$GalleryKeysForRole.length; j++ ) {
if( g.$GalleryKeysForRole.indexOf( ki ) > -1 ) { //bug: can not filter anything
ok = false;
j = g.$GalleryKeysForRole.length; //exit from cycle
}
}
if( ok ) {//found new key
// var key = ki;
// var ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
// if( ( !ships || !ships[0] ) && key.indexOf("-player") > -1 ) { //handle unsuccesful ship creation
// key = key.slice(0, key.indexOf("-player")); //remove -player
// ships = system.addShips("["+key+"]", 1, [0,0,0], 25000);
// if( !ships || !ships[0] ) { //handle unsuccesful ship creation
// if(g.$GalleryLog) log("Gallery", "Failed addShips ["+key+"], skipped.");
// } else { //ok without -player
// ships[0].remove(true);
// o.push( ki );//add to others
// }
// } else {
// if( ships && ships[0] ) { //ok
// ships[0].remove(true);
o.push( ki );//add to others
// } else if(g.$GalleryLog) log("Gallery", "Failed addShips ["+key+"], skipped.");
// }
}
// }
i++;
if( i >= k.length ) {
o.sort();
if( g.$GalleryLog) log("Gallery", "All other dataKeys: " + o );
if( o.length > 0 ) {
g.$GalleryKeysForRole.push( o );
g.$GalleryRoles.push("all others");
}
if( isValidFrameCallback( g.$GalleryFCB3 ) )
removeFrameCallback( g.$GalleryFCB3 );
}
g.$GalleryOthers = o;
}
this.$Gallery_RemoveCurrentShip = function(g, all) {
g.$GalleryKeysForRole[g.$GalleryRole].splice(g.$GalleryKeyi[g.$GalleryRole],1); //remove from the current list
if(!g.$GalleryKeysForRole[g.$GalleryRole]
|| g.$GalleryKeysForRole[g.$GalleryRole].length < 1 ) //none left in this rule
g.$GalleryRole = 0;
else if(g.$GalleryKeyi[g.$GalleryRole] > g.$GalleryKeysForRole[g.$GalleryRole].length)
g.$GalleryKeyi[g.$GalleryRole] ==
g.$GalleryKeysForRole[g.$GalleryRole].length - 1; //previous one
g.$Gallery_Interface2( all ); //try again with another ship
}
this.$Gallery_Search = function( all, init ) {
var g = worldScripts["gallery"];
var title = this.$Gallery_SearchHeadTitle( all );
var msg = this.$Gallery_SearchHeadMsg( all );
if (init || 0 < oolite.compareVersion("1.79")) { //no textEntry before Oolite v1.79
msg += " Select the gallery item that you wish to view.";
var k = [];
if( g.$GalleryShowAll ) k = g.$GalleryKeysForRole[ 0 ];
else k = g.$GalleryEncNames;
var k1 = [];
var l = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o",
"p","q","r","s","t","u","v","w","x","y","z"];
var z = [];
for( var j = 0; j < k.length; j++ )
if(k[j]) k1[j] = k[j].charAt(0).toLowerCase();
else if(g.$GalleryKeysForRole[ 0 ][j]) k1[j] = g.$GalleryKeysForRole[ 0 ][j].charAt(0).toLowerCase();
else k1[j] = "?";
for( var i = 0; i < l.length; i++ ) {
var x = k1.indexOf( l[i] );
if( x != -1 ) z[ l[i] ] = k[x];
}
var last = "";
if( g.$GalleryLastEnc && g.$GalleryLastEnc.length > 0 ) last = "Last encounters";
var ch = { "_" : last,
"A" : z.a,
"B" : z.b,
"C" : z.c,
"D" : z.d,
"E" : z.e,
"F" : z.f,
"G" : z.g,
"H" : z.h,
"I" : z.i,
"J" : z.j,
"K" : z.k,
"L" : z.l,
"M" : z.m,
"N" : z.n,
"O" : z.o,
"P" : z.p,
// "Q" : z.q,//removed to give a line to the exhibitions menu
"R" : z.r,
"S" : z.s,
"T" : z.t,
"U" : z.u,
"V" : z.v,
"W" : z.w,
"X" : z.x,
"Y" : z.y,
"Z" : z.z
};
// if( g.$GalleryAll ) {
// if( all ) {
// ch += {"ZZEnc" : "Encounters"};
// msg += "\nSelect \"Encounters\" to see Gallery of encounters.";
// } else {
// ch += {"ZZAll" : "All"};
// msg += "\nSelect \"All\" to see Gallery of all objects.";
// }
// }
if( isValidFrameCallback( g.$GalleryFCB ) ) removeFrameCallback( g.$GalleryFCB );
mission.runScreen({
title: title,
message: msg,
model: "["+player.ship.dataKey+"]",
modelPersonality: 0,
spinModel:false,
background: "gallery_bg.png",
// initialChoicesKey: "_"+g.$GalleryLastMenu,
choices: ch
},function(text) {
if( text == "_" ) { //Last encounters menu
g.$Gallery_LastEncounters( all, init );
return;
}
// if( text == "__" ) { //exhibitions menu
// var e = worldScripts["exhibitions"];
// e.$ExhibitionsLastMenu = 0;
// if( g.$GalleryLog) log("Gallery", "exhibitions menu");
// if( !isValidFrameCallback( e.$ExhibitionsMenuFCB ) )
// e.$ExhibitionsMenuFCB = addFrameCallback( e.$Exhibitions_MenuFCB ); //will call ex.menu
// } else { //selected a ship
g.$GalleryRole = 0;
// if( g.$GalleryAll && !g.$GalleryShowAll && text == "ZZAll") {
// g.$GalleryShowAll = true;
// g.$GalleryKeysForRole[ 0 ] = g.$GalleryAllObjects; //fill up default key array
// } else if( g.$GalleryAll && g.$GalleryShowAll && text == "ZZEnc") {
// g.$GalleryShowAll = false;
// g.$GalleryKeysForRole[ 0 ] = g.$GalleryEncounters; //fill up default key array
// } else
g.$Gallery_SearchKey(text.toLowerCase(), all);
// }
});
var m = mission.displayModel;
if( m ) {
var w = oolite.gameSettings.gameWindow; //correction if not in widescreen
var wide = Math.max( 0.01, ( w.width / w.height ) / g.$GalleryDefaultZoom );
m.position = Vector3D(m.position.x, m.position.y, m.position.z * wide );
m.orientation = m.orientation.rotateY( Math.PI );
}
} else { //textEntry need Oolite v1.79
msg += "\nType any part of a ship name or press enter for a list.\nDetails of your ship:\n\n";
// if( g.$GalleryAll ) {
// if( all ) msg += "\nType \"enc\" to switch back to the Gallery of encounters.";
// else msg += "\nType \"all\" to switch to the Gallery of all objects.";
// }
msg += g.Gallery_GetShipData(player.ship, g.$GalleryShowAll);
if( isValidFrameCallback( worldScripts["gallery"].$GalleryFCB ) )
removeFrameCallback( worldScripts["gallery"].$GalleryFCB );
mission.runScreen({
title: title,
message: msg,
background: "gallery_bg.png",
model: "["+player.ship.dataKey+"]",
modelPersonality: 0,
spinModel:true,
screenID: "gallery-search",
textEntry: true
},function(text) {
g.$GalleryRole = 0;
if( !text || text.length == 0 ) {
g.$Gallery_Search( all, true );
return;
}
text = text.toLowerCase();
// if( g.$GalleryAll && !g.$GalleryShowAll && text == "all") {
// g.$GalleryShowAll = true;
// g.$GalleryKeysForRole[ 0 ] = g.$GalleryAllObjects; //fill up default key array
// } else if( g.$GalleryAll && g.$GalleryShowAll && text == "enc") {
// g.$GalleryShowAll = false;
// g.$GalleryKeysForRole[ 0 ] = g.$GalleryEncounters; //fill up default key array
// } else
g.$Gallery_SearchKey(text, all);
});
}
}
this.$Gallery_SearchHeadMsg = function( all ) {
var g = worldScripts["gallery"];
var len = g.$GalleryEncounters.length;
if( all ) len = len + " of "+g.$GalleryAllObjects.length;
return( "Your "+player.ship.displayName+" has recorded "+len+" ship and space object types." );
}
this.$Gallery_SearchHeadTitle = function( all ) {
var title = "Gallery of ";
if( all ) title += "all objects";
else title += "encounters";
return( title );
}
this.$Gallery_SearchKey = function( text, all ) {
var g = worldScripts["gallery"];
var k = g.$GalleryKeysForRole[ 0 ];
var found = false;
if( !text || text.length == 0 ) found = true; //no search, show the last item
else if( k ) {
if( !g.$GalleryShowAll ) { //search in name, not in dataKey
var n = g.$GalleryEncNames;
if(g.$GalleryLog) log("Gallery",n);
for( var i = 0; i < n.length; i++ ) {
if ( n[i] && n[i].toLowerCase().indexOf(text) == 0 ) { //find text from begin
found = true;
g.$GalleryKeyi[ 0 ] = i;//set to the found item
i = n.length; //exit
}
}
if( !found ) {
for( var i = 0; i < n.length; i++ ) {
if ( n[i] && n[i].toLowerCase().indexOf(text) != -1 ) { //find text within
found = true;
g.$GalleryKeyi[ 0 ] = i;//set to the found item
i = n.length; //exit
}
}
}
}
if( !found ) for( var i = 0; i < k.length; i++ ) { //search in dataKey
if ( k[i] && k[i].toLowerCase().indexOf(text) == 0 ) { //find text from begin
found = true;
g.$GalleryKeyi[ 0 ] = i;//set to the found item
i = k.length; //exit
}
}
if( !found ) {
for( var i = 0; i < k.length; i++ ) {
if ( k[i] && k[i].toLowerCase().indexOf(text) != -1 ) { //find text within
found = true;
g.$GalleryKeyi[ 0 ] = i;//set to the found item
i = k.length; //exit
}
}
}
if( !found && text.length > 1 ) {
var text1 = text.charAt(0); //find starting letter only
for( var i = 0; i < k.length; i++ ) {
if ( k[i] && k[i].charAt(0).toLowerCase() == text1 ) {
found = true;
g.$GalleryKeyi[ 0 ] = i;//set to the found item
i = k.length; //exit
}
}
}
}
if( found ) g.$Gallery_Interface2( all ); //show it
else g.$Gallery_Search( all, false );//try again
}
/*
this.$Gallery_Timed = function() { //extra ship.remove can not help avoid "Universe is full" due to the remaining entities
for( var i = 0; i < g.$GalleryTrash.length; i++ ) {
g.$GalleryTrash[i].remove(true);
}
if( g.$GalleryLog) log("Gallery", "Removed "+g.$GalleryTrash.length+" tried ship.");
delete g.$GalleryTrash;
}
*/
this.$Gallery_Timed = function() { //cause extreme memory usage and crash when out of allocation space
var g = worldScripts["gallery"];
var maxk = 10; //how many iteration max., very slow and cause "Universe is full" if many OXP ships
var num = 64; //how many ships created at one time
var i = g.$GalleryTRole;//actual role in this timed function
var k = g.$GalleryTRI;//actual TRole Iteration
var prevlen = 0;
if( g.$GalleryTimer ) { //remove old timer
g.$GalleryTimer.stop();
delete g.$GalleryTimer;
}
if( g.$GalleryKeysForRole[ i ] ) prevlen = g.$GalleryKeysForRole[ i ].length;
var ships = system.addShips(g.$GalleryRoles[i], num, [0,0,0], 1000000);
if(ships) {
for( var j = 0; j < ships.length; j++ ) { //created ships
if( ships[j] ) {
var key = ships[j].dataKey;
if( !g.$GalleryKeysForRole[ i ] )
g.$GalleryKeysForRole[ i ] = [key];
else if( g.$GalleryKeysForRole[ i ].indexOf(key) == -1 )
g.$GalleryKeysForRole[ i ].push(key);//add new key
ships[j].remove(true);//can not remove everything, can reach Universe limit
// if(g.$GalleryLog) log("Gallery", i + ". main role: " + g.$GalleryRoles[i]
// +" "+k+". try, "+(j+1)+". key: "+key
// +" GalleryKeysForRole["+i+"]:"+g.$GalleryKeysForRole[ i ]);
}
}
if(g.$GalleryLog) log("Gallery", i + ". main role: " + g.$GalleryRoles[i]
+" "+k+". try: "+g.$GalleryKeysForRole[ i ].length+" object." );
if(prevlen == g.$GalleryKeysForRole[ i ].length) maxk = 0;//exit from iteration cycle
}
var end = false;
g.$GalleryTRI++;
if( g.$GalleryTRI > maxk ) {
if(g.$GalleryKeysForRole[ i ]) {
g.$GalleryKeysForRole[ i ].sort();
if(g.$GalleryLog) log("Gallery", i + ". role after "+k+" try: " + g.$GalleryRoles[i]
+ " ("+g.$GalleryKeysForRole[ i ].length+"): " + g.$GalleryKeysForRole[ i ] );
g.$GalleryKeysForRole[ 0 ] = g.$GalleryKeysForRole[ 0 ].concat(g.$GalleryKeysForRole[ i ]);
}
g.$GalleryTRI = 1;
g.$GalleryTRole++;
if( g.$GalleryTRole >= g.$GalleryRoles.length ) {
g.$GalleryKeysForRole[ 0 ].sort();
for( var i = 1; i < g.$GalleryKeysForRole[ 0 ].length; i++ ) { //remove duplicated keys
if(g.$GalleryKeysForRole[0][i] == g.$GalleryKeysForRole[0][i-1]) {
g.$GalleryKeysForRole[0].splice(i,1); //remove this item
i--;
}
}
if(g.$GalleryLog) log("Gallery", "All dataKeys ("+g.$GalleryKeysForRole[ 0 ].length
+"): " + g.$GalleryKeysForRole[ 0 ] );
end = true; //dataKey search finished, no more timer start
}
}
if( !end ) g.$GalleryTimer = new Timer(g, g.$Gallery_Timed, 2.3); //will make the next step
}
this.$GalleryValidateTarget = function(target) {
if( target.dataKey.indexOf("stealth") > -1 || target.primaryRole.indexOf("stealth") > -1
|| target.scriptInfo && target.scriptInfo.ccl_missionShip //skip mission ships
|| target.name == "Constrictor"
|| target.dataKey == "vector_arn" //mission ship in Vector OXP
|| target.primaryRole.indexOf("rescue_blackbox") > -1 ) //mission ships in Rescue Stations OXP
return false;
if( !target.roles ) return true; //bugfix for entities without any role
var lib = worldScripts["tech_ref_lib"];
if( lib ) return( lib.$validateTarget(target) ); //call the original function if available
//following lines comes from Technical Reference Library OXP by spara
//check scanclasses
if (this.$GalleryClassifiedScanClasses.indexOf(target.scanClass) != -1) return false;
//check roles
var targetRoles = target.roles;
var i;
for (i = 0; i < targetRoles.length; i++) {
if (this.$GalleryClassifiedRoles.indexOf(targetRoles[i]) != -1) {
return false;
}
}
//check for script_info key
if (target.scriptInfo && target.scriptInfo.classifiedShip) return false;
return true;
}
|