✨feature: Added ship details and mining fleet pages
This commit is contained in:
345
agent-info.php
345
agent-info.php
@@ -35,6 +35,16 @@ if (! is_string( $token ) || trim( $token ) === '') {
|
||||
$agent = array();
|
||||
$ships = array();
|
||||
$contracts = array();
|
||||
$system = array();
|
||||
$systemWaypoints = array();
|
||||
$paginatedWaypoints = array();
|
||||
$marketDetails = array();
|
||||
$shipyardDetails = array();
|
||||
$selectedShipSymbol = '';
|
||||
$selectedWaypointSymbol = '';
|
||||
$waypointPageSize = 25;
|
||||
$waypointPage = isset( $_GET['waypoint_page'] ) ? max( 1, (int) $_GET['waypoint_page'] ) : 1;
|
||||
$waypointTotalPages = 1;
|
||||
|
||||
if (! isset( $tokenError ) ) {
|
||||
$client = new SpacetradersApi(
|
||||
@@ -45,6 +55,35 @@ if (! isset( $tokenError ) ) {
|
||||
(int) $config['cache_ttl']
|
||||
);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['navigate_ship'] ) && isset( $_POST['ship_symbol'] ) && isset( $_POST['waypoint_symbol'] )) {
|
||||
$selectedShipSymbol = trim( (string) $_POST['ship_symbol'] );
|
||||
$selectedWaypointSymbol = trim( (string) $_POST['waypoint_symbol'] );
|
||||
|
||||
if ($selectedShipSymbol !== '' && $selectedWaypointSymbol !== '' ) {
|
||||
try {
|
||||
$selectedShipResponse = $client->getShip( $selectedShipSymbol );
|
||||
$selectedShipData = $selectedShipResponse['data'] ?? array();
|
||||
$shipNavStatus = (string) ( $selectedShipData['nav']['status'] ?? '' );
|
||||
|
||||
if ($shipNavStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException(
|
||||
'Selected ship is currently in transit and cannot navigate yet.'
|
||||
);
|
||||
}
|
||||
|
||||
if ($shipNavStatus === 'DOCKED' ) {
|
||||
$client->orbitShip( $selectedShipSymbol );
|
||||
}
|
||||
|
||||
$client->navigateShip( $selectedShipSymbol, $selectedWaypointSymbol );
|
||||
$storage->clearAllCache();
|
||||
$statusMessage = 'Navigation started for ' . $selectedShipSymbol . '.';
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$errorMessage = 'Unable to navigate ship: ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset( $_GET['accept_contract'] ) && is_string( $_GET['accept_contract'] ) && trim( $_GET['accept_contract'] ) !== '') {
|
||||
try {
|
||||
$client->acceptContract( trim( $_GET['accept_contract'] ) );
|
||||
@@ -65,6 +104,101 @@ try {
|
||||
$agent = $agentResponse['data'] ?? $agentResponse;
|
||||
$ships = $shipsResponse['data'] ?? $shipsResponse;
|
||||
$contracts = $contractsResponse['data'] ?? $contractsResponse;
|
||||
|
||||
$currentSystemSymbol = '';
|
||||
if (isset( $ships[0]['nav']['systemSymbol'] ) && is_string( $ships[0]['nav']['systemSymbol'] ) ) {
|
||||
$currentSystemSymbol = $ships[0]['nav']['systemSymbol'];
|
||||
}
|
||||
|
||||
if ($currentSystemSymbol === '' && isset( $agent['headquarters'] ) && is_string( $agent['headquarters'] ) ) {
|
||||
$hqParts = explode( '-', $agent['headquarters'] );
|
||||
if (count( $hqParts ) >= 2 ) {
|
||||
$currentSystemSymbol = $hqParts[0] . '-' . $hqParts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($currentSystemSymbol !== '' ) {
|
||||
$systemResponse = $client->getSystem( $currentSystemSymbol );
|
||||
$system = $systemResponse['data'] ?? $systemResponse;
|
||||
|
||||
$page = 1;
|
||||
$total = 0;
|
||||
do {
|
||||
$waypointsResponse = $client->listWaypoints(
|
||||
$currentSystemSymbol,
|
||||
array(
|
||||
'page' => $page,
|
||||
'limit' => 20,
|
||||
)
|
||||
);
|
||||
$pageData = $waypointsResponse['data'] ?? array();
|
||||
if (! is_array( $pageData ) || empty( $pageData ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$systemWaypoints = array_merge( $systemWaypoints, $pageData );
|
||||
$total = (int) ( $waypointsResponse['meta']['total'] ?? count( $systemWaypoints ) );
|
||||
$page++;
|
||||
} while (count( $systemWaypoints ) < $total);
|
||||
|
||||
foreach ( $systemWaypoints as $waypoint ) {
|
||||
$waypointSymbol = (string) ( $waypoint['symbol'] ?? '' );
|
||||
$traits = $waypoint['traits'] ?? array();
|
||||
$hasMarket = false;
|
||||
$hasShipyard = false;
|
||||
|
||||
foreach ( $traits as $trait ) {
|
||||
$traitSymbol = (string) ( $trait['symbol'] ?? '' );
|
||||
if ($traitSymbol === 'MARKETPLACE' ) {
|
||||
$hasMarket = true;
|
||||
}
|
||||
|
||||
if ($traitSymbol === 'SHIPYARD' ) {
|
||||
$hasShipyard = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasMarket ) {
|
||||
$marketRecord = array(
|
||||
'waypoint' => $waypoint,
|
||||
'data' => array(),
|
||||
'error' => '',
|
||||
);
|
||||
try {
|
||||
$marketResponse = $client->getWaypointMarket( $currentSystemSymbol, $waypointSymbol );
|
||||
$marketRecord['data'] = $marketResponse['data'] ?? array();
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$marketRecord['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$marketDetails[] = $marketRecord;
|
||||
}
|
||||
|
||||
if ($hasShipyard ) {
|
||||
$shipyardRecord = array(
|
||||
'waypoint' => $waypoint,
|
||||
'data' => array(),
|
||||
'error' => '',
|
||||
);
|
||||
try {
|
||||
$shipyardResponse = $client->getWaypointShipyard( $currentSystemSymbol, $waypointSymbol );
|
||||
$shipyardRecord['data'] = $shipyardResponse['data'] ?? array();
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$shipyardRecord['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$shipyardDetails[] = $shipyardRecord;
|
||||
}
|
||||
}
|
||||
|
||||
$waypointCount = count( $systemWaypoints );
|
||||
if ($waypointCount > 0 ) {
|
||||
$waypointTotalPages = (int) ceil( $waypointCount / $waypointPageSize );
|
||||
$waypointPage = min( $waypointPage, $waypointTotalPages );
|
||||
$offset = ( $waypointPage - 1 ) * $waypointPageSize;
|
||||
$paginatedWaypoints = array_slice( $systemWaypoints, $offset, $waypointPageSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$error = array(
|
||||
@@ -107,6 +241,10 @@ try {
|
||||
|
||||
<div class="mb-6">
|
||||
<a href="config.php" class="text-blue-400 hover:underline">Configuration</a>
|
||||
<span class="mx-2">|</span>
|
||||
<a href="buy-ships.php" class="text-blue-400 hover:underline">Buy Ships</a>
|
||||
<span class="mx-2">|</span>
|
||||
<a href="mining-fleet.php" class="text-blue-400 hover:underline">Mining Fleet</a>
|
||||
</div>
|
||||
|
||||
<?php if ($statusMessage !== '' ) : ?>
|
||||
@@ -135,6 +273,172 @@ try {
|
||||
System: <span class="font-normal"><?php echo htmlspecialchars( $ships[0]['nav']['systemSymbol'] ); ?></span>
|
||||
</h3>
|
||||
|
||||
<div class="mb-8 border border-gray-600 p-4 rounded">
|
||||
<h2 class="text-2xl font-bold mb-2">System Details</h2>
|
||||
<p class="mb-3 text-gray-300">
|
||||
Current System:
|
||||
<span class="font-semibold"><?php echo htmlspecialchars( (string) ( $system['symbol'] ?? 'Unknown' ) ); ?></span>
|
||||
<?php if (isset( $system['type'] ) ) : ?>
|
||||
(<?php echo htmlspecialchars( (string) $system['type'] ); ?>)
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<form method="post" class="mb-4 flex flex-wrap items-end gap-3">
|
||||
<input type="hidden" name="navigate_ship" value="1">
|
||||
<div>
|
||||
<label for="ship_symbol" class="block text-sm mb-1">Ship</label>
|
||||
<select id="ship_symbol" name="ship_symbol" class="px-3 py-2 rounded text-black min-w-52">
|
||||
<?php foreach ( $ships as $ship ) : ?>
|
||||
<?php $shipSymbol = (string) ( $ship['symbol'] ?? '' ); ?>
|
||||
<option value="<?php echo htmlspecialchars( $shipSymbol ); ?>" <?php echo ( $shipSymbol === $selectedShipSymbol ) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars( $shipSymbol ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="waypoint_symbol" class="block text-sm mb-1">Destination Waypoint</label>
|
||||
<select id="waypoint_symbol" name="waypoint_symbol" class="px-3 py-2 rounded text-black min-w-64">
|
||||
<?php foreach ( $systemWaypoints as $waypoint ) : ?>
|
||||
<?php $waypointSymbol = (string) ( $waypoint['symbol'] ?? '' ); ?>
|
||||
<?php $waypointType = (string) ( $waypoint['type'] ?? '' ); ?>
|
||||
<option value="<?php echo htmlspecialchars( $waypointSymbol ); ?>" <?php echo ( $waypointSymbol === $selectedWaypointSymbol ) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars( $waypointSymbol . ' (' . $waypointType . ')' ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 rounded hover:bg-blue-500">Navigate</button>
|
||||
</form>
|
||||
|
||||
<div class="mb-3 flex gap-2">
|
||||
<button type="button" class="system-tab px-3 py-2 bg-gray-700 rounded hover:bg-gray-600" data-tab-target="tab-waypoints">Waypoints</button>
|
||||
<button type="button" class="system-tab px-3 py-2 bg-gray-700 rounded hover:bg-gray-600" data-tab-target="tab-markets">Markets</button>
|
||||
<button type="button" class="system-tab px-3 py-2 bg-gray-700 rounded hover:bg-gray-600" data-tab-target="tab-shipyards">Shipyards</button>
|
||||
</div>
|
||||
|
||||
<div id="tab-waypoints" class="system-tab-panel">
|
||||
<?php
|
||||
$waypointCount = count( $systemWaypoints );
|
||||
$waypointStart = $waypointCount > 0 ? ( ( $waypointPage - 1 ) * $waypointPageSize ) + 1 : 0;
|
||||
$waypointEnd = min( $waypointPage * $waypointPageSize, $waypointCount );
|
||||
?>
|
||||
<div class="mb-3 flex items-center justify-between">
|
||||
<p class="text-sm text-gray-300">
|
||||
Showing <?php echo number_format( $waypointStart ); ?>-<?php echo number_format( $waypointEnd ); ?>
|
||||
of <?php echo number_format( $waypointCount ); ?> waypoints
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<?php if ($waypointPage > 1 ) : ?>
|
||||
<a
|
||||
href="agent-info.php?waypoint_page=<?php echo (int) ( $waypointPage - 1 ); ?>"
|
||||
class="px-3 py-1 bg-gray-700 rounded hover:bg-gray-600"
|
||||
>
|
||||
Previous
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($waypointPage < $waypointTotalPages ) : ?>
|
||||
<a
|
||||
href="agent-info.php?waypoint_page=<?php echo (int) ( $waypointPage + 1 ); ?>"
|
||||
class="px-3 py-1 bg-gray-700 rounded hover:bg-gray-600"
|
||||
>
|
||||
Next
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table-auto border-collapse border border-gray-300 w-full">
|
||||
<tr>
|
||||
<th class="border border-gray-300 px-3 py-2">Symbol</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Type</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Coordinates</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Traits</th>
|
||||
</tr>
|
||||
<?php foreach ( $paginatedWaypoints as $waypoint ) : ?>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $waypoint['symbol'] ?? '' ) ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $waypoint['type'] ?? '' ) ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2">
|
||||
<?php echo htmlspecialchars( (string) ( $waypoint['x'] ?? 0 ) ); ?>,
|
||||
<?php echo htmlspecialchars( (string) ( $waypoint['y'] ?? 0 ) ); ?>
|
||||
</td>
|
||||
<td class="border border-gray-300 px-3 py-2">
|
||||
<?php
|
||||
$traitNames = array();
|
||||
foreach ( (array) ( $waypoint['traits'] ?? array() ) as $trait ) {
|
||||
$traitNames[] = (string) ( $trait['symbol'] ?? '' );
|
||||
}
|
||||
echo htmlspecialchars( implode( ', ', array_filter( $traitNames ) ) );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="tab-markets" class="system-tab-panel hidden">
|
||||
<?php if (empty( $marketDetails ) ) : ?>
|
||||
<p class="text-gray-300">No markets found in this system.</p>
|
||||
<?php endif; ?>
|
||||
<?php foreach ( $marketDetails as $market ) : ?>
|
||||
<div class="mb-3 border border-gray-500 p-3 rounded">
|
||||
<h3 class="font-bold">
|
||||
<?php echo htmlspecialchars( (string) ( $market['waypoint']['symbol'] ?? '' ) ); ?>
|
||||
</h3>
|
||||
<?php if ($market['error'] !== '' ) : ?>
|
||||
<p class="text-red-300"><?php echo htmlspecialchars( (string) $market['error'] ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php $tradeGoods = (array) ( $market['data']['tradeGoods'] ?? array() ); ?>
|
||||
<p class="text-sm text-gray-300">Trade Goods: <?php echo htmlspecialchars( (string) count( $tradeGoods ) ); ?></p>
|
||||
<?php if (! empty( $tradeGoods ) ) : ?>
|
||||
<p class="text-sm text-gray-300">
|
||||
<?php
|
||||
$symbols = array();
|
||||
foreach ( $tradeGoods as $tradeGood ) {
|
||||
$symbols[] = (string) ( $tradeGood['symbol'] ?? '' );
|
||||
}
|
||||
echo htmlspecialchars( implode( ', ', array_filter( $symbols ) ) );
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div id="tab-shipyards" class="system-tab-panel hidden">
|
||||
<?php if (empty( $shipyardDetails ) ) : ?>
|
||||
<p class="text-gray-300">No shipyards found in this system.</p>
|
||||
<?php endif; ?>
|
||||
<?php foreach ( $shipyardDetails as $shipyard ) : ?>
|
||||
<div class="mb-3 border border-gray-500 p-3 rounded">
|
||||
<h3 class="font-bold">
|
||||
<?php echo htmlspecialchars( (string) ( $shipyard['waypoint']['symbol'] ?? '' ) ); ?>
|
||||
</h3>
|
||||
<?php if ($shipyard['error'] !== '' ) : ?>
|
||||
<p class="text-red-300"><?php echo htmlspecialchars( (string) $shipyard['error'] ); ?></p>
|
||||
<?php else : ?>
|
||||
<?php $shipTypes = (array) ( $shipyard['data']['shipTypes'] ?? array() ); ?>
|
||||
<p class="text-sm text-gray-300">Ships Available: <?php echo htmlspecialchars( (string) count( $shipTypes ) ); ?></p>
|
||||
<?php if (! empty( $shipTypes ) ) : ?>
|
||||
<p class="text-sm text-gray-300">
|
||||
<?php
|
||||
$types = array();
|
||||
foreach ( $shipTypes as $shipType ) {
|
||||
$types[] = (string) ( $shipType['type'] ?? '' );
|
||||
}
|
||||
echo htmlspecialchars( implode( ', ', array_filter( $types ) ) );
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="text-2xl font-bold my-4">Ships</h2>
|
||||
<table class="table-auto border-collapse border border-gray-300">
|
||||
<tr>
|
||||
@@ -148,7 +452,14 @@ try {
|
||||
|
||||
<?php foreach ( $ships as $ship ) : ?>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2"><?php echo htmlspecialchars( ucfirst( strtolower( $ship['registration']['name'] ) ) ); ?></td>
|
||||
<td class="border border-gray-300 px-4 py-2">
|
||||
<a
|
||||
href="ship-details.php?ship=<?php echo urlencode( (string) ( $ship['symbol'] ?? '' ) ); ?>"
|
||||
class="text-blue-400 hover:underline"
|
||||
>
|
||||
<?php echo htmlspecialchars( ucfirst( strtolower( $ship['registration']['name'] ) ) ); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td class="border border-gray-300 px-4 py-2"><?php echo htmlspecialchars( ucfirst( strtolower( $ship['registration']['role'] ) ) ); ?></td>
|
||||
<td class="border border-gray-300 px-4 py-2"><?php echo htmlspecialchars( $ship['frame']['name'] ); ?></td>
|
||||
<td class="border border-gray-300 px-4 py-2"><?php echo htmlspecialchars( ucfirst( strtolower( $ship['nav']['status'] ) ) ); ?></td>
|
||||
@@ -218,5 +529,37 @@ try {
|
||||
endforeach;
|
||||
?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const tabs = document.querySelectorAll('.system-tab');
|
||||
const panels = document.querySelectorAll('.system-tab-panel');
|
||||
|
||||
function activateTab(targetId) {
|
||||
panels.forEach((panel) => {
|
||||
panel.classList.toggle('hidden', panel.id !== targetId);
|
||||
});
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
const isActive = tab.getAttribute('data-tab-target') === targetId;
|
||||
tab.classList.toggle('bg-blue-700', isActive);
|
||||
tab.classList.toggle('bg-gray-700', !isActive);
|
||||
});
|
||||
}
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
tab.addEventListener('click', () => {
|
||||
const targetId = tab.getAttribute('data-tab-target');
|
||||
if (targetId) {
|
||||
activateTab(targetId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (tabs.length > 0) {
|
||||
activateTab('tab-waypoints');
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
241
buy-ships.php
Normal file
241
buy-ships.php
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
/**
|
||||
* Spacetraders ship purchasing page.
|
||||
*
|
||||
* @package SpacetradersApi
|
||||
* @author Keith Solomon <keith@keithsolomon.net>
|
||||
* @license MIT License
|
||||
* @link https://git.keithsolomon.net/keith/Spacetraders
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/lib/spacetraders-api.php';
|
||||
require_once __DIR__ . '/lib/spacetraders-storage.php';
|
||||
|
||||
$config = require __DIR__ . '/lib/project-config.php';
|
||||
|
||||
$storage = new SpacetradersStorage( $config['db_path'] );
|
||||
$token = $storage->getAgentToken();
|
||||
|
||||
$statusMessage = '';
|
||||
$errorMessage = '';
|
||||
$ships = array();
|
||||
$shipyards = array();
|
||||
$agent = array();
|
||||
$currentSystemSymbol = '';
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$envToken = getenv( 'SPACETRADERS_TOKEN' );
|
||||
if (is_string( $envToken ) && trim( $envToken ) !== '' ) {
|
||||
$token = trim( $envToken );
|
||||
$storage->setAgentToken( $token );
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$tokenError = 'No token found. Set one in config.php or SPACETRADERS_TOKEN.';
|
||||
}
|
||||
|
||||
if (! isset( $tokenError ) ) {
|
||||
$client = new SpacetradersApi(
|
||||
trim( $token ),
|
||||
$config['api_base_url'],
|
||||
(int) $config['api_timeout'],
|
||||
$storage,
|
||||
(int) $config['cache_ttl']
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (! isset( $tokenError ) ) {
|
||||
if (
|
||||
$_SERVER['REQUEST_METHOD'] === 'POST' &&
|
||||
isset( $_POST['ship_type'] ) &&
|
||||
isset( $_POST['waypoint_symbol'] )
|
||||
) {
|
||||
$shipType = trim( (string) $_POST['ship_type'] );
|
||||
$waypointSymbol = trim( (string) $_POST['waypoint_symbol'] );
|
||||
|
||||
if ($shipType !== '' && $waypointSymbol !== '' ) {
|
||||
$purchaseResponse = $client->purchaseShip( $shipType, $waypointSymbol );
|
||||
$shipSymbol = (string) ( $purchaseResponse['data']['ship']['symbol'] ?? '' );
|
||||
$storage->clearAllCache();
|
||||
$statusMessage = 'Purchased ' . $shipType . ( $shipSymbol !== '' ? ' (' . $shipSymbol . ')' : '' ) . '.';
|
||||
}
|
||||
}
|
||||
|
||||
$agentResponse = $client->getMyAgent();
|
||||
$shipsResponse = $client->listMyShips();
|
||||
|
||||
$agent = $agentResponse['data'] ?? $agentResponse;
|
||||
$ships = $shipsResponse['data'] ?? $shipsResponse;
|
||||
|
||||
if (isset( $ships[0]['nav']['systemSymbol'] ) && is_string( $ships[0]['nav']['systemSymbol'] ) ) {
|
||||
$currentSystemSymbol = $ships[0]['nav']['systemSymbol'];
|
||||
}
|
||||
|
||||
if ($currentSystemSymbol === '' && isset( $agent['headquarters'] ) && is_string( $agent['headquarters'] ) ) {
|
||||
$hqParts = explode( '-', $agent['headquarters'] );
|
||||
if (count( $hqParts ) >= 2 ) {
|
||||
$currentSystemSymbol = $hqParts[0] . '-' . $hqParts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($currentSystemSymbol !== '' ) {
|
||||
$page = 1;
|
||||
$total = 0;
|
||||
$waypoints = array();
|
||||
do {
|
||||
$waypointsResponse = $client->listWaypoints(
|
||||
$currentSystemSymbol,
|
||||
array(
|
||||
'page' => $page,
|
||||
'limit' => 20,
|
||||
)
|
||||
);
|
||||
$pageData = $waypointsResponse['data'] ?? array();
|
||||
if (! is_array( $pageData ) || empty( $pageData ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$waypoints = array_merge( $waypoints, $pageData );
|
||||
$total = (int) ( $waypointsResponse['meta']['total'] ?? count( $waypoints ) );
|
||||
$page++;
|
||||
} while (count( $waypoints ) < $total);
|
||||
|
||||
foreach ( $waypoints as $waypoint ) {
|
||||
$traits = $waypoint['traits'] ?? array();
|
||||
$hasShipyard = false;
|
||||
foreach ( $traits as $trait ) {
|
||||
if ((string) ( $trait['symbol'] ?? '' ) === 'SHIPYARD' ) {
|
||||
$hasShipyard = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! $hasShipyard ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$waypointSymbol = (string) ( $waypoint['symbol'] ?? '' );
|
||||
$record = array(
|
||||
'waypoint' => $waypoint,
|
||||
'shipTypes' => array(),
|
||||
'prices' => array(),
|
||||
'error' => '',
|
||||
);
|
||||
|
||||
try {
|
||||
$shipyardResponse = $client->getWaypointShipyard( $currentSystemSymbol, $waypointSymbol );
|
||||
$shipyardData = $shipyardResponse['data'] ?? array();
|
||||
$record['shipTypes'] = (array) ( $shipyardData['shipTypes'] ?? array() );
|
||||
|
||||
$transactions = (array) ( $shipyardData['transactions'] ?? array() );
|
||||
foreach ( $transactions as $transaction ) {
|
||||
$shipType = (string) ( $transaction['shipType'] ?? '' );
|
||||
$price = (int) ( $transaction['price'] ?? 0 );
|
||||
if ($shipType !== '' && $price > 0 && ! isset( $record['prices'][ $shipType ] ) ) {
|
||||
$record['prices'][ $shipType ] = $price;
|
||||
}
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$record['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$shipyards[] = $record;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spacetraders - Buy Ships</title>
|
||||
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="container mx-auto px-4 py-8 bg-stone-800 text-gray-200">
|
||||
<div class="mb-6 flex gap-4">
|
||||
<a href="agent-info.php" class="text-blue-400 hover:underline">Agent Info</a>
|
||||
<a href="mining-fleet.php" class="text-blue-400 hover:underline">Mining Fleet</a>
|
||||
<a href="config.php" class="text-blue-400 hover:underline">Configuration</a>
|
||||
</div>
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6 underline decoration-gray-300 w-full">Buy Ships</h1>
|
||||
|
||||
<?php if (isset( $tokenError ) ) : ?>
|
||||
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $tokenError ); ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php exit; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($statusMessage !== '' ) : ?>
|
||||
<div class="mb-6 border border-green-500 p-4 rounded text-green-300">
|
||||
<?php echo htmlspecialchars( $statusMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($errorMessage !== '' ) : ?>
|
||||
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $errorMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="mb-6">
|
||||
Credits: <span class="font-semibold"><?php echo number_format( (int) ( $agent['credits'] ?? 0 ) ); ?></span>
|
||||
<?php if ($currentSystemSymbol !== '' ) : ?>
|
||||
| Current System: <span class="font-semibold"><?php echo htmlspecialchars( $currentSystemSymbol ); ?></span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<?php if (empty( $shipyards ) ) : ?>
|
||||
<div class="border border-gray-600 p-4 rounded">
|
||||
No shipyards were found in your current system.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach ( $shipyards as $shipyard ) : ?>
|
||||
<div class="mb-6 border border-gray-600 p-4 rounded">
|
||||
<h2 class="text-2xl font-bold mb-3">
|
||||
Shipyard: <?php echo htmlspecialchars( (string) ( $shipyard['waypoint']['symbol'] ?? '' ) ); ?>
|
||||
</h2>
|
||||
|
||||
<?php if ((string) $shipyard['error'] !== '' ) : ?>
|
||||
<p class="text-red-300"><?php echo htmlspecialchars( (string) $shipyard['error'] ); ?></p>
|
||||
<?php else : ?>
|
||||
<table class="table-auto border-collapse border border-gray-300 w-full">
|
||||
<tr>
|
||||
<th class="border border-gray-300 px-4 py-2">Ship Type</th>
|
||||
<th class="border border-gray-300 px-4 py-2">Known Price</th>
|
||||
<th class="border border-gray-300 px-4 py-2">Action</th>
|
||||
</tr>
|
||||
<?php foreach ( (array) $shipyard['shipTypes'] as $shipTypeRecord ) : ?>
|
||||
<?php $shipType = (string) ( $shipTypeRecord['type'] ?? '' ); ?>
|
||||
<?php $knownPrice = (int) ( $shipyard['prices'][ $shipType ] ?? 0 ); ?>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-4 py-2"><?php echo htmlspecialchars( $shipType ); ?></td>
|
||||
<td class="border border-gray-300 px-4 py-2">
|
||||
<?php echo $knownPrice > 0 ? number_format( $knownPrice ) : 'Unknown'; ?>
|
||||
</td>
|
||||
<td class="border border-gray-300 px-4 py-2">
|
||||
<form method="post" class="inline">
|
||||
<input type="hidden" name="ship_type" value="<?php echo htmlspecialchars( $shipType ); ?>">
|
||||
<input type="hidden" name="waypoint_symbol" value="<?php echo htmlspecialchars( (string) ( $shipyard['waypoint']['symbol'] ?? '' ) ); ?>">
|
||||
<button type="submit" class="px-3 py-1 bg-blue-600 rounded hover:bg-blue-500">Buy</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</body>
|
||||
</html>
|
||||
@@ -89,6 +89,10 @@ $hasToken = is_string( $token ) && trim( $token ) !== '';
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<a href="agent-info.php" class="text-blue-400 hover:underline">Back to Agent Info</a>
|
||||
<div class="flex gap-4">
|
||||
<a href="agent-info.php" class="text-blue-400 hover:underline">Agent Info</a>
|
||||
<a href="buy-ships.php" class="text-blue-400 hover:underline">Buy Ships</a>
|
||||
<a href="mining-fleet.php" class="text-blue-400 hover:underline">Mining Fleet</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -329,6 +329,51 @@ class SpacetradersApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about a single waypoint.
|
||||
*
|
||||
* @param string $systemSymbol The system symbol.
|
||||
* @param string $waypointSymbol The waypoint symbol.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function getWaypoint( string $systemSymbol, string $waypointSymbol ): array {
|
||||
return $this->request(
|
||||
'GET',
|
||||
'/systems/' . rawurlencode( $systemSymbol ) . '/waypoints/' . rawurlencode( $waypointSymbol )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get market data for a waypoint with a marketplace.
|
||||
*
|
||||
* @param string $systemSymbol The system symbol.
|
||||
* @param string $waypointSymbol The waypoint symbol.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function getWaypointMarket( string $systemSymbol, string $waypointSymbol ): array {
|
||||
return $this->request(
|
||||
'GET',
|
||||
'/systems/' . rawurlencode( $systemSymbol ) . '/waypoints/' . rawurlencode( $waypointSymbol ) . '/market'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get shipyard data for a waypoint with a shipyard.
|
||||
*
|
||||
* @param string $systemSymbol The system symbol.
|
||||
* @param string $waypointSymbol The waypoint symbol.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function getWaypointShipyard( string $systemSymbol, string $waypointSymbol ): array {
|
||||
return $this->request(
|
||||
'GET',
|
||||
'/systems/' . rawurlencode( $systemSymbol ) . '/waypoints/' . rawurlencode( $waypointSymbol ) . '/shipyard'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate a ship to a specific waypoint.
|
||||
*
|
||||
@@ -387,6 +432,61 @@ class SpacetradersApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a survey at the ship's current waypoint.
|
||||
*
|
||||
* @param string $shipSymbol The symbol of the ship creating the survey.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function surveyWaypoint( string $shipSymbol ): array {
|
||||
return $this->request(
|
||||
'POST',
|
||||
'/my/ships/' . rawurlencode( $shipSymbol ) . '/survey'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Siphon resources at the ship's current waypoint.
|
||||
*
|
||||
* @param string $shipSymbol The symbol of the ship performing siphon.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function siphonResources( string $shipSymbol ): array {
|
||||
return $this->request(
|
||||
'POST',
|
||||
'/my/ships/' . rawurlencode( $shipSymbol ) . '/siphon'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refuel a ship.
|
||||
*
|
||||
* @param string $shipSymbol The symbol of the ship to refuel.
|
||||
* @param bool $fromCargo Whether to refuel from cargo instead of market.
|
||||
* @param int|null $units Optional number of fuel units to buy.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function refuelShip( string $shipSymbol, bool $fromCargo = false, ?int $units = null ): array {
|
||||
$payload = array();
|
||||
|
||||
if ($fromCargo ) {
|
||||
$payload['fromCargo'] = true;
|
||||
}
|
||||
|
||||
if ($units !== null && $units > 0 ) {
|
||||
$payload['units'] = $units;
|
||||
}
|
||||
|
||||
return $this->request(
|
||||
'POST',
|
||||
'/my/ships/' . rawurlencode( $shipSymbol ) . '/refuel',
|
||||
$payload
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purchase cargo for a specific ship at its current waypoint.
|
||||
*
|
||||
@@ -427,6 +527,45 @@ class SpacetradersApi {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Jettison cargo from a ship.
|
||||
*
|
||||
* @param string $shipSymbol The symbol of the ship.
|
||||
* @param string $tradeSymbol The cargo symbol to jettison.
|
||||
* @param int $units Number of units to jettison.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function jettisonCargo( string $shipSymbol, string $tradeSymbol, int $units ): array {
|
||||
return $this->request(
|
||||
'POST',
|
||||
'/my/ships/' . rawurlencode( $shipSymbol ) . '/jettison',
|
||||
array(
|
||||
'symbol' => $tradeSymbol,
|
||||
'units' => $units,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purchase a new ship from a shipyard.
|
||||
*
|
||||
* @param string $shipType The ship type to purchase.
|
||||
* @param string $waypointSymbol The shipyard waypoint symbol.
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
public function purchaseShip( string $shipType, string $waypointSymbol ): array {
|
||||
return $this->request(
|
||||
'POST',
|
||||
'/my/ships',
|
||||
array(
|
||||
'shipType' => $shipType,
|
||||
'waypointSymbol' => $waypointSymbol,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the full URL for an API endpoint with optional query parameters.
|
||||
*
|
||||
|
||||
552
mining-fleet.php
Normal file
552
mining-fleet.php
Normal file
@@ -0,0 +1,552 @@
|
||||
<?php
|
||||
/**
|
||||
* Spacetraders mining fleet control page.
|
||||
*
|
||||
* @package SpacetradersApi
|
||||
* @author Keith Solomon <keith@keithsolomon.net>
|
||||
* @license MIT License
|
||||
* @link https://git.keithsolomon.net/keith/Spacetraders
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/lib/spacetraders-api.php';
|
||||
require_once __DIR__ . '/lib/spacetraders-storage.php';
|
||||
|
||||
/**
|
||||
* Filter only mining ships.
|
||||
*
|
||||
* @param array<int,array<string,mixed>> $ships
|
||||
*
|
||||
* @return array<int,array<string,mixed>>
|
||||
*/
|
||||
function spacetraders_filter_mining_ships( array $ships ): array {
|
||||
return array_values(
|
||||
array_filter(
|
||||
$ships,
|
||||
static function ( array $ship ): bool {
|
||||
$role = strtoupper( (string) ( $ship['registration']['role'] ?? '' ) );
|
||||
return $role === 'EXCAVATOR';
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$config = require __DIR__ . '/lib/project-config.php';
|
||||
|
||||
$storage = new SpacetradersStorage( $config['db_path'] );
|
||||
$token = $storage->getAgentToken();
|
||||
|
||||
$statusMessage = '';
|
||||
$errorMessage = '';
|
||||
$actionResults = array();
|
||||
$agent = array();
|
||||
$ships = array();
|
||||
$miningShips = array();
|
||||
$activeContracts = array();
|
||||
$marketWaypoints = array();
|
||||
$selectedMarketWaypoint = '';
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$envToken = getenv( 'SPACETRADERS_TOKEN' );
|
||||
if (is_string( $envToken ) && trim( $envToken ) !== '' ) {
|
||||
$token = trim( $envToken );
|
||||
$storage->setAgentToken( $token );
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$tokenError = 'No token found. Set one in config.php or SPACETRADERS_TOKEN.';
|
||||
}
|
||||
|
||||
if (! isset( $tokenError ) ) {
|
||||
$client = new SpacetradersApi(
|
||||
trim( $token ),
|
||||
$config['api_base_url'],
|
||||
(int) $config['api_timeout'],
|
||||
$storage,
|
||||
(int) $config['cache_ttl']
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (! isset( $tokenError ) ) {
|
||||
$agentResponse = $client->getMyAgent();
|
||||
$shipsResponse = $client->listMyShips();
|
||||
$contractsResponse = $client->listMyContracts();
|
||||
|
||||
$agent = $agentResponse['data'] ?? $agentResponse;
|
||||
$ships = $shipsResponse['data'] ?? $shipsResponse;
|
||||
$contracts = $contractsResponse['data'] ?? $contractsResponse;
|
||||
$miningShips = spacetraders_filter_mining_ships( $ships );
|
||||
$activeContracts = array_values(
|
||||
array_filter(
|
||||
(array) $contracts,
|
||||
static function ( array $contract ): bool {
|
||||
return (bool) ( $contract['accepted'] ?? false ) && ! (bool) ( $contract['fulfilled'] ?? false );
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
$currentSystemSymbol = '';
|
||||
if (! empty( $miningShips ) && isset( $miningShips[0]['nav']['systemSymbol'] ) ) {
|
||||
$currentSystemSymbol = (string) $miningShips[0]['nav']['systemSymbol'];
|
||||
} elseif (! empty( $ships ) && isset( $ships[0]['nav']['systemSymbol'] ) ) {
|
||||
$currentSystemSymbol = (string) $ships[0]['nav']['systemSymbol'];
|
||||
} elseif (isset( $agent['headquarters'] ) && is_string( $agent['headquarters'] ) ) {
|
||||
$hqParts = explode( '-', $agent['headquarters'] );
|
||||
if (count( $hqParts ) >= 2 ) {
|
||||
$currentSystemSymbol = $hqParts[0] . '-' . $hqParts[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($currentSystemSymbol !== '' ) {
|
||||
$page = 1;
|
||||
$total = 0;
|
||||
$waypoints = array();
|
||||
do {
|
||||
$waypointsResponse = $client->listWaypoints(
|
||||
$currentSystemSymbol,
|
||||
array(
|
||||
'page' => $page,
|
||||
'limit' => 20,
|
||||
)
|
||||
);
|
||||
$pageData = $waypointsResponse['data'] ?? array();
|
||||
if (! is_array( $pageData ) || empty( $pageData ) ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$waypoints = array_merge( $waypoints, $pageData );
|
||||
$total = (int) ( $waypointsResponse['meta']['total'] ?? count( $waypoints ) );
|
||||
$page++;
|
||||
} while (count( $waypoints ) < $total);
|
||||
|
||||
foreach ( $waypoints as $waypoint ) {
|
||||
foreach ( (array) ( $waypoint['traits'] ?? array() ) as $trait ) {
|
||||
if ((string) ( $trait['symbol'] ?? '' ) === 'MARKETPLACE' ) {
|
||||
$marketWaypoints[] = (string) ( $waypoint['symbol'] ?? '' );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$selectedMarketWaypoint = isset( $_POST['market_waypoint'] ) ?
|
||||
trim( (string) $_POST['market_waypoint'] ) :
|
||||
( $marketWaypoints[0] ?? '' );
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['fleet_action'] ) ) {
|
||||
$fleetAction = (string) $_POST['fleet_action'];
|
||||
$successCount = 0;
|
||||
|
||||
foreach ( $miningShips as $fleetShip ) {
|
||||
$shipSymbol = (string) ( $fleetShip['symbol'] ?? '' );
|
||||
if ($shipSymbol === '' ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
$waypointSymbol = (string) ( $shipData['nav']['waypointSymbol'] ?? '' );
|
||||
|
||||
if ($fleetAction === 'excavate_all' ) {
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
$actionResults[] = $shipSymbol . ': skipped (in transit).';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($shipStatus === 'DOCKED' ) {
|
||||
$client->orbitShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$client->extractResources( $shipSymbol );
|
||||
$actionResults[] = $shipSymbol . ': extracting.';
|
||||
$successCount++;
|
||||
} elseif ($fleetAction === 'dock_refuel_all' ) {
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
$actionResults[] = $shipSymbol . ': skipped (in transit).';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$client->refuelShip( $shipSymbol );
|
||||
$actionResults[] = $shipSymbol . ': docked/refueled.';
|
||||
$successCount++;
|
||||
} elseif ($fleetAction === 'move_and_sell_all' ) {
|
||||
if ($selectedMarketWaypoint === '' ) {
|
||||
$actionResults[] = $shipSymbol . ': no market waypoint selected.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
$actionResults[] = $shipSymbol . ': already in transit.';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($waypointSymbol !== $selectedMarketWaypoint ) {
|
||||
if ($shipStatus === 'DOCKED' ) {
|
||||
$client->orbitShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$client->navigateShip( $shipSymbol, $selectedMarketWaypoint );
|
||||
$actionResults[] = $shipSymbol . ': navigating to ' . $selectedMarketWaypoint . '.';
|
||||
$successCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$soldItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$soldItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Ignore individual sell failures and continue.
|
||||
}
|
||||
}
|
||||
|
||||
$actionResults[] = $shipSymbol . ': sold ' . $soldItems . ' cargo item type(s).';
|
||||
$successCount++;
|
||||
} elseif ($fleetAction === 'sell_cargo_here_all' ) {
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
$actionResults[] = $shipSymbol . ': skipped (in transit).';
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$soldItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$soldItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Continue selling other items.
|
||||
}
|
||||
}
|
||||
|
||||
$actionResults[] = $shipSymbol . ': sold ' . $soldItems . ' cargo item type(s) at current waypoint.';
|
||||
$successCount++;
|
||||
} elseif ($fleetAction === 'jettison_cargo_all' ) {
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
$actionResults[] = $shipSymbol . ': skipped (in transit).';
|
||||
continue;
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$jettisonedItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$client->jettisonCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$jettisonedItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Continue jettisoning other items.
|
||||
}
|
||||
}
|
||||
|
||||
$actionResults[] = $shipSymbol . ': jettisoned ' . $jettisonedItems . ' cargo item type(s).';
|
||||
$successCount++;
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$actionResults[] = $shipSymbol . ': ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if ($successCount > 0 ) {
|
||||
$storage->clearAllCache();
|
||||
}
|
||||
|
||||
$statusMessage = 'Action complete for ' . $successCount . ' ship(s).';
|
||||
|
||||
$shipsResponse = $client->listMyShips();
|
||||
$contractsResponse = $client->listMyContracts();
|
||||
$ships = $shipsResponse['data'] ?? $shipsResponse;
|
||||
$contracts = $contractsResponse['data'] ?? $contractsResponse;
|
||||
$miningShips = spacetraders_filter_mining_ships( $ships );
|
||||
$activeContracts = array_values(
|
||||
array_filter(
|
||||
(array) $contracts,
|
||||
static function ( array $contract ): bool {
|
||||
return (bool) ( $contract['accepted'] ?? false ) && ! (bool) ( $contract['fulfilled'] ?? false );
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
$_SERVER['REQUEST_METHOD'] === 'POST' &&
|
||||
isset( $_POST['ship_action'] ) &&
|
||||
in_array( (string) $_POST['ship_action'], array( 'sell_ship_cargo', 'jettison_ship_cargo' ), true ) &&
|
||||
isset( $_POST['ship_symbol'] )
|
||||
) {
|
||||
$shipAction = (string) $_POST['ship_action'];
|
||||
$sellShipSymbol = trim( (string) $_POST['ship_symbol'] );
|
||||
|
||||
if ($sellShipSymbol !== '' ) {
|
||||
try {
|
||||
$shipResponse = $client->getShip( $sellShipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException( 'Ship is in transit and cargo action is unavailable right now.' );
|
||||
}
|
||||
|
||||
if ($shipAction === 'sell_ship_cargo' && $shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $sellShipSymbol );
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$handledItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($shipAction === 'sell_ship_cargo' ) {
|
||||
$client->sellCargo( $sellShipSymbol, $tradeSymbol, $units );
|
||||
} else {
|
||||
$client->jettisonCargo( $sellShipSymbol, $tradeSymbol, $units );
|
||||
}
|
||||
$handledItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Continue processing other items.
|
||||
}
|
||||
}
|
||||
|
||||
if ($shipAction === 'sell_ship_cargo' ) {
|
||||
$statusMessage = $sellShipSymbol . ': sold ' . $handledItems . ' cargo item type(s).';
|
||||
} else {
|
||||
$statusMessage = $sellShipSymbol . ': jettisoned ' . $handledItems . ' cargo item type(s).';
|
||||
}
|
||||
$storage->clearAllCache();
|
||||
|
||||
$shipsResponse = $client->listMyShips();
|
||||
$ships = $shipsResponse['data'] ?? $shipsResponse;
|
||||
$miningShips = spacetraders_filter_mining_ships( $ships );
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$errorMessage = $sellShipSymbol . ': ' . $e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spacetraders - Mining Fleet</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="container mx-auto px-4 py-8 bg-stone-800 text-gray-200">
|
||||
<div class="mb-6 flex gap-4">
|
||||
<a href="agent-info.php" class="text-blue-400 hover:underline">Agent Info</a>
|
||||
<a href="buy-ships.php" class="text-blue-400 hover:underline">Buy Ships</a>
|
||||
<a href="config.php" class="text-blue-400 hover:underline">Configuration</a>
|
||||
</div>
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6 underline decoration-gray-300 w-full">Mining Fleet</h1>
|
||||
|
||||
<?php if (isset( $tokenError ) ) : ?>
|
||||
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $tokenError ); ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php exit; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($statusMessage !== '' ) : ?>
|
||||
<div class="mb-4 border border-green-500 p-4 rounded text-green-300">
|
||||
<?php echo htmlspecialchars( $statusMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($errorMessage !== '' ) : ?>
|
||||
<div class="mb-4 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $errorMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mb-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-3">Global Controls</h2>
|
||||
<form method="post" class="flex flex-wrap items-end gap-3">
|
||||
<div>
|
||||
<label for="market_waypoint" class="block text-sm mb-1">Market Waypoint</label>
|
||||
<select id="market_waypoint" name="market_waypoint" class="px-3 py-2 rounded text-black min-w-64">
|
||||
<?php foreach ( $marketWaypoints as $waypoint ) : ?>
|
||||
<option value="<?php echo htmlspecialchars( $waypoint ); ?>" <?php echo $waypoint === $selectedMarketWaypoint ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars( $waypoint ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" name="fleet_action" value="excavate_all" class="px-4 py-2 bg-emerald-700 rounded hover:bg-emerald-600">
|
||||
Command All: Excavate
|
||||
</button>
|
||||
<button type="submit" name="fleet_action" value="dock_refuel_all" class="px-4 py-2 bg-blue-700 rounded hover:bg-blue-600">
|
||||
Command All: Dock & Refuel
|
||||
</button>
|
||||
<button type="submit" name="fleet_action" value="move_and_sell_all" class="px-4 py-2 bg-amber-700 rounded hover:bg-amber-600">
|
||||
Command All: Move to Market & Sell
|
||||
</button>
|
||||
<button type="submit" name="fleet_action" value="sell_cargo_here_all" class="px-4 py-2 bg-rose-700 rounded hover:bg-rose-600">
|
||||
Command All: Sell Cargo Here
|
||||
</button>
|
||||
<button type="submit" name="fleet_action" value="jettison_cargo_all" class="px-4 py-2 bg-red-800 rounded hover:bg-red-700">
|
||||
Command All: Jettison Cargo
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php if (! empty( $actionResults ) ) : ?>
|
||||
<div class="mb-6 border border-gray-600 rounded p-4">
|
||||
<h3 class="font-bold mb-2">Action Results</h3>
|
||||
<ul class="list-disc list-inside text-sm text-gray-300">
|
||||
<?php foreach ( $actionResults as $result ) : ?>
|
||||
<li><?php echo htmlspecialchars( (string) $result ); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="mb-4 text-gray-300">
|
||||
Mining Ships: <span class="font-semibold"><?php echo number_format( count( $miningShips ) ); ?></span>
|
||||
</p>
|
||||
|
||||
<div class="mb-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-3">Active Contracts</h2>
|
||||
<?php if (empty( $activeContracts ) ) : ?>
|
||||
<p class="text-gray-300">No active contracts.</p>
|
||||
<?php else : ?>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<?php foreach ( $activeContracts as $contract ) : ?>
|
||||
<?php
|
||||
$contractType = (string) ( $contract['type'] ?? '' );
|
||||
$deliveries = (array) ( $contract['terms']['deliver'] ?? array() );
|
||||
?>
|
||||
<div class="border border-gray-500 rounded p-3">
|
||||
<p><span class="font-bold">Contract:</span> <?php echo htmlspecialchars( (string) ( $contract['id'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Type:</span> <?php echo htmlspecialchars( $contractType ); ?></p>
|
||||
<p>
|
||||
<span class="font-bold">Deadline:</span>
|
||||
<?php echo htmlspecialchars( (string) date( 'Y-m-d H:i:s', strtotime( (string) ( $contract['terms']['deadline'] ?? '' ) ) ) ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<span class="font-bold">Payment:</span>
|
||||
<?php echo number_format( (int) ( $contract['terms']['payment']['onAccepted'] ?? 0 ) ); ?>
|
||||
+
|
||||
<?php echo number_format( (int) ( $contract['terms']['payment']['onFulfilled'] ?? 0 ) ); ?>
|
||||
</p>
|
||||
<?php if (! empty( $deliveries ) ) : ?>
|
||||
<p class="mt-2 font-bold">Deliveries:</p>
|
||||
<ul class="list-disc list-inside text-sm text-gray-300">
|
||||
<?php foreach ( $deliveries as $delivery ) : ?>
|
||||
<?php
|
||||
$unitsRequired = (int) ( $delivery['unitsRequired'] ?? 0 );
|
||||
$unitsFulfilled = (int) ( $delivery['unitsFulfilled'] ?? 0 );
|
||||
?>
|
||||
<li>
|
||||
<?php echo htmlspecialchars( (string) ( $delivery['tradeSymbol'] ?? '' ) ); ?>:
|
||||
<?php echo number_format( $unitsFulfilled ); ?>/<?php echo number_format( $unitsRequired ); ?>
|
||||
to <?php echo htmlspecialchars( (string) ( $delivery['destinationSymbol'] ?? '' ) ); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if (empty( $miningShips ) ) : ?>
|
||||
<div class="border border-gray-600 rounded p-4">No mining ships found (role: EXCAVATOR).</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<?php foreach ( $miningShips as $ship ) : ?>
|
||||
<?php
|
||||
$shipSymbol = (string) ( $ship['symbol'] ?? '' );
|
||||
$fuelCurrent = (int) ( $ship['fuel']['current'] ?? 0 );
|
||||
$fuelCapacity = (int) ( $ship['fuel']['capacity'] ?? 0 );
|
||||
$cargoUnits = (int) ( $ship['cargo']['units'] ?? 0 );
|
||||
$cargoCapacity = (int) ( $ship['cargo']['capacity'] ?? 0 );
|
||||
?>
|
||||
<div class="border border-gray-600 rounded p-4">
|
||||
<h3 class="text-lg font-bold mb-2">
|
||||
<a href="ship-details.php?ship=<?php echo urlencode( $shipSymbol ); ?>" class="text-blue-400 hover:underline">
|
||||
<?php echo htmlspecialchars( $shipSymbol ); ?>
|
||||
</a>
|
||||
</h3>
|
||||
<p><span class="font-bold">Name:</span> <?php echo htmlspecialchars( (string) ( $ship['registration']['name'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Status:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['status'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Waypoint:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['waypointSymbol'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Fuel:</span> <?php echo number_format( $fuelCurrent ); ?>/<?php echo number_format( $fuelCapacity ); ?></p>
|
||||
<p><span class="font-bold">Cargo:</span> <?php echo number_format( $cargoUnits ); ?>/<?php echo number_format( $cargoCapacity ); ?></p>
|
||||
|
||||
<?php $inventory = (array) ( $ship['cargo']['inventory'] ?? array() ); ?>
|
||||
<?php if (! empty( $inventory ) ) : ?>
|
||||
<p class="mt-2 font-bold">Cargo Contents:</p>
|
||||
<ul class="list-disc list-inside text-sm text-gray-300">
|
||||
<?php foreach ( $inventory as $item ) : ?>
|
||||
<li>
|
||||
<?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?>:
|
||||
<?php echo number_format( (int) ( $item['units'] ?? 0 ) ); ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<form method="post" class="mt-3">
|
||||
<input type="hidden" name="ship_action" value="sell_ship_cargo">
|
||||
<input type="hidden" name="ship_symbol" value="<?php echo htmlspecialchars( $shipSymbol ); ?>">
|
||||
<button type="submit" class="px-3 py-1 bg-rose-700 rounded hover:bg-rose-600">Sell This Ship's Cargo</button>
|
||||
</form>
|
||||
<form method="post" class="mt-2">
|
||||
<input type="hidden" name="ship_action" value="jettison_ship_cargo">
|
||||
<input type="hidden" name="ship_symbol" value="<?php echo htmlspecialchars( $shipSymbol ); ?>">
|
||||
<button type="submit" class="px-3 py-1 bg-red-800 rounded hover:bg-red-700">Jettison This Ship's Cargo</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
422
ship-details.php
Normal file
422
ship-details.php
Normal file
@@ -0,0 +1,422 @@
|
||||
<?php
|
||||
/**
|
||||
* Spacetraders ship details page.
|
||||
*
|
||||
* @package SpacetradersApi
|
||||
* @author Keith Solomon <keith@keithsolomon.net>
|
||||
* @license MIT License
|
||||
* @link https://git.keithsolomon.net/keith/Spacetraders
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/lib/spacetraders-api.php';
|
||||
require_once __DIR__ . '/lib/spacetraders-storage.php';
|
||||
|
||||
$config = require __DIR__ . '/lib/project-config.php';
|
||||
|
||||
$storage = new SpacetradersStorage( $config['db_path'] );
|
||||
$token = $storage->getAgentToken();
|
||||
|
||||
$statusMessage = '';
|
||||
$errorMessage = '';
|
||||
$ship = array();
|
||||
$shipList = array();
|
||||
$shipSymbol = isset( $_GET['ship'] ) ? trim( (string) $_GET['ship'] ) : '';
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$envToken = getenv( 'SPACETRADERS_TOKEN' );
|
||||
if (is_string( $envToken ) && trim( $envToken ) !== '' ) {
|
||||
$token = trim( $envToken );
|
||||
$storage->setAgentToken( $token );
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_string( $token ) || trim( $token ) === '' ) {
|
||||
$tokenError = 'No token found. Set one in config.php or SPACETRADERS_TOKEN.';
|
||||
}
|
||||
|
||||
if (! isset( $tokenError ) ) {
|
||||
$client = new SpacetradersApi(
|
||||
trim( $token ),
|
||||
$config['api_base_url'],
|
||||
(int) $config['api_timeout'],
|
||||
$storage,
|
||||
(int) $config['cache_ttl']
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
if (! isset( $tokenError ) ) {
|
||||
$shipListResponse = $client->listMyShips();
|
||||
$shipList = $shipListResponse['data'] ?? array();
|
||||
|
||||
if ($shipSymbol === '' && ! empty( $shipList ) ) {
|
||||
$shipSymbol = (string) ( $shipList[0]['symbol'] ?? '' );
|
||||
}
|
||||
|
||||
if ($shipSymbol !== '' ) {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['ship_action'] ) ) {
|
||||
$action = (string) $_POST['ship_action'];
|
||||
switch ($action) {
|
||||
case 'orbit':
|
||||
$client->orbitShip( $shipSymbol );
|
||||
$statusMessage = 'Ship set to orbit.';
|
||||
break;
|
||||
case 'dock':
|
||||
$client->dockShip( $shipSymbol );
|
||||
$statusMessage = 'Ship docked.';
|
||||
break;
|
||||
case 'extract':
|
||||
$client->extractResources( $shipSymbol );
|
||||
$statusMessage = 'Resource extraction started.';
|
||||
break;
|
||||
case 'survey':
|
||||
$client->surveyWaypoint( $shipSymbol );
|
||||
$statusMessage = 'Survey completed.';
|
||||
break;
|
||||
case 'siphon':
|
||||
$client->siphonResources( $shipSymbol );
|
||||
$statusMessage = 'Siphon action completed.';
|
||||
break;
|
||||
case 'refuel':
|
||||
$client->refuelShip( $shipSymbol );
|
||||
$statusMessage = 'Ship refueled.';
|
||||
break;
|
||||
case 'sell_all_cargo':
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException( 'Ship is in transit and cannot sell cargo right now.' );
|
||||
}
|
||||
|
||||
if ($shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$soldItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$soldItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Continue selling other items.
|
||||
}
|
||||
}
|
||||
|
||||
$statusMessage = 'Attempted to sell all cargo item types. Sold: ' . $soldItems . '.';
|
||||
break;
|
||||
case 'sell_cargo_item':
|
||||
$tradeSymbol = trim( (string) ( $_POST['trade_symbol'] ?? '' ) );
|
||||
$units = (int) ( $_POST['units'] ?? 0 );
|
||||
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
throw new SpacetradersApiException( 'Trade symbol and units are required to sell cargo.' );
|
||||
}
|
||||
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException( 'Ship is in transit and cannot sell cargo right now.' );
|
||||
}
|
||||
|
||||
if ($shipStatus !== 'DOCKED' ) {
|
||||
$client->dockShip( $shipSymbol );
|
||||
}
|
||||
|
||||
$client->sellCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$statusMessage = 'Sold ' . number_format( $units ) . ' units of ' . $tradeSymbol . '.';
|
||||
break;
|
||||
case 'jettison_all_cargo':
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException( 'Ship is in transit and cannot jettison cargo right now.' );
|
||||
}
|
||||
|
||||
$inventory = (array) ( $shipData['cargo']['inventory'] ?? array() );
|
||||
$jettisonedItems = 0;
|
||||
foreach ( $inventory as $item ) {
|
||||
$tradeSymbol = (string) ( $item['symbol'] ?? '' );
|
||||
$units = (int) ( $item['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$client->jettisonCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$jettisonedItems++;
|
||||
} catch (SpacetradersApiException $e) {
|
||||
// Continue attempting the rest.
|
||||
}
|
||||
}
|
||||
|
||||
$statusMessage = 'Attempted to jettison all cargo item types. Jettisoned: ' . $jettisonedItems . '.';
|
||||
break;
|
||||
case 'jettison_cargo_item':
|
||||
$tradeSymbol = trim( (string) ( $_POST['trade_symbol'] ?? '' ) );
|
||||
$units = (int) ( $_POST['units'] ?? 0 );
|
||||
if ($tradeSymbol === '' || $units <= 0 ) {
|
||||
throw new SpacetradersApiException( 'Trade symbol and units are required to jettison cargo.' );
|
||||
}
|
||||
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$shipData = $shipResponse['data'] ?? array();
|
||||
$shipStatus = (string) ( $shipData['nav']['status'] ?? '' );
|
||||
if ($shipStatus === 'IN_TRANSIT' ) {
|
||||
throw new SpacetradersApiException( 'Ship is in transit and cannot jettison cargo right now.' );
|
||||
}
|
||||
|
||||
$client->jettisonCargo( $shipSymbol, $tradeSymbol, $units );
|
||||
$statusMessage = 'Jettisoned ' . number_format( $units ) . ' units of ' . $tradeSymbol . '.';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($statusMessage !== '' ) {
|
||||
$storage->clearAllCache();
|
||||
}
|
||||
}
|
||||
|
||||
$shipResponse = $client->getShip( $shipSymbol );
|
||||
$ship = $shipResponse['data'] ?? $shipResponse;
|
||||
}
|
||||
}
|
||||
} catch (SpacetradersApiException $e) {
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Spacetraders - Ship Details</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body class="container mx-auto px-4 py-8 bg-stone-800 text-gray-200">
|
||||
<div class="mb-6 flex gap-4">
|
||||
<a href="agent-info.php" class="text-blue-400 hover:underline">Agent Info</a>
|
||||
<a href="mining-fleet.php" class="text-blue-400 hover:underline">Mining Fleet</a>
|
||||
<a href="buy-ships.php" class="text-blue-400 hover:underline">Buy Ships</a>
|
||||
<a href="config.php" class="text-blue-400 hover:underline">Configuration</a>
|
||||
</div>
|
||||
|
||||
<h1 class="text-3xl font-bold mb-6 underline decoration-gray-300 w-full">Ship Details</h1>
|
||||
|
||||
<?php if (isset( $tokenError ) ) : ?>
|
||||
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $tokenError ); ?>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
<?php exit; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($errorMessage !== '' ) : ?>
|
||||
<div class="mb-6 border border-red-500 p-4 rounded text-red-300">
|
||||
<?php echo htmlspecialchars( $errorMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($statusMessage !== '' ) : ?>
|
||||
<div class="mb-6 border border-green-500 p-4 rounded text-green-300">
|
||||
<?php echo htmlspecialchars( $statusMessage ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="get" class="mb-6 flex items-end gap-3">
|
||||
<div>
|
||||
<label for="ship" class="block text-sm mb-1">Choose Ship</label>
|
||||
<select id="ship" name="ship" class="px-3 py-2 rounded text-black min-w-64">
|
||||
<?php foreach ( $shipList as $listShip ) : ?>
|
||||
<?php $listSymbol = (string) ( $listShip['symbol'] ?? '' ); ?>
|
||||
<option value="<?php echo htmlspecialchars( $listSymbol ); ?>" <?php echo ( $listSymbol === $shipSymbol ) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars( $listSymbol ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="px-4 py-2 bg-blue-600 rounded hover:bg-blue-500">View</button>
|
||||
</form>
|
||||
|
||||
<?php if (! empty( $ship ) ) : ?>
|
||||
<?php
|
||||
$shipRole = strtoupper( (string) ( $ship['registration']['role'] ?? '' ) );
|
||||
$shipStatus = (string) ( $ship['nav']['status'] ?? '' );
|
||||
$fuelCurrent = (int) ( $ship['fuel']['current'] ?? 0 );
|
||||
$fuelCapacity = (int) ( $ship['fuel']['capacity'] ?? 0 );
|
||||
$showRefuel = $fuelCapacity > 0 && $fuelCurrent < $fuelCapacity;
|
||||
?>
|
||||
<div class="mb-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-3">Ship Controls</h2>
|
||||
<form method="post" class="flex flex-wrap gap-2">
|
||||
<?php if ($shipStatus === 'DOCKED' ) : ?>
|
||||
<button type="submit" name="ship_action" value="orbit" class="px-3 py-1 bg-blue-600 rounded hover:bg-blue-500">Orbit</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($shipStatus !== 'DOCKED' && $shipStatus !== 'IN_TRANSIT' ) : ?>
|
||||
<button type="submit" name="ship_action" value="dock" class="px-3 py-1 bg-blue-600 rounded hover:bg-blue-500">Dock</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($shipRole === 'EXCAVATOR' ) : ?>
|
||||
<button type="submit" name="ship_action" value="extract" class="px-3 py-1 bg-emerald-700 rounded hover:bg-emerald-600">Mine (Extract)</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($shipRole === 'SURVEYOR' ) : ?>
|
||||
<button type="submit" name="ship_action" value="survey" class="px-3 py-1 bg-indigo-700 rounded hover:bg-indigo-600">Survey</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($shipRole === 'EXCAVATOR' ) : ?>
|
||||
<button type="submit" name="ship_action" value="siphon" class="px-3 py-1 bg-cyan-700 rounded hover:bg-cyan-600">Siphon</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($showRefuel ) : ?>
|
||||
<button type="submit" name="ship_action" value="refuel" class="px-3 py-1 bg-amber-700 rounded hover:bg-amber-600">Refuel</button>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( (int) ( $ship['cargo']['units'] ?? 0 ) > 0 ) : ?>
|
||||
<button type="submit" name="ship_action" value="sell_all_cargo" class="px-3 py-1 bg-rose-700 rounded hover:bg-rose-600">Sell All Cargo</button>
|
||||
<button type="submit" name="ship_action" value="jettison_all_cargo" class="px-3 py-1 bg-red-800 rounded hover:bg-red-700">Jettison All Cargo</button>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
<p class="mt-2 text-sm text-gray-300">
|
||||
Role: <?php echo htmlspecialchars( $shipRole ); ?> |
|
||||
Status: <?php echo htmlspecialchars( $shipStatus ); ?> |
|
||||
Fuel: <?php echo number_format( $fuelCurrent ); ?>/<?php echo number_format( $fuelCapacity ); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Overview</h2>
|
||||
<p><span class="font-bold">Symbol:</span> <?php echo htmlspecialchars( (string) ( $ship['symbol'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Name:</span> <?php echo htmlspecialchars( (string) ( $ship['registration']['name'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Role:</span> <?php echo htmlspecialchars( (string) ( $ship['registration']['role'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Faction:</span> <?php echo htmlspecialchars( (string) ( $ship['registration']['factionSymbol'] ?? '' ) ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Navigation</h2>
|
||||
<p><span class="font-bold">Status:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['status'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Flight Mode:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['flightMode'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">System:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['systemSymbol'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Waypoint:</span> <?php echo htmlspecialchars( (string) ( $ship['nav']['waypointSymbol'] ?? '' ) ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Frame / Engine / Reactor</h2>
|
||||
<p><span class="font-bold">Frame:</span> <?php echo htmlspecialchars( (string) ( $ship['frame']['name'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Engine:</span> <?php echo htmlspecialchars( (string) ( $ship['engine']['name'] ?? '' ) ); ?></p>
|
||||
<p><span class="font-bold">Reactor:</span> <?php echo htmlspecialchars( (string) ( $ship['reactor']['name'] ?? '' ) ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Cargo / Fuel</h2>
|
||||
<p><span class="font-bold">Cargo:</span> <?php echo number_format( (int) ( $ship['cargo']['units'] ?? 0 ) ); ?> / <?php echo number_format( (int) ( $ship['cargo']['capacity'] ?? 0 ) ); ?></p>
|
||||
<p><span class="font-bold">Fuel:</span> <?php echo number_format( (int) ( $ship['fuel']['current'] ?? 0 ) ); ?> / <?php echo number_format( (int) ( $ship['fuel']['capacity'] ?? 0 ) ); ?></p>
|
||||
<p><span class="font-bold">Cooldown Remaining:</span> <?php echo number_format( (int) ( $ship['cooldown']['remainingSeconds'] ?? 0 ) ); ?>s</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Mounts</h2>
|
||||
<?php $mounts = (array) ( $ship['mounts'] ?? array() ); ?>
|
||||
<?php if (empty( $mounts ) ) : ?>
|
||||
<p class="text-gray-300">No mounts equipped.</p>
|
||||
<?php else : ?>
|
||||
<ul class="list-disc list-inside">
|
||||
<?php foreach ( $mounts as $mount ) : ?>
|
||||
<li><?php echo htmlspecialchars( (string) ( $mount['name'] ?? $mount['symbol'] ?? '' ) ); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Modules</h2>
|
||||
<?php $modules = (array) ( $ship['modules'] ?? array() ); ?>
|
||||
<?php if (empty( $modules ) ) : ?>
|
||||
<p class="text-gray-300">No modules installed.</p>
|
||||
<?php else : ?>
|
||||
<ul class="list-disc list-inside">
|
||||
<?php foreach ( $modules as $module ) : ?>
|
||||
<li><?php echo htmlspecialchars( (string) ( $module['name'] ?? $module['symbol'] ?? '' ) ); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 border border-gray-600 rounded p-4">
|
||||
<h2 class="text-xl font-bold mb-2">Cargo Inventory</h2>
|
||||
<?php $inventory = (array) ( $ship['cargo']['inventory'] ?? array() ); ?>
|
||||
<?php if (empty( $inventory ) ) : ?>
|
||||
<p class="text-gray-300">Cargo hold is empty.</p>
|
||||
<?php else : ?>
|
||||
<table class="table-auto border-collapse border border-gray-300 w-full">
|
||||
<tr>
|
||||
<th class="border border-gray-300 px-3 py-2">Symbol</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Name</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Units</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Description</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Sell</th>
|
||||
<th class="border border-gray-300 px-3 py-2">Jettison</th>
|
||||
</tr>
|
||||
<?php foreach ( $inventory as $item ) : ?>
|
||||
<?php $itemUnits = (int) ( $item['units'] ?? 0 ); ?>
|
||||
<tr>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $item['name'] ?? '' ) ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo number_format( $itemUnits ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2"><?php echo htmlspecialchars( (string) ( $item['description'] ?? '' ) ); ?></td>
|
||||
<td class="border border-gray-300 px-3 py-2">
|
||||
<?php if ($itemUnits > 0 ) : ?>
|
||||
<form method="post" class="flex items-center gap-2">
|
||||
<input type="hidden" name="ship_action" value="sell_cargo_item">
|
||||
<input type="hidden" name="trade_symbol" value="<?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?>">
|
||||
<input
|
||||
type="number"
|
||||
name="units"
|
||||
value="<?php echo (int) $itemUnits; ?>"
|
||||
min="1"
|
||||
max="<?php echo (int) $itemUnits; ?>"
|
||||
class="w-24 px-2 py-1 rounded text-black"
|
||||
>
|
||||
<button type="submit" class="px-3 py-1 bg-rose-700 rounded hover:bg-rose-600">Sell</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="border border-gray-300 px-3 py-2">
|
||||
<?php if ($itemUnits > 0 ) : ?>
|
||||
<form method="post" class="flex items-center gap-2">
|
||||
<input type="hidden" name="ship_action" value="jettison_cargo_item">
|
||||
<input type="hidden" name="trade_symbol" value="<?php echo htmlspecialchars( (string) ( $item['symbol'] ?? '' ) ); ?>">
|
||||
<input
|
||||
type="number"
|
||||
name="units"
|
||||
value="<?php echo (int) $itemUnits; ?>"
|
||||
min="1"
|
||||
max="<?php echo (int) $itemUnits; ?>"
|
||||
class="w-24 px-2 py-1 rounded text-black"
|
||||
>
|
||||
<button type="submit" class="px-3 py-1 bg-red-800 rounded hover:bg-red-700">Jettison</button>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user