Implement fuel consumption mechanic

Front-end only for now
This commit is contained in:
Aelita4 2025-02-04 16:47:15 +01:00
parent d664fc00ef
commit 848f2c37dc
Signed by: Aelita4
GPG Key ID: E44490C2025906C1
4 changed files with 271 additions and 21 deletions

View File

@ -67,7 +67,7 @@ if(!(planet instanceof SystemManager)) {
</div>
</div>
{resourceArray.map(res =>
<div class="resourcebar-item resourcebar-iterable"
<div class="resourcebar-item resourcebar-iterable" id={`resource-${res.id}`}
data-res-type={resourceTypes.find(x => x.id === res.id)?.type ?? "solid"}
data-res-id={res.id}
data-res-amount={res.amount}

View File

@ -0,0 +1,50 @@
import { APIRoute } from "astro";
import parseParams from "../../../lib/utils/parseParams";
import locationManager, { Sector } from "../../../lib/classes/managers/LocationManager";
import SystemManager from "../../../lib/classes/managers/SystemManager";
import { Planet } from "../../../lib/classes/managers/PlanetManager";
import getDistanceBetween from "../../../lib/utils/getDistanceBetween";
export const GET: APIRoute = async({ request }) => {
const URLParams = parseParams(request.url);
if(!URLParams.source || !URLParams.destination) {
return new Response(
JSON.stringify({
code: 400,
message: "Bad Request",
error: "Missing parameters"
}), { status: 400 }
);
}
const source = locationManager.findId(URLParams.source);
if(source === null) {
return new Response(
JSON.stringify({
code: 404,
message: "Not Found",
error: "Source not found"
}), { status: 404 }
);
}
let destination: Planet | SystemManager | Sector | null = locationManager.findId(URLParams.destination);
if(destination === null) destination = locationManager.getSector(URLParams.destination) ?? null;
if(destination === null) {
return new Response(
JSON.stringify({
code: 404,
message: "Not Found",
error: "Destination not found"
}), { status: 404 }
);
}
return new Response(
JSON.stringify({
code: 200,
message: "OK",
distance: getDistanceBetween(source, destination)
}), { status: 200 }
)
}

View File

@ -11,6 +11,7 @@ import { getName } from '../../lib/utils/langDriver';
const { token, user, lang } = Astro.locals;
const active: SystemManager | Planet = Astro.locals.active;
const activeId = active instanceof SystemManager ? active.data._id : active._id;
const ships = await getAllShips();
const url = Astro.url.origin;
@ -82,10 +83,10 @@ for(const f of fleet) {
if(source !== null) {
if(source instanceof SystemManager) {
if(source.data.ownedBy.id.equals(user.id)) own++;
else enemy++;
else if(!f.returning) enemy++;
} else {
if(source.system.data.ownedBy.id.equals(user.id)) own++;
else enemy++;
else if(!f.returning) enemy++;
}
}
}
@ -152,14 +153,14 @@ const sectorsList = galaxies.map(galaxy => {
</div>
</label>
<div class="fleet-send-container">
<form method="post">
<form method="post" id="send-fleet">
<h1>Sending fleet from {active instanceof SystemManager ? active.data.name : active.name}</h1>
<hr />
<h2>Ships</h2>
<div class="fleet-send-ships">
{active.ships.ships.map(ship => <div class="fleet-ship-card">
<h3>{getName(lang, 'ships', ship.data.id)} - {ship.amount}</h3>
<input type="number" value="0" min="0" max={ship.amount} id={ship.data.id} name={`ship-amount-${ship.data.id}`} />
<input type="number" value="0" min="0" max={ship.amount} id={ship.data.id} name={`ship-amount-${ship.data.id}`} class="ship-amount-inputs" />
</div>)}
</div>
<hr />
@ -171,24 +172,37 @@ const sectorsList = galaxies.map(galaxy => {
<label for="spy"><input type="radio" name="mission" value="SPY" id="spy" />Spying</label>
<label><input type="checkbox" name="toSystem" />Send to system</label>
<hr />
<h2>Send to:</h2>
<h2>Send to</h2>
<div class="fleet-destination">
<div>
<h3>Galaxy</h3>
<select id="destination-galaxy" name="destination-galaxy">
{galaxies.map(galaxy => <option value={galaxy._id.toString()}>{galaxy.name}</option>)}
</select>
</div>
<div>
<h3>Sector</h3>
<select id="destination-sector" name="destination-sector"></select>
</div>
<div>
<h3>System</h3>
<select id="destination-system" name="destination-system"></select>
<div id="destination-system-error"></div>
</div>
<div>
<h3>Planet</h3>
<select id="destination-planet" name="destination-planet"></select>
<div id="destination-planet-error"></div>
</div>
</div>
<hr />
<h2>Cargo</h2>
<div class="cargo-container">
<div id="cargo-available">
Solid: <span id="available-solid">0</span><br />
Liquid: <span id="available-liquid">0</span><br />
Gas: <span id="available-gas">0</span><br />
</div>
<div class="cargo-container" id="cargo-container">
<div class="cargo-item">
<select name="cargo[0][id]" class="select">
<option value="coal">Coal</option>
@ -207,6 +221,15 @@ const sectorsList = galaxies.map(galaxy => {
</div>
<div id="cargo-add-new">Add new +</div>
<hr />
<h2>Fuel consumption</h2>
<div>Base usage from ships: <span id="fuel-consumption">0</span></div>
<div>Distance: <span id="fuel-consumption-distance">0</span></div>
<div><span id="fuel-consumption-required">0</span> hydrogen will be added to cargo as fuel</div>
<hr />
<h2>Estimates</h2>
<div>Fleet will arrive at destination at: <span id="arrival-time"></span></div>
<div>Fleet will return at: <span id="return-time"></span></div>
<hr />
<button type="submit">Send fleet</button>
</form>
</div>
@ -318,6 +341,12 @@ label {
color: black;
}
.fleet-destination {
display: flex;
flex-direction: row;
column-gap: 5%;
}
.fleet-destination select {
width: 10rem;
height: 3rem;
@ -337,7 +366,7 @@ label {
color: black;
}
</style>
<script define:vars={{ lang, sectorsList, url }}>
<script define:vars={{ lang, sectorsList, url, ships, activeId }}>
const revertButtons = document.querySelectorAll('.revert');
const destinationGalaxy = document.getElementById('destination-galaxy');
const destinationSector = document.getElementById('destination-sector');
@ -345,8 +374,10 @@ label {
const destinationPlanet = document.getElementById('destination-planet');
const toSystemCheckbox = document.querySelector('input[name="toSystem"]');
const sendAllButtons = document.querySelectorAll('.cargo-sendall');
const shipInputs = document.querySelectorAll('.ship-amount-inputs');
const sendFleetForm = document.getElementById('send-fleet');
if(!revertButtons || !destinationGalaxy || !destinationSector || !destinationSystem || !destinationPlanet || !toSystemCheckbox || !sendAllButtons) {
if(!revertButtons || !destinationGalaxy || !destinationSector || !destinationSystem || !destinationPlanet || !toSystemCheckbox || !sendAllButtons || !shipInputs || !sendFleetForm) {
console.error('Could not find all elements');
return;
};
@ -449,12 +480,17 @@ label {
opt.innerText = 'No planets';
destinationPlanet.appendChild(opt);
}
destinationPlanet.dispatchEvent(new Event('change'));
});
destinationPlanet.addEventListener('change', calculateDistance);
destinationGalaxy.dispatchEvent(new Event('change'));
toSystemCheckbox.addEventListener('change', () => {
destinationPlanet.disabled = toSystemCheckbox.checked;
calculateDistance();
});
sendAllButtons.forEach(button => {
@ -495,6 +531,169 @@ label {
cargoContainer.appendChild(cargoItem);
});
shipInputs.forEach(input => {
input.addEventListener('input', () => {
const fuelConsumption = Array.from(shipInputs).reduce((acc, cur) => {
const ship = ships.find(ship => ship.id === cur.id);
if(!ship) return acc;
return acc + ship.fuelConsumption * parseInt(cur.value);
}, 0);
document.getElementById('fuel-consumption').innerText = fuelConsumption;
const availableSolid = Array.from(shipInputs).reduce((acc, cur) => {
const ship = ships.find(ship => ship.id === cur.id);
if(!ship) return acc;
return acc + ship.capacity.solid * parseInt(cur.value);
}, 0);
const availableLiquid = Array.from(shipInputs).reduce((acc, cur) => {
const ship = ships.find(ship => ship.id === cur.id);
if(!ship) return acc;
return acc + ship.capacity.liquid * parseInt(cur.value);
}, 0);
const availableGas = Array.from(shipInputs).reduce((acc, cur) => {
const ship = ships.find(ship => ship.id === cur.id);
if(!ship) return acc;
return acc + ship.capacity.gas * parseInt(cur.value);
}, 0);
document.getElementById('available-solid').innerText = availableSolid;
document.getElementById('available-liquid').innerText = availableLiquid;
document.getElementById('available-gas').innerText = availableGas;
calculateRequiredFuel();
});
});
sendFleetForm.addEventListener('submit', evt => {
evt.preventDefault();
// at least one ship
if(Array.from(shipInputs).reduce((acc, cur) => acc + parseInt(cur.value), 0) === 0) {
alert('You need to send at least one ship');
return;
}
// source === destination
const destinationId = document.querySelector('input[name="toSystem"]').checked ? document.getElementById('destination-system').value : document.getElementById('destination-planet').value;
if(destinationId === activeId) {
alert('Source and destination cannot be the same');
return;
}
// check fuel
const requiredFuel = parseInt(document.getElementById('fuel-consumption-required').innerText);
const storedFuel = parseInt(document.getElementById('resource-hydrogen').dataset.resAmount);
if(storedFuel < requiredFuel) {
alert('Not enough fuel in storage');
return;
}
const cargoSolidStored = Array.from(document.getElementById('cargo-container').children).reduce((acc, cur) => {
const resId = cur.children.item(0).value;
if(resId === "coal" || resId === "iron" || resId === "gold") {
const amount = cur.children.item(1).value === "" ? 0 : parseInt(cur.children.item(1).value);
return acc + amount;
}
return acc;
}, 0);
const cargoLiquidStored = Array.from(document.getElementById('cargo-container').children).reduce((acc, cur) => {
const resId = cur.children.item(0).value;
if(resId === "water" || resId === "sulfuric-acid" || resId === "liquid-nitrogen") {
const amount = cur.children.item(1).value === "" ? 0 : parseInt(cur.children.item(1).value);
return acc + amount;
}
return acc;
}, 0);
const cargoGasStored = Array.from(document.getElementById('cargo-container').children).reduce((acc, cur) => {
const resId = cur.children.item(0).value;
if(resId === "hydrogen" || resId === "oxygen" || resId === "helium-3") {
const amount = cur.children.item(1).value === "" ? 0 : parseInt(cur.children.item(1).value);
return acc + amount;
}
return acc;
}, 0);
const cargoSolidCapacity = document.getElementById('available-solid').innerText;
const cargoLiquidCapacity = document.getElementById('available-liquid').innerText;
const cargoGasCapacity = document.getElementById('available-gas').innerText;
if(cargoSolidStored > cargoSolidCapacity) {
alert('Not enough solid capacity in ships');
return;
}
if(cargoLiquidStored > cargoLiquidCapacity) {
alert('Not enough liquid capacity in ships');
return;
}
if(cargoGasStored > cargoGasCapacity) {
alert('Not enough gas capacity in ships');
return;
}
if((cargoGasStored + requiredFuel) > cargoGasCapacity) {
alert('Not enough gas capacity in ships for fuel');
return;
}
// add hydrogen to cargo
// const hydrogenInCargo = Array.from(document.getElementById('cargo-container').children).find(c => c.children.item(0).value === "hydrogen")?.children.item(1).value ?? 0;
// const formData = new FormData(evt.target);
sendFleetForm.submit();
});
async function calculateDistance() {
const source = activeId;
const destination = document.querySelector('input[name="toSystem"]').checked ? document.getElementById('destination-system').value : document.getElementById('destination-planet').value;
if(!source || !destination) return;
const response = await fetch(`${url}/api/fleet/getDistance?source=${source}&destination=${destination}`);
const data = await response.json();
if(data.error) {
document.getElementById('fuel-consumption-distance').innerText = "Error";
return;
}
const distance = data.distance;
document.getElementById('fuel-consumption-distance').innerText = distance;
document.getElementById('arrival-time').innerText = new Date(new Date().getTime() + distance * 1000).toLocaleString();
document.getElementById('return-time').innerText = new Date(new Date().getTime() + distance * 1000 * 2).toLocaleString();
calculateRequiredFuel();
}
function calculateRequiredFuel() {
const fuelConsumption = parseInt(document.getElementById('fuel-consumption').innerText);
const distance = parseInt(document.getElementById('fuel-consumption-distance').innerText);
if(isNaN(fuelConsumption) || isNaN(distance)) {
document.getElementById('fuel-consumption-required').innerText = "Error";
return;
}
if(distance === 0) {
document.getElementById('fuel-consumption-required').innerText = 0;
return;
}
const requiredFuel = Math.ceil(Math.log(fuelConsumption * distance) / Math.log(1.01));
document.getElementById('fuel-consumption-required').innerText = requiredFuel;
}
function handleAllClick(button) {
const avaliableResources = [];
for(const resItem of document.querySelectorAll('.resourcebar-item')) {

View File

@ -20,4 +20,5 @@ export default interface DBShip {
attack: number;
};
speed: number;
fuelConsumption: number;
}