- Add "interfaces" mechanism to stations (F4) to allow "pull" rather than "push" access to mission screens.

- Add parcel deliveries to interfaces so that there's something there.
- Tweak mission screen options to add colour to choices, for parcel consistency with r5320.


git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@5327 127b21dd-08f5-0310-b4b7-95ae10353056
master
Chris Morris 2012-09-14 19:49:53 +00:00
parent 320de0d9e6
commit 266294005b
26 changed files with 1737 additions and 22 deletions

Binary file not shown.

View File

@ -274,6 +274,7 @@ OOLITE_SCRIPTING_FILES = \
OOJSEquipmentInfo.m \
OOJSFunction.m \
OOJSGlobal.m \
OOJSInterfaceDefinition.m \
OOJSManifest.m \
OOJSMission.m \
OOJSMissionVariables.m \

View File

@ -1141,7 +1141,13 @@
"weapon-installed-@" = "Weapon installed: %@.";
"weapon-@-enter-to-replace" = "Weapon installed: %@. Press enter to replace it.";
"no-weapon-enter-to-install" = "No weapon installed. Press enter to install this weapon here.";
// Interfaces screen
"interfaces-title" = "Ship and System Interfaces";
"interfaces-no-interfaces-available-for-use" = "No interfaces are installed on your ship or enabled at this station";
"interfaces-for-ship-@-and-station-@" = "Interfaces for %@ and %@";
"interfaces-unspecified-category" = "Uncategorised";
// Contracts screen
"@-contracts-title" = "%@ Carrier Market";
@ -1186,6 +1192,7 @@
"manifest-none" = " None.";
"manifest-cargo-d-d" = "Cargo %d t (%d t):";
"manifest-passengers-d-d" = "Passengers %d (%d):";
"manifest-parcels" = "Parcels:";
"manifest-contracts" = "Contracts:";
"manifest-missions" = "Missions:";
"manifest-@-travelling-to-@-to-arrive-within-@" = " %@ travelling to %@ to arrive within %@.";
@ -1292,7 +1299,19 @@
"passenger-delivered-okay-@-@-@" = "%@ thanks you, and pays you %@ for delivering them to %@.\n";
"passenger-delivered-late-@-@-@" = "%@ pays you %@ for eventually delivering them to %@.\n";
"passenger-failed-@" = "%@ leaves your ship, annoyed that you have wasted so much of their time.\n";
"parcel-delivered-okay-@-@" = "You deliver %@, and are paid %@.\n";
"parcel-delivered-late-@-@" = "You have arrived late to deliver %@, and are only paid %@.\n";
"parcel-failed-@" = "You have failed to deliver %@ on time, and will not be paid.\n";
"parcel-description" =
(
"Videos of [34] [35]",
"Data backups",
"Tax returns",
"Licensing forms",
"Recipes for [30] [33]"
);
"cargo-delivered-okay-@-@" = "Droids unload the %@ and you are paid %@.";
"cargo-delivered-short-@-@-d" = "Droids unload the %@, but you are only paid %@ as there is a %d percent shortfall.";
"cargo-refused-short-%@" = "You dont have enough inventory to deliver the %@.";

View File

@ -56,4 +56,35 @@
"OOLITE_TRUMBLE_NO" = "No thanks. No pets on my ship.";
"OOLITE_TRUMBLE_YES" = "Okay, Ill take one, it looks cute.";
};
// Parcel delivery contracts (oolite-contracts-parcels.js)
"oolite-contracts-parcels-interface-title" = "Parcel contract deliveries ([oolite-contracts-parcels-interface-title-count] available)";
"oolite-contracts-parcels-interface-summary" = "Deliveries of small parcels to recipients in other systems. No special equipment is required, and the parcels will not take up space in your hold.";
"oolite-contracts-parcels-interface-category" = "Contracts";
"oolite-contracts-parcels-none-available-title" = "Parcel delivery contracts";
"oolite-contracts-parcels-none-available-message" = "There are currently no parcel delivery contracts available in this system.";
"oolite-contracts-parcels-title-summary" = "Parcel delivery contracts";
"oolite-contracts-parcels-title-detail" = "Parcel delivery contract [oolite-contracts-parcels-title-detail-number] of [oolite-contracts-parcels-title-detail-total]";
"oolite-contracts-parcels-column-cargo" = "Package";
"oolite-contracts-parcels-column-destination" = "Destination";
"oolite-contracts-parcels-column-within" = "Within";
"oolite-contracts-parcels-column-fee" = "Fee";
"oolite-contracts-parcels-long-description" = "[oolite-contracts-parcels-longdesc-sender] has some [oolite-contracts-parcels-longdesc-contents] that need to be taken to [oolite-contracts-parcels-longdesc-destination] within [oolite-contracts-parcels-longdesc-deadline]. The journey will take about [oolite-contracts-parcels-longdesc-time], and you will be paid [oolite-contracts-parcels-longdesc-payment] upon successful delivery.";
"oolite-contracts-parcels-command-ana-quickest" = "Show quickest route";
"oolite-contracts-parcels-command-ana-shortest" = "Show route with fewest jumps";
"oolite-contracts-parcels-command-back" = "Previous contract";
"oolite-contracts-parcels-command-next" = "Next contract";
"oolite-contracts-parcels-command-list" = "List all contracts";
"oolite-contracts-parcels-command-accept" = "Accept delivery contract";
"oolite-contracts-parcels-command-quit" = "Exit parcel delivery contracts";
"oolite-contracts-parcels-time-format" = "[oolite-contracts-parcels-time-format-hours] hours";
}

View File

@ -3,5 +3,6 @@
"oolite-cloaking-device-mission.js",
"oolite-nova-mission.js",
"oolite-thargoid-plans-mission.js",
"oolite-trumbles-mission.js"
"oolite-trumbles-mission.js",
"oolite-contracts-parcels.js"
)

View File

@ -0,0 +1,617 @@
/*
oolite-contracts-parcels.js
Script for managing parcel contracts
Oolite
Copyright © 2004-2012 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
/*jslint white: true, undef: true, eqeqeq: true, bitwise: true, regexp: true, newcap: true, immed: true */
/*global galaxyNumber, missionVariables, system*/
"use strict";
this.name = "oolite-contracts-parcels";
this.author = "cim";
this.copyright = "© 2012 the Oolite team.";
this.description = "Parcel delivery contracts.";
this.version = "1.77";
/* Configuration options */
// OXPs which alter the background for the long range chart screen may
// wish to overwrite this value.
this.$longRangeChartBackground = "oolite-long-range-chart.png";
// OXPs which wish to add a background to the summary pages should
// set this value
this.$parcelSummaryPageBackground = "";
/* Event handlers */
this.startUp = function()
{
// stored contents of local main station's parcel contract list
if (missionVariables.oolite_contracts_parcels)
{
this.$parcels = JSON.parse(missionVariables.oolite_contracts_parcels);
}
else
{
this._initialiseParcelContractsForSystem();
}
this._updateMainStationInterfacesList();
}
this.shipWillExitWitchspace = function()
{
this._initialiseParcelContractsForSystem();
this._updateMainStationInterfacesList();
}
this.playerWillSaveGame = function()
{
// encode the contract list to a string for storage in the savegame
missionVariables.oolite_contracts_parcels = JSON.stringify(this.$parcels);
}
// if the player launches from within the mission screens, reset their
// destination system and HUD settings, which the mission screens may
// have affected.
this.shipWillLaunchFromStation = function() {
if (this.$suspendedDestination) {
player.ship.targetSystem = this.$suspendedDestination;
player.ship.hudHidden = this.$suspendedHUD;
}
}
/* Interface functions */
// initialise a new parcel contract list for the current system
this._initialiseParcelContractsForSystem = function()
{
// clear list
this.$parcels = [];
// basic range -1 to +3 evenly distributed
// parcel contracts require far less investment than cargo or passenger
// so fewer are available
var numContracts = Math.floor(Math.random()*5) - 1;
// larger systems more likely to have contracts, smaller less likely
if (system.info.population > 50)
{
numContracts++;
}
else if (system.info.population < 30)
{
numContracts--;
}
// if the player has a bad reputation, reduce the available contract number
if (player.parcelReputation < 0)
{
numContracts += player.parcelReputation;
}
// if they have a very good reputation, increase the numbers
else if (player.parcelReputation > 4)
{
numContracts += (player.parcelReputation - 4);
}
// always have at least two available for new Jamesons
if (!missionVariables.oolite_contracts_parcels && numContracts < 2)
{
numContracts = 2;
}
for (var i = 0; i < numContracts; i++)
{
var parcel = new Object;
// pick a random system to take the parcel to
var destination = Math.floor(Math.random()*256);
// discard if chose the current system
if (destination === system.ID)
{
continue;
}
// get the SystemInfo object for the destination
var destinationInfo = System.infoForSystem(galaxyNumber,destination);
// check that a route to the destination exists
var routeToDestination = system.info.routeToSystem(destinationInfo);
// if the system cannot be reached, discard the parcel
if (!routeToDestination)
{
continue;
}
// we now have a valid destination, so generate the rest of
// the parcel details
parcel.destination = destination;
// we'll need this again later, and route calculation is slow
parcel.route = routeToDestination;
parcel.sender = randomName()+" "+randomName();
parcel.description = expandDescription("[parcel-description]");
// time allowed for delivery is time taken by "fewest jumps"
// route, plus 10-60%, plus one day
parcel.deadline = clock.seconds + Math.floor((routeToDestination.time * 3600 * 1.1+(Math.random()/2))) + 86400;
// total payment is small for these items.
parcel.payment = Math.floor(
// 2-3 credits per LY of route
(routeToDestination.distance * (2+Math.random())) +
// additional income for route length based on reputation
(Math.pow(routeToDestination.route.length,1+(0.1*player.parcelReputation))) +
// small premium for delivery to more dangerous systems
(2 * Math.pow(7-destinationInfo.government,1.5))
);
// add parcel to contract list
this.$parcels.push(parcel);
}
}
// this should be called every time the contents of this.$parcelContracts
// change, as it updates the summary of the interface entry.
this._updateMainStationInterfacesList = function()
{
if (this.$parcels.length === 0)
{
// no contracts, remove interface if it exists
system.mainStation.setInterface("oolite-contracts-parcels",null);
}
else
{
var title = expandMissionText("oolite-contracts-parcels-interface-title",{
"oolite-contracts-parcels-interface-title-count": this.$parcels.length
});
system.mainStation.setInterface("oolite-contracts-parcels",{
title: title,
category: expandMissionText("oolite-contracts-parcels-interface-category"),
summary: expandMissionText("oolite-contracts-parcels-interface-summary"),
callback: this._parcelContractsScreens.bind(this)
// could alternatively use "cbThis: this" parameter instead of bind()
});
}
}
// if the interface is activated, this function is run.
this._parcelContractsScreens = function(interfaceKey)
{
// the interfaceKey parameter is not used here, but would be useful if
// this callback managed more than one interface entry
// set up variables used to remember state on the mission screens
this.$suspendedDestination = null;
this.$suspendedHUD = false;
this.$contractIndex = 0;
this.$routeMode = "LONG_RANGE_CHART_SHORTEST";
this.$lastOptionChosen = "06_EXIT";
// start on the summary page if more than one contract is available
var summary = (this.$parcels.length > 1);
this._parcelContractsDisplay(summary);
}
// this function is called after the player makes a choice which keeps
// them in the system, and also on initial entry to the system
// to select the appropriate mission screen and display it
this._parcelContractsDisplay = function(summary) {
// if there are no parcels (because the player has taken the last one)
// display a message and quit.
if (this.$parcels.length === 0)
{
mission.runScreen({titleKey: "oolite-contracts-parcels-none-available-title",
messageKey: "oolite-contracts-parcels-none-available-message"});
// no callback, just exits contracts system
return;
}
// make sure that the 'currently selected contract' pointer
// is in bounds
if (this.$contractIndex >= this.$parcels.length)
{
this.$contractIndex = 0;
}
else if (this.$contractIndex < 0)
{
this.$contractIndex = this.$parcels.length - 1;
}
// sub functions display either summary or detail screens
if (summary)
{
this._parcelContractSummaryPage();
}
else
{
this._parcelContractSinglePage();
}
}
// display the mission screen for the summary page
this._parcelContractSummaryPage = function()
{
// column 'tab stops'
var columns = [13,21,28];
// column header line
var headline = expandMissionText("oolite-contracts-parcels-column-cargo");
// pad to correct length to give a table-like layout
headline += this._paddingText(headline,columns[0]);
headline += expandMissionText("oolite-contracts-parcels-column-destination");
headline += this._paddingText(headline,columns[1]);
headline += expandMissionText("oolite-contracts-parcels-column-within");
headline += this._paddingText(headline,columns[2]);
headline += expandMissionText("oolite-contracts-parcels-column-fee");
// required because of way choices are displayed.
headline = " "+headline;
// setting options dynamically; one contract per line
var options = new Object;
var i;
for (i=0; i<this.$parcels.length; i++)
{
// temp variable to simplify following code
var parcel = this.$parcels[i];
// write the parcel description, padded to line up with the headers
var optionText = parcel.description;
optionText += this._paddingText(optionText, columns[0]);
optionText += System.infoForSystem(galaxyNumber, parcel.destination).name;
optionText += this._paddingText(optionText, columns[1]);
optionText += this._timeRemaining(parcel);
optionText += this._paddingText(optionText, columns[2]);
// right-align the fee so that the credits signs line up
var priceText = formatCredits(parcel.payment,false,true);
priceText = this._paddingText(priceText, 2.5)+priceText;
optionText += priceText
// maximum of seven contracts available, so no need to pad the number
// in the key to maintain alphabetical order
// needs to be aligned left to line up with the heading
options["01_CONTRACT_"+i] = { text: optionText, alignment: "LEFT" };
// if there doesn't appear to be sufficient time remaining
if (this._timeRemainingSeconds(parcel) < this._timeEstimateSeconds(parcel))
{
options["01_CONTRACT_"+i].color = "orangeColor";
}
}
// if we've come from the detail screen, make sure the last
// contract shown there is selected here
var initialChoice = ["01_CONTRACT_"+this.$contractIndex];
// next, an empty string gives an unselectable row
options["02_SPACER"] = "";
// numbered 06 to match the option of the same function in the other branch
options["06_EXIT"] = expandMissionText("oolite-contracts-parcels-command-quit");
// now need to add further spacing to fill the remaining rows, or
// the options will end up at the bottom of the screen.
var rowsToFill = 21;
if (player.ship.hudHidden)
{
rowsToFill = 27;
}
for (i = 4 + this.$parcels.length; i < rowsToFill ; i++)
{
// each key needs to be unique at this stage.
options["07_SPACER_"+i] = "";
}
var missionConfig = {titleKey: "oolite-contracts-parcels-title-summary",
message: headline,
choices: options,
initialChoicesKey: initialChoice};
if (this.$parcelSummaryPageBackground != "") {
missionConfig.background = this.$parcelSummaryPageBackground;
}
// now run the mission screen
mission.runScreen(missionConfig, this._processParcelChoice);
}
// display the mission screen for the contract detail page
this._parcelContractSinglePage = function()
{
// temp variable to simplify code
var parcel = this.$parcels[this.$contractIndex];
// This mission screen uses the long range chart as a backdrop.
// This means that the first 18 lines are taken up by the chart,
// and we can't put text there without overwriting the chart.
// We therefore need to hide the player's HUD, to get the full 27
// lines.
if (!player.ship.hudHidden)
{
this.$suspendedHUD = true; // note that we hid it, for later
player.ship.hudHidden = true;
}
// We also set the player's witchspace destination temporarily
// so we need to store the old one in a variable to reset it later
this.$suspendedDestination = player.ship.targetSystem;
// That done, we can set the player's destination so the map looks
// right.
player.ship.targetSystem = parcel.destination;
// start with 18 blank lines, since we don't want to overlap the chart
var message = new Array(18).join("\n");
message += expandMissionText("oolite-contracts-parcels-long-description",{
"oolite-contracts-parcels-longdesc-sender": parcel.sender,
"oolite-contracts-parcels-longdesc-contents": this._formatPackageName(parcel.description),
"oolite-contracts-parcels-longdesc-destination": System.infoForSystem(galaxyNumber,parcel.destination).name,
"oolite-contracts-parcels-longdesc-deadline": this._timeRemaining(parcel),
"oolite-contracts-parcels-longdesc-time": this._timeEstimate(parcel),
"oolite-contracts-parcels-longdesc-payment": formatCredits(parcel.payment,false,true)
});
// use a special background
var backgroundSpecial = "LONG_RANGE_CHART";
// the available options will vary quite a bit, so this rather
// than a choicesKey in missiontext.plist
var options = new Object;
// these are the only options which are always available
options["05_ACCEPT"] = {
text: expandMissionText("oolite-contracts-parcels-command-accept")
};
// if there's not much time left, change the option colour as a warning!
if (this._timeRemainingSeconds(parcel) < this._timeEstimateSeconds(parcel))
{
options["05_ACCEPT"].color = "orangeColor";
}
options["06_EXIT"] = expandMissionText("oolite-contracts-parcels-command-quit");
// if the ship has a working advanced nav array, can switch
// between 'quickest' and 'shortest' routes
// (and also upgrade the special background)
if (player.ship.equipmentStatus("EQ_ADVANCED_NAVIGATIONAL_ARRAY") === "EQUIPMENT_OK")
{
backgroundSpecial = this.$routeMode;
if (this.$routeMode === "LONG_RANGE_CHART_SHORTEST")
{
options["01_MODE"] = expandMissionText("oolite-contracts-parcels-command-ana-quickest");
}
else
{
options["01_MODE"] = expandMissionText("oolite-contracts-parcels-command-ana-shortest");
}
}
// if there's more than one, need options for forward, back, and listing
if (this.$parcels.length > 1)
{
options["02_BACK"] = expandMissionText("oolite-contracts-parcels-command-back");
options["03_NEXT"] = expandMissionText("oolite-contracts-parcels-command-next");
options["04_LIST"] = expandMissionText("oolite-contracts-parcels-command-list");
}
else
{
// if not, we may need to set a different choice
// we never want 05_ACCEPT to end up selected initially
if (this.$lastChoice === "02_BACK" || this.$lastChoice === "03_NEXT" || this.$lastChoice === "04_LIST")
{
this.$lastChoice = "06_EXIT";
}
}
var title = expandMissionText("oolite-contracts-parcels-title-detail",{
"oolite-contracts-parcels-title-detail-number": this.$contractIndex+1,
"oolite-contracts-parcels-title-detail-total": this.$parcels.length
});
// finally, after all that setup, actually create the mission screen
mission.runScreen({
title: title,
message: message,
background: this.$longRangeChartBackground,
backgroundSpecial: backgroundSpecial,
choices: options,
initialChoicesKey: this.$lastChoice
},this._processParcelChoice);
}
this._processParcelChoice = function(choice)
{
// firstly, restore the HUD and witchspace destination if
// necessary, and clear the stashed values
if (this.$suspendedDestination !== null)
{
player.ship.targetSystem = this.$suspendedDestination;
this.$suspendedDestination = null;
}
if (this.$suspendedHUD)
{
player.ship.hudHidden = false;
this.$suspendedHUD = false;
}
if (choice === null)
{
// can occur if ship launches mid mission screen
return;
}
// now process the various choices
if (choice.match(/^01_CONTRACT_/))
{
// contract selected from summary page
// set the index to that contract, and show details
var index = parseInt(choice.slice(12));
this.$contractIndex = index;
this.$lastChoice = "04_LIST";
this._parcelContractsDisplay(false);
}
else if (choice === "01_MODE")
{
// advanced navigation array mode flip
this.$routeMode = (this.$routeMode === "LONG_RANGE_CHART_SHORTEST")?"LONG_RANGE_CHART_QUICKEST":"LONG_RANGE_CHART_SHORTEST";
this.$lastChoice = "01_MODE";
this._parcelContractsDisplay(false);
}
else if (choice === "02_BACK")
{
// reduce contract index (parcelContractsDisplay manages wraparound)
this.$contractIndex--;
this.$lastChoice = "02_BACK";
this._parcelContractsDisplay(false);
}
else if (choice === "03_NEXT")
{
// increase contract index (parcelContractsDisplay manages wraparound)
this.$contractIndex++;
this.$lastChoice = "03_NEXT";
this._parcelContractsDisplay(false);
}
else if (choice === "04_LIST")
{
// display the summary page
this._parcelContractsDisplay(true);
}
else if (choice === "05_ACCEPT")
{
this._acceptContract();
// do not leave the setting as accept for the next contract!
this.$lastChoice = "03_NEXT";
this._parcelContractsDisplay(false);
}
// if we get this far without having called parcelContractsDisplay
// that means either 'exit' or an unrecognised option was chosen
}
// move a parcel from the contracts list to the player's ship
this._acceptContract = function()
{
var parcel = this.$parcels[this.$contractIndex];
// give the parcel to the player
player.ship.addParcel(parcel.sender+"'s "+this._formatPackageName(parcel.description),system.ID,parcel.destination,parcel.deadline,parcel.payment);
// remove the parcel from the station list
this.$parcels.splice(this.$contractIndex,1);
// update the interface description
this._updateMainStationInterfacesList();
}
/* Utility functions */
// returns a string containing the necessary number of "hair spaces" to
// pad the currentText string to the specified length in 'em'
this._paddingText = function(currentText, desiredLength)
{
var hairSpace = String.fromCharCode(31);
var currentLength = defaultFont.measureString(currentText);
var hairSpaceLength = defaultFont.measureString(hairSpace);
// calculate number needed to fill remaining length
var padsNeeded = Math.floor((desiredLength - currentLength) / hairSpaceLength);
// quick way of generating a repeated string of that number
return new Array(padsNeeded).join(hairSpace);
}
// gives a text description of the time remaining to deliver this parcel
this._timeRemaining = function(parcel)
{
return this._formatTravelTime(this._timeRemainingSeconds(parcel));
}
this._timeRemainingSeconds = function(parcel) {
return parcel.deadline - clock.seconds;
}
// gives a text description of a reasonable travel time to deliver this parcel
this._timeEstimate = function(parcel)
{
// allow 30 minutes in each system on the shortest route
return this._formatTravelTime(this._timeEstimateSeconds(parcel));
}
this._timeEstimateSeconds = function(parcel)
{
return (parcel.route.time * 3600) + (parcel.route.route.length * 1800);
}
// format the travel time
this._formatTravelTime = function(seconds) {
// this function uses an hours-only format
// but provides enough information to use a days&hours format if
// oolite-contracts-parcels-time-format in missiontext.plist is overridden
// extra minutes are discarded
var hours = Math.floor(seconds/3600);
var days = Math.floor(hours/24);
var spareHours = hours % 24;
return expandMissionText("oolite-contracts-parcels-time-format",{
"oolite-contracts-parcels-time-format-hours": hours,
"oolite-contracts-parcels-time-format-days": days,
"oolite-contracts-parcels-time-format-spare-hours": spareHours
});
}
// lower-cases the initial letter of the package contents
this._formatPackageName = function(name) {
return name.charAt(0).toLowerCase() + name.slice(1);
}

View File

@ -108,7 +108,13 @@ enum
GUI_ROW_EQUIPMENT_CASH = 1,
GUI_ROW_MARKET_KEY = 1,
GUI_ROW_MARKET_START = 2,
GUI_ROW_MARKET_CASH = 20
GUI_ROW_MARKET_CASH = 20,
GUI_ROW_INTERFACES_HEADING = 1,
GUI_ROW_INTERFACES_START = 3,
GUI_MAX_ROWS_INTERFACES = 12,
GUI_ROW_INTERFACES_DETAIL = GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES + 1,
GUI_ROW_NO_INTERFACES = 3
};
#if GUI_FIRST_ROW() < 0
# error Too many items in OPTIONS list!
@ -237,6 +243,9 @@ typedef enum
#define PASSAGE_GOOD_KEY @"passage_fulfilled"
#define PASSAGE_BAD_KEY @"passage_expired"
#define PASSAGE_UNKNOWN_KEY @"passage_unknown"
#define PARCEL_GOOD_KEY @"parcels_fulfilled"
#define PARCEL_BAD_KEY @"parcels_expired"
#define PARCEL_UNKNOWN_KEY @"parcels_unknown"
#define SCANNER_ZOOM_RATE_UP 2.0
@ -286,6 +295,9 @@ typedef enum
unsigned max_passengers;
NSMutableArray *passengers;
NSMutableDictionary *passenger_record;
NSMutableArray *parcels;
NSMutableDictionary *parcel_record;
NSMutableArray *contracts;
NSMutableDictionary *contract_record;
@ -733,6 +745,11 @@ typedef enum
- (OOWeaponFacingSet) availableFacings;
- (void) setGuiToEquipShipScreen:(int)skip selectingFacingFor:(NSString *)eqKeyForSelectFacing;
- (void) setGuiToEquipShipScreen:(int)skip;
- (void) setGuiToInterfacesScreen:(int)skip;
- (void) showInformationForSelectedInterface;
- (void) activateSelectedInterface;
- (void) highlightEquipShipScreenKey:(NSString *)key;
- (void) showInformationForSelectedUpgrade;
- (void) showInformationForSelectedUpgradeWithFormatString:(NSString *)extraString;
@ -752,6 +769,7 @@ typedef enum
- (OOGUIScreenID) guiScreen;
- (void) buySelectedItem;
- (BOOL) marketFlooded:(OOCommodityType)type;
- (BOOL) tryBuyingCommodity:(OOCommodityType)type all:(BOOL)all;
- (BOOL) trySellingCommodity:(OOCommodityType)type all:(BOOL)all;

View File

@ -71,6 +71,7 @@ MA 02110-1301, USA.
#import "OOScriptTimer.h"
#import "OOJSEngineTimeManagement.h"
#import "OOJSScript.h"
#import "OOJSInterfaceDefinition.h"
#import "OOConstToJSString.h"
#import "OOJoystickManager.h"
@ -726,10 +727,25 @@ static GLfloat sBaseMass = 0.0;
// reputation
[result setObject:reputation forKey:@"reputation"];
// initialise parcel reputations in dictionary if not set
int pGood = [reputation oo_intForKey:PARCEL_GOOD_KEY];
int pBad = [reputation oo_intForKey:PARCEL_BAD_KEY];
int pUnknown = [reputation oo_intForKey:PARCEL_UNKNOWN_KEY];
if (pGood+pBad+pUnknown != 7)
{
[reputation oo_setInteger:0 forKey:PARCEL_GOOD_KEY];
[reputation oo_setInteger:0 forKey:PARCEL_BAD_KEY];
[reputation oo_setInteger:7 forKey:PARCEL_UNKNOWN_KEY];
}
// passengers
[result oo_setInteger:max_passengers forKey:@"max_passengers"];
[result setObject:passengers forKey:@"passengers"];
[result setObject:passenger_record forKey:@"passenger_record"];
// parcels
[result setObject:parcels forKey:@"parcels"];
[result setObject:parcel_record forKey:@"parcel_record"];
//specialCargo
if (specialCargo) [result setObject:specialCargo forKey:@"special_cargo"];
@ -933,6 +949,8 @@ static GLfloat sBaseMass = 0.0;
if (reputation == nil) reputation = [[NSMutableDictionary alloc] init];
// passengers and contracts
[parcels release];
[parcel_record release];
[passengers release];
[passenger_record release];
[contracts release];
@ -946,6 +964,8 @@ static GLfloat sBaseMass = 0.0;
passenger_record = nil;
contracts = nil;
contract_record = nil;
parcels = nil;
parcel_record = nil;
}
else
{
@ -954,12 +974,17 @@ static GLfloat sBaseMass = 0.0;
passenger_record = [[dict oo_dictionaryForKey:@"passenger_record"] mutableCopy];
contracts = [[dict oo_arrayForKey:@"contracts"] mutableCopy];
contract_record = [[dict oo_dictionaryForKey:@"contract_record"] mutableCopy];
parcels = [[dict oo_arrayForKey:@"parcels"] mutableCopy];
parcel_record = [[dict oo_dictionaryForKey:@"parcel_record"] mutableCopy];
}
if (passengers == nil) passengers = [[NSMutableArray alloc] init];
if (passenger_record == nil) passenger_record = [[NSMutableDictionary alloc] init];
if (contracts == nil) contracts = [[NSMutableArray alloc] init];
if (contract_record == nil) contract_record = [[NSMutableDictionary alloc] init];
if (parcels == nil) parcels = [[NSMutableArray alloc] init];
if (parcel_record == nil) parcel_record = [[NSMutableDictionary alloc] init];
//specialCargo
[specialCargo release];
@ -1402,6 +1427,9 @@ static GLfloat sBaseMass = 0.0;
[reputation oo_setInteger:0 forKey:PASSAGE_GOOD_KEY];
[reputation oo_setInteger:0 forKey:PASSAGE_BAD_KEY];
[reputation oo_setInteger:7 forKey:PASSAGE_UNKNOWN_KEY];
[reputation oo_setInteger:0 forKey:PARCEL_GOOD_KEY];
[reputation oo_setInteger:0 forKey:PARCEL_BAD_KEY];
[reputation oo_setInteger:7 forKey:PARCEL_UNKNOWN_KEY];
energy = 256;
weapon_temp = 0.0f;
@ -1427,6 +1455,11 @@ static GLfloat sBaseMass = 0.0;
contracts = [[NSMutableArray alloc] init];
[contract_record release];
contract_record = [[NSMutableDictionary alloc] init];
[parcels release];
parcels = [[NSMutableArray alloc] init];
[parcel_record release];
parcel_record = [[NSMutableDictionary alloc] init];
[missionDestinations release];
missionDestinations = [[NSMutableDictionary alloc] init];
@ -1706,6 +1739,8 @@ static GLfloat sBaseMass = 0.0;
DESTROY(passenger_record);
DESTROY(contracts);
DESTROY(contract_record);
DESTROY(parcels);
DESTROY(parcel_record);
DESTROY(missionDestinations);
DESTROY(shipyard_record);
@ -2407,6 +2442,7 @@ static GLfloat sBaseMass = 0.0;
// Screens from which it's safe to jump to the mission screen
case GUI_SCREEN_CONTRACTS:
case GUI_SCREEN_EQUIP_SHIP:
case GUI_SCREEN_INTERFACES:
case GUI_SCREEN_LONG_RANGE_CHART:
case GUI_SCREEN_MANIFEST:
case GUI_SCREEN_SHIPYARD:
@ -5028,7 +5064,7 @@ static GLfloat sBaseMass = 0.0;
[self unloadCargoPods]; // fill up the on-ship commodities before...
// check contracts
NSString *passengerAndCargoReport = [self checkPassengerContracts]; // Is also processing cargo contracts.
NSString *passengerAndCargoReport = [self checkPassengerContracts]; // Is also processing cargo and parcel contracts.
[self addMessageToReport:passengerAndCargoReport];
[UNIVERSE setDisplayText:YES];
@ -5301,9 +5337,12 @@ static GLfloat sBaseMass = 0.0;
[UNIVERSE removeAllEntitiesExceptPlayer];
// remove any contracts for the old galaxy
// remove any contracts and parcels for the old galaxy
if (contracts)
[contracts removeAllObjects];
if (parcels)
[parcels removeAllObjects];
// remove any mission destinations for the old galaxy
if (missionDestinations)
@ -5861,6 +5900,12 @@ static GLfloat sBaseMass = 0.0;
}
- (NSArray *) parcelListForScripting
{
return [self contractsListForScriptingFromArray:parcels forCargo:NO];
}
- (NSArray *) contractListForScripting
{
return [self contractsListForScriptingFromArray:contracts forCargo:YES];
@ -6008,6 +6053,12 @@ static GLfloat sBaseMass = 0.0;
marker = [self passengerContractMarker:sysid];
[self prepareMarkedDestination:destinations:marker];
}
for (i = 0; i < [parcels count]; i++)
{
sysid = [[parcels oo_dictionaryAtIndex:i] oo_unsignedCharForKey:CONTRACT_KEY_DESTINATION];
marker = [self parcelContractMarker:sysid];
[self prepareMarkedDestination:destinations:marker];
}
for (i = 0; i < [contracts count]; i++)
{
sysid = [[contracts oo_dictionaryAtIndex:i] oo_unsignedCharForKey:CONTRACT_KEY_DESTINATION];
@ -6879,6 +6930,177 @@ static NSString *last_outfitting_key=nil;
}
- (void) setGuiToInterfacesScreen:(int)skip
{
[[UNIVERSE gameController] setMouseInteractionModeForUIWithMouseInteraction:YES];
// build an array of available interfaces
NSDictionary *interfaces = [dockedStation localInterfaces];
NSArray *interfaceKeys = [interfaces keysSortedByValueUsingSelector:@selector(interfaceCompare:)]; // sorts by category, then title
int i;
// GUI stuff
{
GuiDisplayGen *gui = [UNIVERSE gui];
OOGUIRow start_row = GUI_ROW_INTERFACES_START;
OOGUIRow row = start_row;
BOOL guiChanged = (gui_screen != GUI_SCREEN_INTERFACES);
[gui clearAndKeepBackground:!guiChanged];
[gui setTitle:DESC(@"interfaces-title")];
OOGUITabSettings tab_stops;
tab_stops[0] = 0;
tab_stops[1] = -480;
[gui setTabStops:tab_stops];
unsigned n_rows = GUI_MAX_ROWS_INTERFACES;
NSUInteger count = [interfaceKeys count];
if (count > 0)
{
if (skip > 0) // lose the first row to Back <--
{
unsigned previous;
if (count <= n_rows || skip < n_rows)
previous = 0; // single page
else
{
previous = skip - (n_rows - 2); // multi-page.
if (previous < 2)
previous = 0; // if only one previous item, just show it
}
[gui setKey:[NSString stringWithFormat:@"More:%d", previous] forRow:row];
[gui setColor:[OOColor greenColor] forRow:row];
[gui setArray:[NSArray arrayWithObjects:DESC(@"gui-back"), @" <-- ", nil] forRow:row];
row++;
}
for (i = skip; i < count && (row - start_row < (OOGUIRow)n_rows); i++)
{
NSString *interfaceKey = [interfaceKeys objectAtIndex:i];
OOJSInterfaceDefinition *definition = [interfaces objectForKey:interfaceKey];
[gui setKey:interfaceKey forRow:row];
[gui setArray:[NSArray arrayWithObjects:[definition title],[definition category], nil] forRow:row];
row++;
}
if (i < count)
{
// just overwrite the last item :-)
[gui setColor:[OOColor greenColor] forRow:row - 1];
[gui setArray:[NSArray arrayWithObjects:DESC(@"gui-more"), @" --> ", nil] forRow:row - 1];
[gui setKey:[NSString stringWithFormat:@"More:%d", i - 1] forRow:row - 1];
}
[gui setSelectableRange:NSMakeRange(start_row,row - start_row)];
if ([gui selectedRow] != start_row)
[gui setSelectedRow:start_row];
[self showInformationForSelectedInterface];
}
else
{
[gui setText:DESC(@"interfaces-no-interfaces-available-for-use") forRow:GUI_ROW_NO_INTERFACES align:GUI_ALIGN_LEFT];
[gui setColor:[OOColor greenColor] forRow:GUI_ROW_NO_INTERFACES];
[gui setSelectableRange:NSMakeRange(0,0)];
[gui setNoSelectedRow];
}
[gui setShowTextCursor:NO];
NSString *desc = [NSString stringWithFormat:DESC(@"interfaces-for-ship-@-and-station-@"), [self displayName], [dockedStation displayName]];
[gui setColor:[OOColor yellowColor] forRow:GUI_ROW_INTERFACES_HEADING];
[gui setText:desc forRow:GUI_ROW_INTERFACES_HEADING];
if (guiChanged)
{
[gui setForegroundTextureKey:@"docked_overlay"];
NSDictionary *background = [UNIVERSE screenTextureDescriptorForKey:@"interfaces"];
[self setEquipScreenBackgroundDescriptor:background];
[gui setBackgroundTextureDescriptor:background];
}
}
/* ends */
[self setShowDemoShips:NO];
gui_screen = GUI_SCREEN_INTERFACES;
[self setShowDemoShips:NO];
[UNIVERSE enterGUIViewModeWithMouseInteraction:YES];
}
- (void) showInformationForSelectedInterface
{
GuiDisplayGen* gui = [UNIVERSE gui];
NSString* interfaceKey = [gui selectedRowKey];
int i;
for (i = GUI_ROW_EQUIPMENT_DETAIL; i < GUI_MAX_ROWS; i++)
{
[gui setText:@"" forRow:i];
[gui setColor:[OOColor greenColor] forRow:i];
}
if (interfaceKey && ![interfaceKey hasPrefix:@"More:"])
{
NSDictionary *interfaces = [dockedStation localInterfaces];
OOJSInterfaceDefinition *definition = [interfaces objectForKey:interfaceKey];
if (definition)
{
[gui addLongText:[definition summary] startingAtRow:GUI_ROW_INTERFACES_DETAIL align:GUI_ALIGN_LEFT];
}
}
}
- (void) activateSelectedInterface
{
GuiDisplayGen* gui = [UNIVERSE gui];
NSString* key = [gui selectedRowKey];
if ([key hasPrefix:@"More:"])
{
int from_item = [[key componentsSeparatedByString:@":"] oo_intAtIndex:1];
[self setGuiToInterfacesScreen:from_item];
if ([gui selectedRow] < 0)
[gui setSelectedRow:GUI_ROW_INTERFACES_START];
if (from_item == 0)
[gui setSelectedRow:GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES - 1];
[self showInformationForSelectedInterface];
return;
}
NSDictionary *interfaces = [dockedStation localInterfaces];
OOJSInterfaceDefinition *definition = [interfaces objectForKey:key];
if (definition)
{
[definition runCallback:key];
}
else
{
OOLog(@"script.javaScript.error",@"Unable to find callback definition for key %@",key);
}
}
- (void) setGuiToIntroFirstGo:(BOOL)justCobra
{
NSString *text = nil;
@ -8103,6 +8325,12 @@ static NSString *last_outfitting_key=nil;
}
- (NSUInteger) parcelCount
{
return [parcels count];
}
- (NSUInteger) passengerCount
{
return [passengers count];

View File

@ -71,6 +71,10 @@ MA 02110-1301, USA.
- (void) increasePassengerReputation;
- (void) decreasePassengerReputation;
- (int) parcelReputation;
- (void) increaseParcelReputation;
- (void) decreaseParcelReputation;
- (int) contractReputation;
- (void) increaseContractReputation;
- (void) decreaseContractReputation;
@ -85,10 +89,13 @@ MA 02110-1301, USA.
- (BOOL) addPassenger:(NSString*)Name start:(unsigned)start destination:(unsigned)destination eta:(double)eta fee:(double)fee; // for js scripting
- (BOOL) removePassenger:(NSString*)Name; // for js scripting
- (BOOL) addParcel:(NSString*)Name start:(unsigned)start destination:(unsigned)destination eta:(double)eta fee:(double)fee; // for js scripting
- (BOOL) removeParcel:(NSString*)Name; // for js scripting
- (BOOL) awardContract:(unsigned)qty commodity:(NSString*)commodity start:(unsigned)start destination:(unsigned)destination eta:(double)eta fee:(double)fee; // for js scripting.
- (BOOL) removeContract:(NSString*)commodity destination:(unsigned)destination; // for js scripting
- (NSArray *) passengerList;
- (NSArray *) parcelList;
- (NSArray *) contractList;
- (void) setGuiToManifestScreen;
- (void) setManifestScreenRow:(id)object inColor:(OOColor*)color forRow:(OOGUIRow)row ofRows:(OOGUIRow)max_rows andOffset:(OOGUIRow)offset inMultipage:(BOOL)multi;

View File

@ -52,7 +52,7 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
@interface PlayerEntity (ContractsPrivate)
- (OOCreditsQuantity) tradeInValue;
- (NSArray*) contractsListFromArray:(NSArray *) contracts_array forCargo:(BOOL) forCargo;
- (NSArray*) contractsListFromArray:(NSArray *) contracts_array forCargo:(BOOL) forCargo forParcels:(BOOL)forParcels;
@end
@ -225,6 +225,63 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
}
}
}
// check parcel contracts
for (i = 0; i < [parcels count]; i++)
{
NSDictionary* parcel_info = [parcels oo_dictionaryAtIndex:i];
NSString* parcel_name = [parcel_info oo_stringForKey:PASSENGER_KEY_NAME];
int dest = [parcel_info oo_intForKey:CONTRACT_KEY_DESTINATION];
Random_Seed dest_seed = [UNIVERSE systemSeedForSystemNumber:dest];
int dest_eta = [parcel_info oo_doubleForKey:CONTRACT_KEY_ARRIVAL_TIME] - ship_clock;
if (equal_seeds( system_seed, dest_seed))
{
// we've arrived in system!
if (dest_eta > 0)
{
// and in good time
long long fee = [parcel_info oo_longLongForKey:CONTRACT_KEY_FEE];
while ((randf() < 0.75)&&(dest_eta > 86400)) // delivered with more than a day to spare and a decent customer?
{
// lower tips than passengers
fee *= 110; // tip + 10%
fee /= 100;
dest_eta *= 0.5;
}
credits += 10 * fee;
[result appendFormatLine:DESC(@"parcel-delivered-okay-@-@"), parcel_name, OOIntCredits(fee)];
[parcels removeObjectAtIndex:i--];
[self increaseParcelReputation];
}
else
{
// but we're late!
long long fee = [parcel_info oo_longLongForKey:CONTRACT_KEY_FEE] / 2; // halve fare
while (randf() < 0.5) // maybe halve fare a few times!
fee /= 2;
credits += 10 * fee;
[result appendFormatLine:DESC(@"parcel-delivered-late-@-@"), parcel_name, OOIntCredits(fee)];
[parcels removeObjectAtIndex:i--];
}
}
else
{
if (dest_eta < 0)
{
// we've run out of time!
[result appendFormatLine:DESC(@"parcel-failed-@"), parcel_name];
[parcels removeObjectAtIndex:i--];
[self decreaseParcelReputation];
}
}
}
// check cargo contracts
for (i = 0; i < [contracts count]; i++)
@ -358,6 +415,18 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
[contract_record removeObjectForKey:[ids objectAtIndex:i]];
}
}
// check parcel_record for expired deliveries
ids = [parcel_record allKeys];
for (i = 0; i < [ids count]; i++)
{
double dest_eta = [(NSNumber*)[parcel_record objectForKey:[ids objectAtIndex:i]] doubleValue] - ship_clock;
if (dest_eta < 0)
{
[parcel_record removeObjectForKey:[ids objectAtIndex:i]];
}
}
if ([result length] == 0)
{
@ -460,6 +529,75 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
}
- (int) parcelReputation
{
int good = [reputation oo_intForKey:PARCEL_GOOD_KEY];
int bad = [reputation oo_intForKey:PARCEL_BAD_KEY];
int unknown = [reputation oo_intForKey:PARCEL_UNKNOWN_KEY];
if (unknown > 0)
unknown = 7 - (market_rnd % unknown);
else
unknown = 7;
return (good + unknown - 2 * bad) / 2; // return a number from -7 to +7
}
- (void) increaseParcelReputation
{
int good = [reputation oo_intForKey:PARCEL_GOOD_KEY];
int bad = [reputation oo_intForKey:PARCEL_BAD_KEY];
int unknown = [reputation oo_intForKey:PARCEL_UNKNOWN_KEY];
if (bad > 0)
{
// shift a bean from bad to unknown
bad--;
if (unknown < 7)
unknown++;
}
else
{
// shift a bean from unknown to good
if (unknown > 0)
unknown--;
if (good < 7)
good++;
}
[reputation oo_setInteger:good forKey:PARCEL_GOOD_KEY];
[reputation oo_setInteger:bad forKey:PARCEL_BAD_KEY];
[reputation oo_setInteger:unknown forKey:PARCEL_UNKNOWN_KEY];
}
- (void) decreaseParcelReputation
{
int good = [reputation oo_intForKey:PARCEL_GOOD_KEY];
int bad = [reputation oo_intForKey:PARCEL_BAD_KEY];
int unknown = [reputation oo_intForKey:PARCEL_UNKNOWN_KEY];
if (good > 0)
{
// shift a bean from good to bad
good--;
if (bad < 7)
bad++;
}
else
{
// shift a bean from unknown to bad
if (unknown > 0)
unknown--;
if (bad < 7)
bad++;
}
[reputation oo_setInteger:good forKey:PARCEL_GOOD_KEY];
[reputation oo_setInteger:bad forKey:PARCEL_BAD_KEY];
[reputation oo_setInteger:unknown forKey:PARCEL_UNKNOWN_KEY];
}
- (int) contractReputation
{
int good = [reputation oo_intForKey:CONTRACTS_GOOD_KEY];
@ -537,6 +675,9 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
int p_good = [reputation oo_intForKey:PASSAGE_GOOD_KEY];
int p_bad = [reputation oo_intForKey:PASSAGE_BAD_KEY];
int p_unknown = [reputation oo_intForKey:PASSAGE_UNKNOWN_KEY];
int pl_good = [reputation oo_intForKey:PARCEL_GOOD_KEY];
int pl_bad = [reputation oo_intForKey:PARCEL_BAD_KEY];
int pl_unknown = [reputation oo_intForKey:PARCEL_UNKNOWN_KEY];
if (c_unknown < 7)
{
@ -561,6 +702,18 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
}
p_unknown++;
}
if (pl_unknown < 7)
{
if (pl_bad > 0)
pl_bad--;
else
{
if (pl_good > 0)
pl_good--;
}
pl_unknown++;
}
[reputation setObject:[NSNumber numberWithInt:c_good] forKey:CONTRACTS_GOOD_KEY];
[reputation setObject:[NSNumber numberWithInt:c_bad] forKey:CONTRACTS_BAD_KEY];
@ -568,6 +721,9 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
[reputation setObject:[NSNumber numberWithInt:p_good] forKey:PASSAGE_GOOD_KEY];
[reputation setObject:[NSNumber numberWithInt:p_bad] forKey:PASSAGE_BAD_KEY];
[reputation setObject:[NSNumber numberWithInt:p_unknown] forKey:PASSAGE_UNKNOWN_KEY];
[reputation setObject:[NSNumber numberWithInt:pl_good] forKey:PARCEL_GOOD_KEY];
[reputation setObject:[NSNumber numberWithInt:pl_bad] forKey:PARCEL_BAD_KEY];
[reputation setObject:[NSNumber numberWithInt:pl_unknown] forKey:PARCEL_UNKNOWN_KEY];
}
@ -867,6 +1023,50 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
}
- (BOOL) addParcel:(NSString*)Name start:(unsigned)start destination:(unsigned)Destination eta:(double)eta fee:(double)fee
{
NSDictionary* parcel_info = [NSDictionary dictionaryWithObjectsAndKeys:
Name, PASSENGER_KEY_NAME,
[NSNumber numberWithInt:start], CONTRACT_KEY_START,
[NSNumber numberWithInt:Destination], CONTRACT_KEY_DESTINATION,
[NSNumber numberWithDouble:[PLAYER clockTime]], CONTRACT_KEY_DEPARTURE_TIME,
[NSNumber numberWithDouble:eta], CONTRACT_KEY_ARRIVAL_TIME,
[NSNumber numberWithDouble:fee], CONTRACT_KEY_FEE,
[NSNumber numberWithInt:0], CONTRACT_KEY_PREMIUM,
NULL];
// extra checks, just in case.
if ([parcel_record objectForKey:Name] != nil) return NO;
[parcels addObject:parcel_info];
[parcel_record setObject:[NSNumber numberWithDouble:eta] forKey:Name];
return YES;
}
- (BOOL) removeParcel:(NSString*)Name // removes the first parcel that answers to Name, returns NO if none found
{
// extra check, just in case.
if ([parcels count] == 0) return NO;
unsigned i;
for (i = 0; i < [parcels count]; i++)
{
NSString *this_name = [[parcels oo_dictionaryAtIndex:i] oo_stringForKey:PASSENGER_KEY_NAME];
if ([Name isEqualToString:this_name])
{
[parcels removeObjectAtIndex:i];
[parcel_record removeObjectForKey:Name];
return YES;
}
}
return NO;
}
- (BOOL) awardContract:(unsigned)qty commodity:(NSString*)commodity start:(unsigned)start
destination:(unsigned)Destination eta:(double)eta fee:(double)fee
{
@ -1069,21 +1269,27 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
- (NSArray*) passengerList
{
return [self contractsListFromArray:passengers forCargo:NO];
return [self contractsListFromArray:passengers forCargo:NO forParcels:NO];
}
- (NSArray*) parcelList
{
return [self contractsListFromArray:parcels forCargo:NO forParcels:YES];
}
- (NSArray*) contractList
{
return [self contractsListFromArray:contracts forCargo:YES];
return [self contractsListFromArray:contracts forCargo:YES forParcels:NO];
}
- (NSArray*) contractsListFromArray:(NSArray *) contracts_array forCargo:(BOOL) forCargo
- (NSArray*) contractsListFromArray:(NSArray *) contracts_array forCargo:(BOOL) forCargo forParcels:(BOOL)forParcels;
{
// check contracts
NSMutableArray *result = [NSMutableArray arrayWithCapacity:5];
NSString *formatString = forCargo ? DESC(@"manifest-deliver-@-to-@within-@")
NSString *formatString = (forCargo||forParcels) ? DESC(@"manifest-deliver-@-to-@within-@")
: DESC(@"manifest-@-travelling-to-@-to-arrive-within-@");
unsigned i;
for (i = 0; i < [contracts_array count]; i++)
@ -1118,6 +1324,7 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
NSArray* missionsManifest = [self missionsList];
NSArray* passengerManifest = [self passengerList];
NSArray* contractManifest = [self contractList];
NSArray* parcelManifest = [self parcelList];
NSUInteger i = 0;
NSUInteger max_rows = 20;
@ -1126,6 +1333,7 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
OOGUIRow cargoRow = 2;
OOGUIRow passengersRow = 2;
OOGUIRow contractsRow = 2;
OOGUIRow parcelsRow = 2;
OOGUIRow missionsRow = 2;
// show extra lines if no HUD is displayed.
@ -1200,7 +1408,28 @@ static NSString * const kOOLogNoteShowShipyardModel = @"script.debug.note.showSh
manifestCount = 1;
}
contractsRow = passengersRow + manifestCount + 1;
parcelsRow = passengersRow + manifestCount + 1;
// Parcels Manifest
manifestCount = [parcelManifest count];
SET_MANIFEST_ROW( (DESC(@"manifest-parcels")) , yellowColor, parcelsRow - 1);
if (manifestCount > 0)
{
for (i = 0; i < manifestCount; i++)
{
SET_MANIFEST_ROW( ((NSString*)[parcelManifest objectAtIndex:i]) , greenColor, parcelsRow + i);
}
}
else
{
SET_MANIFEST_ROW( (DESC(@"manifest-none")), greenColor, parcelsRow);
manifestCount = 1;
}
contractsRow = parcelsRow + manifestCount + 1;
// Contracts Manifest
manifestCount = [contractManifest count];
@ -1925,6 +2154,7 @@ static NSMutableDictionary *currentShipyard = nil;
[passengers removeAllObjects];
[passenger_record removeAllObjects];
// parcels stay the same; easy to transfer between ships
// contracts stay the same, so if you default - tough!
// okay we need to switch the model used, lots of the stats, and add all the extras

View File

@ -1985,6 +1985,57 @@ static NSTimeInterval time_last_frame;
}
break;
case GUI_SCREEN_INTERFACES:
if ([self handleGUIUpDownArrowKeys])
{
[self showInformationForSelectedInterface];
}
if ([gameView isDown:gvArrowKeyLeft])
{
if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
{
if ([[gui keyForRow:GUI_ROW_INTERFACES_START] hasPrefix:@"More:"])
{
[self playMenuPagePrevious];
[gui setSelectedRow:GUI_ROW_INTERFACES_START];
[self activateSelectedInterface];
}
timeLastKeyPress = script_time;
}
}
if ([gameView isDown:gvArrowKeyRight])
{
if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
{
if ([[gui keyForRow:GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES - 1] hasPrefix:@"More:"])
{
[self playMenuPageNext];
[gui setSelectedRow:GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES - 1];
[self activateSelectedInterface];
}
timeLastKeyPress = script_time;
}
}
leftRightKeyPressed = [gameView isDown:gvArrowKeyRight]|[gameView isDown:gvArrowKeyLeft];
if ([gameView isDown:13] || [gameView isDown:gvMouseDoubleClick]) // 'enter'
{
if ([gameView isDown:gvMouseDoubleClick])
{
selectPressed = NO;
[gameView clearMouse];
}
if ((!selectPressed)&&([gui selectedRow] > -1))
{
[self activateSelectedInterface];
selectPressed = YES;
}
}
else
{
selectPressed = NO;
}
break;
case GUI_SCREEN_MARKET:
if ([self status] == STATUS_DOCKED)
{
@ -3129,6 +3180,12 @@ static NSTimeInterval time_last_frame;
switching_equipship_screens = NO;
}
if ((([gameView isDown:gvFunctionKey4])||(fKeyAlias && [gameView isDown:gvNumberKey4])) && ![UNIVERSE strict])
{
[self setGuiToInterfacesScreen:0];
[gui setSelectedRow:GUI_ROW_INTERFACES_START];
}
if (([gameView isDown:gvFunctionKey8])||(fKeyAlias && [gameView isDown:gvNumberKey8]))
{
if (!switching_market_screens)

View File

@ -1966,6 +1966,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
{
choiceValue = [choicesDict objectForKey:choiceKey];
OOGUIAlignment alignment = GUI_ALIGN_CENTER;
OOColor *rowColor = [OOColor yellowColor];
if ([choiceValue isKindOfClass:[NSString class]])
{
choiceText = [NSString stringWithFormat:@" %@ ",(NSString*)choiceValue];
@ -1983,6 +1984,11 @@ static int scriptRandomSeed = -1; // ensure proper random function
{
alignment = GUI_ALIGN_RIGHT;
}
id colorDesc = [choiceOpts objectForKey:@"color"];
if (colorDesc != nil)
{
rowColor = [OOColor colorWithDescription:colorDesc];
}
}
else
{
@ -1995,7 +2001,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
{
[gui setText:choiceText forRow:choicesRow align: alignment];
[gui setKey:choiceKey forRow:choicesRow];
[gui setColor:[OOColor yellowColor] forRow:choicesRow];
[gui setColor:rowColor forRow:choicesRow];
if (!selectableRowExists)
{
selectableRowExists = YES;
@ -2004,7 +2010,7 @@ static int scriptRandomSeed = -1; // ensure proper random function
}
else
{
[gui setText:@"" forRow:choicesRow align: alignment];
// [gui setText:@"" forRow:choicesRow align: alignment];
[gui setKey:GUI_KEY_SKIP forRow:choicesRow];
}
choicesRow++;

View File

@ -56,6 +56,7 @@ MA 02110-1301, USA.
- (double) systemPseudoRandomFloat;
- (NSDictionary *) passengerContractMarker:(OOSystemID)system;
- (NSDictionary *) parcelContractMarker:(OOSystemID)system;
- (NSDictionary *) cargoContractMarker:(OOSystemID)system;
- (NSDictionary *) defaultMarker:(OOSystemID)system;
- (NSDictionary *) validatedMarker:(NSDictionary *)marker;

View File

@ -261,6 +261,7 @@ MA 02110-1301, USA.
}
- (NSDictionary *) passengerContractMarker:(OOSystemID)system
{
return [[[NSDictionary dictionaryWithObjectsAndKeys:
@ -271,6 +272,18 @@ MA 02110-1301, USA.
nil] retain] autorelease];
}
- (NSDictionary *) parcelContractMarker:(OOSystemID)system
{
return [[[NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:system], @"system",
MISSION_DEST_LEGACY, @"name",
@"orangeColor", @"markerColor",
@"MARKER_PLUS", @"markerShape",
nil] retain] autorelease];
}
- (NSDictionary *) cargoContractMarker:(OOSystemID)system
{
return [[[NSDictionary dictionaryWithObjectsAndKeys:
@ -281,6 +294,7 @@ MA 02110-1301, USA.
nil] retain] autorelease];
}
- (NSDictionary *) defaultMarker:(OOSystemID)system
{
return [[[NSDictionary dictionaryWithObjectsAndKeys:
@ -291,6 +305,7 @@ MA 02110-1301, USA.
nil] retain] autorelease];
}
- (NSDictionary *) validatedMarker:(NSDictionary *)marker
{
OOSystemID dest = [marker oo_intForKey:@"system"];

View File

@ -560,7 +560,8 @@ typedef enum
- (BOOL) hasPrimaryWeapon:(OOWeaponType)weaponType;
- (BOOL) removeExternalStore:(OOEquipmentType *)eqType;
// Passengers - not supported for NPCs, but interface is here for genericity.
// Passengers and parcels - not supported for NPCs, but interface is here for genericity.
- (NSUInteger) parcelCount;
- (NSUInteger) passengerCount;
- (NSUInteger) passengerCapacity;
@ -778,6 +779,7 @@ typedef enum
- (BOOL) showScoopMessage;
- (NSArray *) passengerListForScripting;
- (NSArray *) parcelListForScripting;
- (NSArray *) contractListForScripting;
- (NSArray *) equipmentListForScripting;
- (OOEquipmentType *) weaponTypeForFacing:(OOWeaponFacing)facing;

View File

@ -2685,6 +2685,12 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
- (NSArray *) parcelListForScripting
{
return [NSArray array];
}
- (NSArray *) contractListForScripting
{
return [NSArray array];
@ -3230,6 +3236,12 @@ ShipEntity* doOctreesCollide(ShipEntity* prime, ShipEntity* other)
}
- (NSUInteger) parcelCount
{
return 0;
}
- (NSUInteger) passengerCount
{
return 0;

View File

@ -25,6 +25,7 @@ MA 02110-1301, USA.
*/
#import "ShipEntity.h"
#import "OOJSInterfaceDefinition.h"
#import "Universe.h"
@class OOWeakSet;
@ -81,6 +82,8 @@ typedef enum
NSMutableArray *localContracts;
NSMutableArray *localShipyard;
NSMutableDictionary *localInterfaces;
unsigned docked_shuttles;
double last_shuttle_launch_time;
double shuttle_launch_interval;
@ -108,6 +111,8 @@ typedef enum
- (void) setLocalContracts:(NSArray *)market;
- (NSMutableArray *) localShipyard;
- (void) setLocalShipyard:(NSArray *)market;
- (NSMutableDictionary *) localInterfaces;
- (void) setInterfaceDefinition:(OOJSInterfaceDefinition *)definition forKey:(NSString *)key;
- (NSMutableArray *) initialiseLocalMarketWithRandomFactor:(int)random_factor;
- (NSMutableArray *) initialiseMarketWithSeed:(Random_Seed)seed andRandomFactor:(int)random_factor;

View File

@ -170,6 +170,25 @@ MA 02110-1301, USA.
}
- (NSMutableDictionary *) localInterfaces
{
return localInterfaces;
}
- (void) setInterfaceDefinition:(OOJSInterfaceDefinition *)definition forKey:(NSString *)key
{
if (definition == nil)
{
[localInterfaces removeObjectForKey:key];
}
else
{
[localInterfaces setObject:definition forKey:key];
}
}
- (NSMutableArray *) initialiseLocalMarketWithRandomFactor:(int) random_factor
{
return [self initialiseMarketWithSeed:[PLAYER system_seed] andRandomFactor:random_factor];
@ -522,6 +541,7 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
}
hasBreakPattern = YES;
localInterfaces = [[NSMutableDictionary alloc] init];
return self;
@ -536,7 +556,8 @@ NSDictionary *OOMakeDockingInstructions(StationEntity *station, Vector coords, f
DESTROY(localPassengers);
DESTROY(localContracts);
DESTROY(localShipyard);
DESTROY(localInterfaces);
[super dealloc];
}

View File

@ -1678,6 +1678,7 @@ static OOTextureSprite *NewTextureSpriteWithDescriptor(NSDictionary *descriptor)
}
else if ([shape isEqualToString:@"MARKER_PLUS"])
{
mark_size *= 1.4; // match volumes
glVertex3f(x, y - mark_size, z);
glVertex3f(x, y + mark_size, z);
glVertex3f(x - mark_size, y, z);
@ -1696,6 +1697,7 @@ static OOTextureSprite *NewTextureSpriteWithDescriptor(NSDictionary *descriptor)
}
else if ([shape isEqualToString:@"MARKER_DIAMOND"])
{
mark_size *= 1.4; // match volumes
glVertex3f(x, y - mark_size, z);
glVertex3f(x - mark_size, y, z);
glVertex3f(x - mark_size, y, z);

View File

@ -0,0 +1,57 @@
/*
OOJSInterfaceDefinition.h
Oolite
Copyright (C) 2004-2012 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#import "OOJSScript.h"
#include <jsapi.h>
@interface OOJSInterfaceDefinition: OOWeakRefObject
{
@private
jsval _callback;
JSObject *_callbackThis;
OOJSScript *_owningScript;
NSString *_title;
NSString *_summary;
NSString *_category;
}
- (NSString *)title;
- (void)setTitle:(NSString *)title;
- (NSString *)category;
- (void)setCategory:(NSString *)category;
- (NSString *)summary;
- (void)setSummary:(NSString *)summary;
- (jsval)callback;
- (void)setCallback:(jsval)callback;
- (JSObject *)callbackThis;
- (void)setCallbackThis:(JSObject *)callbackthis;
- (void)runCallback:(NSString *)key;
- (NSComparisonResult)interfaceCompare:(OOJSInterfaceDefinition *)other;
@end

View File

@ -0,0 +1,178 @@
/*
OOJSInterfaceDefinition.m
Oolite
Copyright (C) 2004-2012 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#import "OOJSInterfaceDefinition.h"
#import "OOJavaScriptEngine.h"
@implementation OOJSInterfaceDefinition
- (id) init {
_callback = JSVAL_VOID;
_callbackThis = NULL;
_owningScript = [[OOJSScript currentlyRunningScript] weakRetain];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(deleteJSPointers)
name:kOOJavaScriptEngineWillResetNotification
object:[OOJavaScriptEngine sharedEngine]];
return self;
}
- (void) deleteJSPointers
{
JSContext *context = OOJSAcquireContext();
_callback = JSVAL_VOID;
_callbackThis = NULL;
JS_RemoveValueRoot(context, &_callback);
JS_RemoveObjectRoot(context, &_callbackThis);
OOJSRelinquishContext(context);
[[NSNotificationCenter defaultCenter] removeObserver:self
name:kOOJavaScriptEngineWillResetNotification
object:[OOJavaScriptEngine sharedEngine]];
}
- (void) dealloc
{
[_owningScript release];
[self deleteJSPointers];
[super dealloc];
}
- (NSString *)title
{
return _title;
}
- (void)setTitle:(NSString *)title
{
[_title autorelease];
_title = [title retain];
}
- (NSString *)category
{
return _category;
}
- (void)setCategory:(NSString *)category
{
[_category autorelease];
_category = [category retain];
}
- (NSString *)summary
{
return _summary;
}
- (void)setSummary:(NSString *)summary
{
[_summary autorelease];
_summary = [summary retain];
}
- (jsval)callback
{
return _callback;
}
- (void)setCallback:(jsval)callback
{
JSContext *context = OOJSAcquireContext();
JS_RemoveValueRoot(context, &_callback);
_callback = callback;
OOJSAddGCValueRoot(context, &_callback, "OOJSInterfaceDefinition callback function");
OOJSRelinquishContext(context);
}
- (JSObject *)callbackThis
{
return _callbackThis;
}
- (void)setCallbackThis:(JSObject *)callbackThis
{
JSContext *context = OOJSAcquireContext();
JS_RemoveObjectRoot(context, &_callbackThis);
_callbackThis = callbackThis;
OOJSAddGCObjectRoot(context, &_callbackThis, "OOJSInterfaceDefinition callback this");
OOJSRelinquishContext(context);
}
- (void)runCallback:(NSString *)key
{
OOJavaScriptEngine *engine = [OOJavaScriptEngine sharedEngine];
JSContext *context = OOJSAcquireContext();
jsval rval = JSVAL_VOID;
jsval cKey = OOJSValueFromNativeObject(context, key);
[OOJSScript pushScript:_owningScript];
[engine callJSFunction:_callback
forObject:_callbackThis
argc:1
argv:&cKey
result:&rval];
[OOJSScript popScript:_owningScript];
OOJSRelinquishContext(context);
}
- (NSComparisonResult)interfaceCompare:(OOJSInterfaceDefinition *)other
{
NSComparisonResult byCategory = [_category caseInsensitiveCompare:[other category]];
if (byCategory == NSOrderedSame)
{
return [_title caseInsensitiveCompare:[other title]];
}
else
{
return byCategory;
}
}
@end

View File

@ -53,6 +53,8 @@ static JSBool PlayerIncreaseContractReputation(JSContext *context, uintN argc, j
static JSBool PlayerDecreaseContractReputation(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerIncreasePassengerReputation(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerDecreasePassengerReputation(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerIncreaseParcelReputation(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerDecreaseParcelReputation(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerAddMessageToArrivalReport(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerReplaceShip(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerSetEscapePodDestination(JSContext *context, uintN argc, jsval *vp);
@ -90,6 +92,7 @@ enum
kPlayer_dockingClearanceStatus, // docking clearance status, string, read only
kPlayer_legalStatus, // legalStatus, string, read-only
kPlayer_name, // Player name, string, read-only
kPlayer_parcelReputation, // reputation for parcel contracts, integer, read-only
kPlayer_passengerReputation, // reputation for passenger contracts, integer, read-only
kPlayer_rank, // rank, string, read-only
kPlayer_score, // kill count, integer, read/write
@ -112,6 +115,7 @@ static JSPropertySpec sPlayerProperties[] =
{ "dockingClearanceStatus", kPlayer_dockingClearanceStatus, OOJS_PROP_READONLY_CB },
{ "legalStatus", kPlayer_legalStatus, OOJS_PROP_READONLY_CB },
{ "name", kPlayer_name, OOJS_PROP_READONLY_CB },
{ "parcelReputation", kPlayer_parcelReputation, OOJS_PROP_READONLY_CB },
{ "passengerReputation", kPlayer_passengerReputation, OOJS_PROP_READONLY_CB },
{ "rank", kPlayer_rank, OOJS_PROP_READONLY_CB },
{ "score", kPlayer_score, OOJS_PROP_READWRITE_CB },
@ -127,8 +131,10 @@ static JSFunctionSpec sPlayerMethods[] =
{ "commsMessage", PlayerCommsMessage, 1 },
{ "consoleMessage", PlayerConsoleMessage, 1 },
{ "decreaseContractReputation", PlayerDecreaseContractReputation, 0 },
{ "decreaseParcelReputation", PlayerDecreaseParcelReputation, 0 },
{ "decreasePassengerReputation", PlayerDecreasePassengerReputation, 0 },
{ "increaseContractReputation", PlayerIncreaseContractReputation, 0 },
{ "increaseParcelReputation", PlayerIncreaseParcelReputation, 0 },
{ "increasePassengerReputation", PlayerIncreasePassengerReputation, 0 },
{ "replaceShip", PlayerReplaceShip, 1 },
{ "setEscapePodDestination", PlayerSetEscapePodDestination, 1 }, // null destination must be set explicitly
@ -237,6 +243,10 @@ static JSBool PlayerGetProperty(JSContext *context, JSObject *this, jsid propID,
case kPlayer_passengerReputation:
*value = INT_TO_JSVAL([player passengerReputation]);
return YES;
case kPlayer_parcelReputation:
*value = INT_TO_JSVAL([player parcelReputation]);
return YES;
case kPlayer_dockingClearanceStatus:
// EMMSTRAN: OOConstToJSString-ify this.
@ -383,6 +393,30 @@ static JSBool PlayerDecreaseContractReputation(JSContext *context, uintN argc, j
}
// increaseParcelReputation()
static JSBool PlayerIncreaseParcelReputation(JSContext *context, uintN argc, jsval *vp)
{
OOJS_NATIVE_ENTER(context)
[OOPlayerForScripting() increaseParcelReputation];
OOJS_RETURN_VOID;
OOJS_NATIVE_EXIT
}
// decreaseParcelReputation()
static JSBool PlayerDecreaseParcelReputation(JSContext *context, uintN argc, jsval *vp)
{
OOJS_NATIVE_ENTER(context)
[OOPlayerForScripting() decreaseParcelReputation];
OOJS_RETURN_VOID;
OOJS_NATIVE_EXIT
}
// increasePassengerReputation()
static JSBool PlayerIncreasePassengerReputation(JSContext *context, uintN argc, jsval *vp)
{

View File

@ -61,6 +61,8 @@ static JSBool PlayerShipDisengageAutopilot(JSContext *context, uintN argc, jsval
static JSBool PlayerShipAwardEquipmentToCurrentPylon(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipAddPassenger(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipRemovePassenger(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipAddParcel(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipRemoveParcel(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipAwardContract(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipRemoveContract(JSContext *context, uintN argc, jsval *vp);
static JSBool PlayerShipSetCustomView(JSContext *context, uintN argc, jsval *vp);
@ -68,7 +70,7 @@ static JSBool PlayerShipResetCustomView(JSContext *context, uintN argc, jsval *v
static JSBool PlayerShipTakeInternalDamage(JSContext *context, uintN argc, jsval *vp);
static BOOL ValidateContracts(JSContext *context, uintN argc, jsval *vp, BOOL isCargo, OOSystemID *start, OOSystemID *destination, double *eta, double *fee);
static BOOL ValidateContracts(JSContext *context, uintN argc, jsval *vp, BOOL isCargo, OOSystemID *start, OOSystemID *destination, double *eta, double *fee, NSString *functionName);
static JSClass sPlayerShipClass =
@ -171,6 +173,7 @@ static JSPropertySpec sPlayerShipProperties[] =
static JSFunctionSpec sPlayerShipMethods[] =
{
// JS name Function min args
{ "addParcel", PlayerShipAddParcel, 0 },
{ "addPassenger", PlayerShipAddPassenger, 0 },
{ "awardContract", PlayerShipAwardContract, 0 },
{ "awardEquipmentToCurrentPylon", PlayerShipAwardEquipmentToCurrentPylon, 1 },
@ -179,6 +182,7 @@ static JSFunctionSpec sPlayerShipMethods[] =
{ "launch", PlayerShipLaunch, 0 },
{ "removeAllCargo", PlayerShipRemoveAllCargo, 0 },
{ "removeContract", PlayerShipRemoveContract, 2 },
{ "removeParcel", PlayerShipRemoveParcel, 1 },
{ "removePassenger", PlayerShipRemovePassenger, 1 },
{ "resetCustomView", PlayerShipResetCustomView, 0 },
{ "setCustomView", PlayerShipSetCustomView, 2 },
@ -733,7 +737,7 @@ static JSBool PlayerShipAddPassenger(JSContext *context, uintN argc, jsval *vp)
return NO;
}
if (!ValidateContracts(context, argc, vp, NO, &start, &destination, &eta, &fee)) return NO; // always go through validate contracts (passenger)
if (!ValidateContracts(context, argc, vp, NO, &start, &destination, &eta, &fee, @"addPassenger")) return NO; // always go through validate contracts (passenger)
// Ensure there's space.
if ([player passengerCount] >= [player passengerCapacity]) OOJS_RETURN_BOOL(NO);
@ -770,6 +774,65 @@ static JSBool PlayerShipRemovePassenger(JSContext *context, uintN argc, jsval *v
}
// addParcel(description: string, start: int, destination: int, ETA: double, fee: double) : Boolean
static JSBool PlayerShipAddParcel(JSContext *context, uintN argc, jsval *vp)
{
OOJS_NATIVE_ENTER(context)
PlayerEntity *player = OOPlayerForScripting();
NSString *name = nil;
OOSystemID start = 0, destination = 0;
jsdouble eta = 0.0, fee = 0.0;
if (argc < 5)
{
OOJSReportBadArguments(context, @"PlayerShip", @"addParcel", argc, OOJS_ARGV, nil, @"name, start, destination, ETA, fee");
return NO;
}
name = OOStringFromJSValue(context, OOJS_ARGV[0]);
if (EXPECT_NOT(name == nil))
{
OOJSReportBadArguments(context, @"PlayerShip", @"addParcel", 1, &OOJS_ARGV[0], nil, @"string");
return NO;
}
if (!ValidateContracts(context, argc, vp, NO, &start, &destination, &eta, &fee, @"addParcel")) return NO; // always go through validate contracts (passenger/parcel mode)
// Ensure there's space.
BOOL OK = [player addParcel:name start:start destination:destination eta:eta fee:fee];
OOJS_RETURN_BOOL(OK);
OOJS_NATIVE_EXIT
}
// removeParcel(description :string)
static JSBool PlayerShipRemoveParcel(JSContext *context, uintN argc, jsval *vp)
{
OOJS_NATIVE_ENTER(context)
PlayerEntity *player = OOPlayerForScripting();
NSString *name = nil;
BOOL OK = YES;
if (argc > 0) name = OOStringFromJSValue(context, OOJS_ARGV[0]);
if (EXPECT_NOT(name == nil))
{
OOJSReportBadArguments(context, @"PlayerShip", @"removeParcel", MIN(argc, 1U), OOJS_ARGV, nil, @"string");
return NO;
}
OK = [player parcelCount] > 0 && [name length] > 0;
if (OK) OK = [player removeParcel:name];
OOJS_RETURN_BOOL(OK);
OOJS_NATIVE_EXIT
}
// awardContract(quantity: int, commodity: string, start: int, destination: int, eta: double, fee: double) : Boolean
static JSBool PlayerShipAwardContract(JSContext *context, uintN argc, jsval *vp)
{
@ -800,7 +863,7 @@ static JSBool PlayerShipAwardContract(JSContext *context, uintN argc, jsval *vp)
return NO;
}
if (!ValidateContracts(context, argc, vp, YES, &start, &destination, &eta, &fee)) return NO; // always go through validate contracts (cargo)
if (!ValidateContracts(context, argc, vp, YES, &start, &destination, &eta, &fee, @"awardContract")) return NO; // always go through validate contracts (cargo)
BOOL OK = [player awardContract:qty commodity:key start:start destination:destination eta:eta fee:fee];
OOJS_RETURN_BOOL(OK);
@ -940,14 +1003,13 @@ static JSBool PlayerShipTakeInternalDamage(JSContext *context, uintN argc, jsval
}
static BOOL ValidateContracts(JSContext *context, uintN argc, jsval *vp, BOOL isCargo, OOSystemID *start, OOSystemID *destination, double *eta, double *fee)
static BOOL ValidateContracts(JSContext *context, uintN argc, jsval *vp, BOOL isCargo, OOSystemID *start, OOSystemID *destination, double *eta, double *fee, NSString *functionName)
{
OOJS_PROFILE_ENTER
NSCParameterAssert(context != NULL && vp != NULL && start != NULL && destination != NULL && eta != NULL && fee != NULL);
unsigned offset = isCargo ? 2 : 1;
NSString *functionName = isCargo ? @"awardContract" : @"addPassenger";
jsdouble fValue;
int32 iValue;

View File

@ -185,6 +185,8 @@ enum
kShip_missileLoadTime, // missile load time, double, read/write
kShip_missiles, // the ship's missiles / external storage, array of equipmentTypes, read only
kShip_name, // name, string, read-only
kShip_parcelCount, // number of parcels on ship, integer, read-only
kShip_parcels, // parcel contracts, array - strings & whatnot, read only
kShip_passengerCapacity, // amount of passenger space on ship, integer, read-only
kShip_passengerCount, // number of passengers on ship, integer, read-only
kShip_passengers, // passengers contracts, array - strings & whatnot, read only
@ -301,6 +303,8 @@ static JSPropertySpec sShipProperties[] =
{ "missileLoadTime", kShip_missileLoadTime, OOJS_PROP_READWRITE_CB },
{ "missiles", kShip_missiles, OOJS_PROP_READONLY_CB },
{ "name", kShip_name, OOJS_PROP_READWRITE_CB },
{ "parcelCount", kShip_parcelCount, OOJS_PROP_READONLY_CB },
{ "parcels", kShip_parcels, OOJS_PROP_READONLY_CB },
{ "passengerCount", kShip_passengerCount, OOJS_PROP_READONLY_CB },
{ "passengerCapacity", kShip_passengerCapacity, OOJS_PROP_READONLY_CB },
{ "passengers", kShip_passengers, OOJS_PROP_READONLY_CB },
@ -721,6 +725,9 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsid propID, j
case kShip_passengerCount:
return JS_NewNumberValue(context, [entity passengerCount], value);
case kShip_parcelCount:
return JS_NewNumberValue(context, [entity parcelCount], value);
case kShip_passengerCapacity:
return JS_NewNumberValue(context, [entity passengerCapacity], value);
@ -780,6 +787,10 @@ static JSBool ShipGetProperty(JSContext *context, JSObject *this, jsid propID, j
case kShip_passengers:
result = [entity passengerListForScripting];
break;
case kShip_parcels:
result = [entity parcelListForScripting];
break;
case kShip_contracts:
result = [entity contractListForScripting];

View File

@ -26,6 +26,7 @@ MA 02110-1301, USA.
#import "OOJSShip.h"
#import "OOJSPlayer.h"
#import "OOJavaScriptEngine.h"
#import "OOJSInterfaceDefinition.h"
#import "StationEntity.h"
#import "GameController.h"
@ -48,7 +49,7 @@ static JSBool StationLaunchPirateShip(JSContext *context, uintN argc, jsval *vp)
static JSBool StationLaunchShuttle(JSContext *context, uintN argc, jsval *vp);
static JSBool StationLaunchPatrol(JSContext *context, uintN argc, jsval *vp);
static JSBool StationLaunchPolice(JSContext *context, uintN argc, jsval *vp);
static JSBool StationSetInterface(JSContext *context, uintN argc, jsval *vp);
static JSClass sStationClass =
{
@ -120,6 +121,7 @@ static JSFunctionSpec sStationMethods[] =
{ "launchScavenger", StationLaunchScavenger, 0 },
{ "launchShipWithRole", StationLaunchShipWithRole, 1 },
{ "launchShuttle", StationLaunchShuttle, 0 },
{ "setInterface", StationSetInterface, 0 },
{ 0 }
};
@ -477,3 +479,100 @@ static JSBool StationLaunchPolice(JSContext *context, uintN argc, jsval *vp)
OOJS_RETURN_OBJECT([station launchPolice]);
OOJS_NATIVE_EXIT
}
static JSBool StationSetInterface(JSContext *context, uintN argc, jsval *vp)
{
OOJS_NATIVE_ENTER(context)
StationEntity *station = nil;
if (!JSStationGetStationEntity(context, OOJS_THIS, &station)) OOJS_RETURN_VOID; // stale reference, no-op
if (argc < 1)
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]");
return NO;
}
NSString *key = OOStringFromJSValue(context, OOJS_ARGV[0]);
if (argc < 2 || JSVAL_IS_NULL(OOJS_ARGV[1]))
{
[station setInterfaceDefinition:nil forKey:key];
OOJS_RETURN_VOID;
}
jsval value = JSVAL_NULL;
jsval callback = JSVAL_NULL;
JSObject *callbackThis = NULL;
JSObject *params = NULL;
NSString *title = nil;
NSString *summary = nil;
NSString *category = nil;
if (!JS_ValueToObject(context, OOJS_ARGV[1], &params))
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]");
return NO;
}
// get and validate title
if (JS_GetProperty(context, params, "title", &value) == JS_FALSE || JSVAL_IS_VOID(value))
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'title' property.");
return NO;
}
title = OOStringFromJSValue(context, value);
// get category with default
if (JS_GetProperty(context, params, "category", &value) == JS_FALSE || JSVAL_IS_VOID(value))
{
category = [NSString stringWithString:DESC(@"interfaces-unspecified-category")];
}
else
{
category = OOStringFromJSValue(context, value);
}
// get and validate summary
if (JS_GetProperty(context, params, "summary", &value) == JS_FALSE || JSVAL_IS_VOID(value))
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'summary' property.");
return NO;
}
summary = OOStringFromJSValue(context, value);
// get and validate callback
if (JS_GetProperty(context, params, "callback", &callback) == JS_FALSE || JSVAL_IS_VOID(callback))
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; if definition is set, it must have a 'callback' property.");
return NO;
}
if (!OOJSValueIsFunction(context,callback))
{
OOJSReportBadArguments(context, @"Station", @"setInterface", MIN(argc, 1U), OOJS_ARGV, NULL, @"key [, definition]; 'callback' property must be a function.");
return NO;
}
OOJSInterfaceDefinition* definition = [[OOJSInterfaceDefinition alloc] init];
[definition setTitle:title];
[definition setCategory:category];
[definition setSummary:summary];
[definition setCallback:callback];
// get callback 'this'
if (JS_GetProperty(context, params, "cbThis", &value) == JS_TRUE && !JSVAL_IS_VOID(value))
{
JS_ValueToObject(context, value, &callbackThis);
[definition setCallbackThis:callbackThis];
// can do .bind(this) for callback instead
}
[station setInterfaceDefinition:definition forKey:key];
[definition release];
OOJS_RETURN_VOID;
OOJS_NATIVE_EXIT
}

View File

@ -18,3 +18,4 @@ ENTRY(GUI_SCREEN_SAVE_OVERWRITE, -1)
ENTRY(GUI_SCREEN_STICKMAPPER, -1)
ENTRY(GUI_SCREEN_MISSION, -1)
ENTRY(GUI_SCREEN_REPORT, -1)
ENTRY(GUI_SCREEN_INTERFACES, -1)