diff --git a/data/lang/ui-core/en.json b/data/lang/ui-core/en.json index 40b35b9fc3..bc28a623a2 100644 --- a/data/lang/ui-core/en.json +++ b/data/lang/ui-core/en.json @@ -2690,5 +2690,9 @@ "ZOOM": { "description": "Label for a zoom (magnification) control bar.", "message": "Zoom" + }, + "TRANSFER_FUEL": { + "description": "Label indicating the ability to transfer fuel between equipment tanks", + "message": "Transfer Fuel" } } diff --git a/data/libs/EquipSet.lua b/data/libs/EquipSet.lua index 9304729636..8e4d017827 100644 --- a/data/libs/EquipSet.lua +++ b/data/libs/EquipSet.lua @@ -16,7 +16,7 @@ local utils = require 'utils' ---@field New fun(ship: Ship): EquipSet local EquipSet = utils.class("EquipSet") ----@alias EquipSet.Listener fun(op: 'install'|'remove', equip: EquipType, slot: HullConfig.Slot?) +---@alias EquipSet.Listener fun(op: 'install'|'remove'|'modify', equip: EquipType, slot: HullConfig.Slot?) -- Function: SlotTypeMatches -- @@ -419,6 +419,18 @@ function EquipSet:RemoveListener(fun) utils.remove_elem(self.listeners, fun) end +-- Method: NotifyListeners +-- +-- Send a notification event to listeners. +---@param op string The type of event to send. +---@param equipment EquipType The equipment item generating the event +---@param slot HullConfig.Slot? The slot handle on this EquipSet that is relevant to the event +function EquipSet:NotifyListeners(op, equipment, slot) + for _, listener in ipairs(self.listeners) do + listener(op, equipment, slot) + end +end + -- Method: Install -- -- Install an equipment item in the given slot or in free equipment volume. diff --git a/data/libs/EquipType.lua b/data/libs/EquipType.lua index 989feb2936..de0be386f0 100644 --- a/data/libs/EquipType.lua +++ b/data/libs/EquipType.lua @@ -344,53 +344,146 @@ end --============================================================================== --- Single drive type, no support for slave drives. +-- Class: HyperdriveType +-- +-- HyperdriveType is responsible for most logic related to computing a hyperspace jump. +-- The actual logic for executing the jump is delegated to Ship, but the drive is responsible +-- for checking that a jump is possible and deducting fuel. +-- +-- Note that no attempt is made to model multiple hyperdrives, including backup drives; +-- redundancy in hyperdrives should be achieved by repairing the existing drive or installing +-- a replacement drive from the ship's stores while underway. +-- ---@class Equipment.HyperdriveType : EquipType ---@field fuel CommodityType ---@field byproduct CommodityType? local HyperdriveType = utils.inherits(EquipType, "Equipment.HyperdriveType") +HyperdriveType.storedFuel = 0.0 + +-- Static factors +HyperdriveType.factor_eff = 55 +HyperdriveType.factor_time = 1.0 +HyperdriveType.fuel_resv_size = 1.0 + +-- Travel time exponents +local range_exp = 1.6 +local mass_exp = 1.2 +-- Fuel use exponents +local fuel_use_exp = 0.9 +local fuel_use_exp_inv = 1.0 / 0.9 + +---@param ship Ship +---@param extraMass number Additional mass beyond current lading to include in calculation +function HyperdriveType:GetEfficiencyTerm(ship, extraMass) + return self.factor_eff / (ship.staticMass + ship.fuelMassLeft + extraMass)^(3/5) * (1 + self.capabilities.hyperclass) / self.capabilities.hyperclass +end + +-- Function: GetMaximumRange +-- +-- Returns the maximum range of the hyperdrive under their current lading state of the ship. +---@param ship Ship function HyperdriveType:GetMaximumRange(ship) - return 625.0*(self.capabilities.hyperclass ^ 2) / (ship.staticMass + ship.fuelMassLeft) + -- Account for the extra mass needed to reach full fuel state + local E = self:GetEfficiencyTerm(ship, self.fuel_resv_size - self.storedFuel) + return (self.fuel_resv_size * E)^fuel_use_exp_inv +end + +-- Function: GetFuelUse +-- +-- Returns the fuel consumed by the drive in attempting a jump of the specified distance. +---@param ship Ship +---@param distance number Distance to jump, in light years +---@return number fuelUsed Amount of fuel used, in tons +function HyperdriveType:GetFuelUse(ship, distance) + return distance^fuel_use_exp / self:GetEfficiencyTerm(ship, 0) end --- range_max is as usual optional +-- Function: GetDuration +-- +-- Returns the duration taken for a jump of the specified distance. +---@param ship Ship +---@param distance number Distance to jump, in light years +---@return number duration Duration of the jump, in seconds function HyperdriveType:GetDuration(ship, distance, range_max) - range_max = range_max or self:GetMaximumRange(ship) - local hyperclass = self.capabilities.hyperclass - return 0.36*distance^2/(range_max*hyperclass) * (86400*math.sqrt(ship.staticMass + ship.fuelMassLeft)) + local mass = ship.staticMass + ship.fuelMassLeft + return 86400 * 0.36 * (distance^range_exp * mass^mass_exp) / (425 * self.capabilities.hyperclass^2 * self.factor_time) +end + +-- Function: GetRange +-- +-- Return the current jump range of the ship given the current fuel state, +-- and the maximum jump range of the ship at its current lading if the drive were fully fueled. +---@param ship Ship +---@return number currentRange +---@return number maxRange +function HyperdriveType:GetRange(ship) + local E, E1 = self:GetEfficiencyTerm(ship, 0), self:GetEfficiencyTerm(ship, self.fuel_resv_size - self.storedFuel) + return (self.storedFuel * E)^fuel_use_exp_inv, (self.fuel_resv_size * E1)^fuel_use_exp_inv end --- range_max is optional, distance defaults to the maximal range. -function HyperdriveType:GetFuelUse(ship, distance, range_max) - range_max = range_max or self:GetMaximumRange(ship) - local distance = distance or range_max - local hyperclass_squared = self.capabilities.hyperclass^2 - return math.clamp(math.ceil(hyperclass_squared*distance / range_max), 1, hyperclass_squared); +-- Function: SetFuel +-- +-- Update the amount of fuel stored in the drive's internal reservoir. +-- The amount of fuel must be equal to or less than the fuel_resv_size of the drive. +---@param ship Ship? The ship this hyperdrive is installed in, or nil if the hyperdrive is not yet installed +---@param newFuel number The fuel amount stored in the hyperdrive's reservoir, in tons +function HyperdriveType:SetFuel(ship, newFuel) + assert(newFuel >= 0 and newFuel <= self.fuel_resv_size) + + local massDiff = newFuel - self.storedFuel + self.storedFuel = newFuel + self.mass = self.mass + massDiff + + if ship then + ship:setprop("mass_cap", ship["mass_cap"] + massDiff) + ship:UpdateEquipStats() + + ship:GetComponent('EquipSet'):NotifyListeners('modify', self) + end end +-- Function: GetMaxFuel +-- +-- Return the maximum fuel capacity of the drive, in tons. +function HyperdriveType:GetMaxFuel() + return self.fuel_resv_size +end + +-- Function: CheckJump +-- +-- Checks the viability of a potential jump from are source SystemPath to a destination SystemPath. +-- -- if the destination is reachable, returns: distance, fuel, duration -- if the destination is out of range, returns: distance -- if the specified jump is invalid, returns nil +---@param ship Ship +---@param source SystemPath +---@param destination SystemPath function HyperdriveType:CheckJump(ship, source, destination) if ship:GetInstalledHyperdrive() ~= self or source:IsSameSystem(destination) then return nil end local distance = source:DistanceTo(destination) - local max_range = self:GetMaximumRange(ship) -- takes fuel into account + local max_range = self:GetRange(ship) -- takes fuel into account if distance > max_range then return distance end - local fuel = self:GetFuelUse(ship, distance, max_range) -- specify range_max to avoid unnecessary recomputing. + local fuel = self:GetFuelUse(ship, distance) local duration = self:GetDuration(ship, distance, max_range) -- same as above return distance, fuel, duration end --- like HyperdriveType.CheckJump, but uses Game.system as the source system +-- Function: CheckDestination +-- +-- Like HyperdriveType.CheckJump, but uses Game.system as the source system +-- -- if the destination is reachable, returns: distance, fuel, duration -- if the destination is out of range, returns: distance -- if the specified jump is invalid, returns nil +---@param ship Ship +---@param destination SystemPath function HyperdriveType:CheckDestination(ship, destination) if not Game.system then return nil @@ -398,30 +491,6 @@ function HyperdriveType:CheckDestination(ship, destination) return self:CheckJump(ship, Game.system.path, destination) end --- Give the range for the given remaining fuel --- If the fuel isn't specified, it takes the current value. -function HyperdriveType:GetRange(ship, remaining_fuel) - local range_max = self:GetMaximumRange(ship) - local fuel_max = self:GetFuelUse(ship, range_max, range_max) - - ---@type CargoManager - local cargoMgr = ship:GetComponent('CargoManager') - remaining_fuel = remaining_fuel or cargoMgr:CountCommodity(self.fuel) - - if fuel_max <= remaining_fuel then - return range_max, range_max - end - local range = range_max*remaining_fuel/fuel_max - - while range > 0 and self:GetFuelUse(ship, range, range_max) > remaining_fuel do - range = range - 0.05 - end - - -- range is never negative - range = math.max(range, 0) - return range, range_max -end - local HYPERDRIVE_SOUNDS_NORMAL = { warmup = "Hyperdrive_Charge", abort = "Hyperdrive_Abort", @@ -434,6 +503,11 @@ local HYPERDRIVE_SOUNDS_MILITARY = { jump = "Hyperdrive_Jump_Military", } +-- Function: HyperjumpTo +-- +-- Perform safety checks and initiate a hyperjump to the destination system +---@param ship Ship +---@param destination SystemPath function HyperdriveType:HyperjumpTo(ship, destination) -- First off, check that this is the primary engine. -- NOTE: this enforces the constraint that only one hyperdrive may be installed on a ship @@ -463,17 +537,23 @@ function HyperdriveType:HyperjumpTo(ship, destination) return ship:InitiateHyperjumpTo(destination, warmup_time, duration, sounds), fuel_use, duration end +-- Function: OnLeaveHyperspace +-- +-- Handle cleanup after leaving hyperspace +---@param ship Ship function HyperdriveType:OnLeaveHyperspace(ship) if ship:hasprop('nextJumpFuelUse') then - ---@type CargoManager - local cargoMgr = ship:GetComponent('CargoManager') + local amount = ship['nextJumpFuelUse'] + ship:unsetprop('nextJumpFuelUse') + + self.storedFuel = math.max(0, self.storedFuel - amount) - local amount = ship.nextJumpFuelUse - cargoMgr:RemoveCommodity(self.fuel, amount) if self.byproduct then - cargoMgr:AddCommodity(self.byproduct, amount) + local cargoMgr = ship:GetComponent('CargoManager') + -- TODO: byproduct can be "bypassed" when jumping on a full cargo hold + local byproductAmount = math.min(math.ceil(amount), cargoMgr:GetFreeSpace()) + cargoMgr:AddCommodity(self.byproduct, byproductAmount) end - ship:unsetprop('nextJumpFuelUse') end end diff --git a/data/libs/HullConfig.lua b/data/libs/HullConfig.lua index cbdc9a531b..c88e68ad07 100644 --- a/data/libs/HullConfig.lua +++ b/data/libs/HullConfig.lua @@ -49,12 +49,7 @@ HullConfig.equipCapacity = 0 -- Individual shipdefs can redefine slots or remove them by setting the slot to 'false' ---@type table HullConfig.slots = { - sensor = Slot:clone { type = "sensor", size = 1 }, - computer_1 = Slot:clone { type = "computer", size = 1 }, - hull_mod = Slot:clone { type = "hull", size = 1 }, - structure = Slot:clone { type = "structure", size = 1 }, - hyperdrive = Slot:clone { type = "hyperdrive", size = 1 }, - thruster = Slot:clone { type = "thruster", size = 1 }, + sensor = Slot:clone { type = "sensor", size = 1 }, } function HullConfig:__clone() diff --git a/data/libs/Ship.lua b/data/libs/Ship.lua index 56dda8fb5a..b960dfef4f 100644 --- a/data/libs/Ship.lua +++ b/data/libs/Ship.lua @@ -241,14 +241,11 @@ Ship.GetHyperspaceDetails = function (self, source, destination) local distance, fuel, duration = engine:CheckJump(self, source, destination) local status = "OK" - ---@type CargoManager - local cargoMgr = self:GetComponent('CargoManager') - if not duration then duration = 0 fuel = 0 status = "OUT_OF_RANGE" - elseif fuel > cargoMgr:CountCommodity(engine.fuel) then + elseif fuel > engine.storedFuel then status = "INSUFFICIENT_FUEL" end return status, distance, fuel, duration diff --git a/data/meta/CoreObject/Body.meta.lua b/data/meta/CoreObject/Body.meta.lua index 027f0e523e..4a6f0a19c2 100644 --- a/data/meta/CoreObject/Body.meta.lua +++ b/data/meta/CoreObject/Body.meta.lua @@ -50,6 +50,10 @@ function Body:isa(type) end ---@param value any NOTE: functions, tables, and coroutines cannot be set as body properties function Body:setprop(key, value) end +-- Clears the given body property +---@param key string +function Body:unsetprop(key) end + -- Check if the given property exists on the body ---@param key string ---@return boolean diff --git a/data/modules/Debug/CheckShipData.lua b/data/modules/Debug/CheckShipData.lua index 0f5c2728cb..66c16e9679 100644 --- a/data/modules/Debug/CheckShipData.lua +++ b/data/modules/Debug/CheckShipData.lua @@ -102,6 +102,22 @@ local function checkConfig(config) warn("Ship {id} has no thruster slots. This may break in the future.") end + if utils.count(findMatchingSlots(config, "hull")) == 0 then + info("Ship {id} has no hull modification slots." % config) + end + + if utils.count(findMatchingSlots(config, "structure")) == 0 then + info("Ship {id} has no structural modification slots." % config) + end + + if utils.count(findMatchingSlots(config, "computer")) == 0 then + info("Ship {id} has no computer equipment slots." % config) + end + + if utils.count(findMatchingSlots(config, "sensor")) == 0 then + info("Ship {id} has no sensor slots." % config) + end + -- TODO: more validation passes on the whole ship config end diff --git a/data/modules/Debug/DebugRPG.lua b/data/modules/Debug/DebugRPG.lua index 90d96db84e..d34e8add95 100644 --- a/data/modules/Debug/DebugRPG.lua +++ b/data/modules/Debug/DebugRPG.lua @@ -6,6 +6,7 @@ local Format = require "Format" local ui = require 'pigui' local debugView = require 'pigui.views.debug' local Commodities = require 'Commodities' +local Equipment = require 'Equipment' local amount = 1000 local Legal = require "Legal" @@ -38,9 +39,20 @@ local get_commodities = function() end end -debugView.registerTab("RPG-debug-view", { - icon = ui.theme.icons.money, - label = "RPG", +local equipment = {} +local selected_equip = 0 + +local get_equipment = function() + for id, equip in pairs(Equipment.new) do + table.insert(equipment, { "{} (S{})" % { equip:GetName(), equip.slot and equip.slot.size or "-" }, equip }) + end + + table.sort(equipment, function(a, b) return a[1] < b[1] end) +end + +debugView.registerTab("debug-player", { + icon = ui.theme.icons.personal, + label = "Player Debug", show = function() return Game.player ~= nil end, draw = function() ui.text("State: " .. Game.player:GetFlightState()) @@ -102,6 +114,56 @@ debugView.registerTab("RPG-debug-view", { end end + -- Add equipment + if ui.collapsingHeader("Equipment") then + + if #equipment == 0 then + get_equipment() + end + + local active_equip = equipment[selected_equip] + + ui.comboBox("##Selected", active_equip and active_equip[1] or "", function() + for i, pair in ipairs(equipment) do + if ui.selectable(pair[1], selected_equip == active_equip) then + selected_equip = i + active_equip = pair + end + end + end) + + if active_equip then + + ui.sameLine() + + local equipSet = Game.player:GetComponent('EquipSet') + + local slot = equipSet:GetFreeSlotForEquip(active_equip[2]) + + if ui.button("Install") and slot then + + ---@type EquipType + local inst = active_equip[2]:Instance() + + if inst.SpecializeForShip then + inst:SpecializeForShip(equipSet.config) + end + + if slot.count then + inst:SetCount(slot.count) + end + + if equipSet:CanInstallInSlot(slot, inst) then + equipSet:Install(inst, slot) + end + + end + + ui.text(slot and "Slot Status: Available" or "Slot Status: Unavailable or Occupied") + + end + + end -- Load up on commodities if ui.collapsingHeader("Cargo", {}) then -- {"OpenOnDoubleClick"} diff --git a/data/modules/Equipment/Hyperdrive.lua b/data/modules/Equipment/Hyperdrive.lua index e1db6734b4..95bfe8595c 100644 --- a/data/modules/Equipment/Hyperdrive.lua +++ b/data/modules/Equipment/Hyperdrive.lua @@ -15,6 +15,7 @@ Equipment.Register("hyperspace.hyperdrive_1", HyperdriveType.New { l10n_key="DRIVE_CLASS1", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=1 }, mass=1.4, volume=2.5, capabilities={ hyperclass=1 }, + fuel_resv_size = 1, factor_eff = 65, price=1700, purchasable=true, tech_level=3, icon_name="equip_hyperdrive" }) @@ -22,6 +23,7 @@ Equipment.Register("hyperspace.hyperdrive_2", HyperdriveType.New { l10n_key="DRIVE_CLASS2", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=2 }, mass=4, volume=6, capabilities={ hyperclass=2 }, + fuel_resv_size = 4, factor_eff = 60, price=2300, purchasable=true, tech_level=4, icon_name="equip_hyperdrive" }) @@ -29,6 +31,7 @@ Equipment.Register("hyperspace.hyperdrive_3", HyperdriveType.New { l10n_key="DRIVE_CLASS3", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=3 }, mass=9.5, volume=15, capabilities={ hyperclass=3 }, + fuel_resv_size = 10, factor_eff = 55, price=7500, purchasable=true, tech_level=4, icon_name="equip_hyperdrive" }) @@ -36,6 +39,7 @@ Equipment.Register("hyperspace.hyperdrive_4", HyperdriveType.New { l10n_key="DRIVE_CLASS4", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=4 }, mass=25, volume=40, capabilities={ hyperclass=4 }, + fuel_resv_size = 30, factor_eff = 42, price=21000, purchasable=true, tech_level=6, icon_name="equip_hyperdrive" }) @@ -43,6 +47,7 @@ Equipment.Register("hyperspace.hyperdrive_5", HyperdriveType.New { l10n_key="DRIVE_CLASS5", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=5 }, mass=76, volume=120, capabilities={ hyperclass=5 }, + fuel_resv_size = 75, factor_eff = 35, price=68000, purchasable=true, tech_level=7, icon_name="equip_hyperdrive" }) @@ -52,6 +57,7 @@ Equipment.Register("hyperspace.hyperdrive_6", HyperdriveType.New { l10n_key="DRIVE_CLASS6", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=6 }, mass=152, volume=340, capabilities={ hyperclass=6 }, + fuel_resv_size = 120, factor_eff = 30, price=129000, purchasable=true, tech_level=7, icon_name="equip_hyperdrive" }) @@ -60,6 +66,7 @@ Equipment.Register("hyperspace.hyperdrive_7", HyperdriveType.New { l10n_key="DRIVE_CLASS7", fuel=Commodities.hydrogen, slot = { type="hyperdrive.civilian", size=7 }, mass=540, volume=960, capabilities={ hyperclass=7 }, + fuel_resv_size = 350, factor_eff = 25, price=341000, purchasable=true, tech_level=9, icon_name="equip_hyperdrive" }) @@ -71,63 +78,40 @@ Equipment.Register("hyperspace.hyperdrive_7", HyperdriveType.New { Equipment.Register("hyperspace.hyperdrive_mil1", HyperdriveType.New { l10n_key="DRIVE_MIL1", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, slot = { type="hyperdrive.military", size=1 }, - mass=1, volume=1, capabilities={ hyperclass=1 }, + mass=2, volume=2.5, capabilities={ hyperclass=1 }, + fuel_resv_size = 1, factor_eff = 75, price=23000, purchasable=true, tech_level=10, icon_name="equip_hyperdrive_mil" }) Equipment.Register("hyperspace.hyperdrive_mil2", HyperdriveType.New { l10n_key="DRIVE_MIL2", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, slot = { type="hyperdrive.military", size=2 }, - mass=3, volume=3, capabilities={ hyperclass=2 }, + mass=5.5, volume=6, capabilities={ hyperclass=2 }, + fuel_resv_size = 4, factor_eff = 68, price=47000, purchasable=true, tech_level="MILITARY", icon_name="equip_hyperdrive_mil" }) Equipment.Register("hyperspace.hyperdrive_mil3", HyperdriveType.New { l10n_key="DRIVE_MIL3", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, slot = { type="hyperdrive.military", size=3 }, - mass=5, volume=5, capabilities={ hyperclass=3 }, + mass=12.5, volume=15, capabilities={ hyperclass=3 }, + fuel_resv_size = 10, factor_eff = 60, price=85000, purchasable=true, tech_level=11, icon_name="equip_hyperdrive_mil" }) Equipment.Register("hyperspace.hyperdrive_mil4", HyperdriveType.New { l10n_key="DRIVE_MIL4", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, slot = { type="hyperdrive.military", size=4 }, - mass=13, volume=13, capabilities={ hyperclass=4 }, + mass=32, volume=40, capabilities={ hyperclass=4 }, + fuel_resv_size = 30, factor_eff = 48, price=214000, purchasable=true, tech_level=12, icon_name="equip_hyperdrive_mil" }) Equipment.Register("hyperspace.hyperdrive_mil5", HyperdriveType.New { l10n_key="DRIVE_MIL5", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, slot = { type="hyperdrive.military", size=5 }, - mass=29, volume=29, capabilities={ hyperclass=5 }, + mass=105, volume=120, capabilities={ hyperclass=5 }, + fuel_resv_size = 75, factor_eff = 42, price=540000, purchasable=false, tech_level="MILITARY", icon_name="equip_hyperdrive_mil" }) -Equipment.Register("hyperspace.hyperdrive_mil6", HyperdriveType.New { - l10n_key="DRIVE_MIL6", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, - slot = { type="hyperdrive.military", size=6 }, - mass=60, volume=60, capabilities={ hyperclass=6 }, - price=1350000, purchasable=false, tech_level="MILITARY", - icon_name="equip_hyperdrive_mil" -}) -Equipment.Register("hyperspace.hyperdrive_mil7", HyperdriveType.New { - l10n_key="DRIVE_MIL7", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, - slot = { type="hyperdrive.military", size=7 }, - mass=135, volume=135, capabilities={ hyperclass=7 }, - price=3500000, purchasable=false, tech_level="MILITARY", - icon_name="equip_hyperdrive_mil" -}) -Equipment.Register("hyperspace.hyperdrive_mil8", HyperdriveType.New { - l10n_key="DRIVE_MIL8", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, - slot = { type="hyperdrive.military", size=8 }, - mass=190, volume=190, capabilities={ hyperclass=8 }, - price=8500000, purchasable=false, tech_level="MILITARY", - icon_name="equip_hyperdrive_mil" -}) -Equipment.Register("hyperspace.hyperdrive_mil9", HyperdriveType.New { - l10n_key="DRIVE_MIL9", fuel=Commodities.military_fuel, byproduct=Commodities.radioactives, - slot = { type="hyperdrive.military", size=9 }, - mass=260, volume=260, capabilities={ hyperclass=9 }, - price=22000000, purchasable=false, tech_level="MILITARY", - icon_name="equip_hyperdrive_mil" -}) diff --git a/data/modules/MissionUtils/OutfitRules.lua b/data/modules/MissionUtils/OutfitRules.lua index 3ed0dc6db9..e9cc64e4e1 100644 --- a/data/modules/MissionUtils/OutfitRules.lua +++ b/data/modules/MissionUtils/OutfitRules.lua @@ -16,6 +16,7 @@ local OutfitRules = {} ---@field maxThreatFactor number? Maximum proportion of remaining threat that can be consumed by this rule ---@field randomChance number? Random chance to apply this rule, in [0..1] ---@field balance boolean? Attempt to balance volume / threat across all slots this rule matches (works best with .pick = nil) +---@field apply fun(equip: EquipType)? Make custom changes to the selected equipment before it is installed in the ship OutfitRules.DifficultWeapon = { slot = "weapon", @@ -91,8 +92,19 @@ OutfitRules.DefaultPassengerCabins = { filter = "cabin.passenger" } +OutfitRules.AnyHyperdrive = { + slot = "hyperdrive", + apply = function(equip) ---@param equip Equipment.HyperdriveType + equip:SetFuel(nil, equip:GetMaxFuel()) + end +} + OutfitRules.DefaultHyperdrive = { - slot = "hyperdrive" + slot = "hyperdrive", + filter = "hyperdrive.civilian", + apply = function(equip) ---@param equip Equipment.HyperdriveType + equip:SetFuel(nil, equip:GetMaxFuel()) + end } OutfitRules.DefaultAtmoShield = { diff --git a/data/modules/MissionUtils/ShipBuilder.lua b/data/modules/MissionUtils/ShipBuilder.lua index fba45f5394..15454635e3 100644 --- a/data/modules/MissionUtils/ShipBuilder.lua +++ b/data/modules/MissionUtils/ShipBuilder.lua @@ -361,6 +361,10 @@ function ShipBuilder.ApplyEquipmentRule(shipPlan, rule, rand, hullThreat) inst:SetCount(slot.count) end + if rule.apply then + rule.apply(inst) + end + if shipPlan.freeVolume >= inst.volume then shipPlan:AddEquipToPlan(equip, slot, threat) end @@ -439,6 +443,10 @@ function ShipBuilder.ApplyEquipmentRule(shipPlan, rule, rand, hullThreat) inst:SetCount(slot.count) end + if rule.apply then + rule.apply(inst) + end + return shipPlan.freeVolume >= inst.volume and inst or nil end) @@ -652,13 +660,20 @@ function ShipBuilder.MakePlan(template, shipConfig, threat) if rule.slot then ShipBuilder.ApplyEquipmentRule(shipPlan, rule, Engine.rand, hullThreat) else - local equip = Equipment.Get(rule.equip) - assert(equip) + local inst = assert(Equipment.Get(rule.equip)):Instance() + + if inst.SpecializeForShip then + inst:SpecializeForShip(shipPlan.config) + end + + if rule.apply then + rule.apply(inst) + end - local equipThreat = ShipBuilder.ComputeEquipThreatFactor(equip, hullThreat) + local equipThreat = ShipBuilder.ComputeEquipThreatFactor(inst, hullThreat) - if shipPlan.freeVolume >= equip.volume and shipPlan.freeThreat >= equipThreat then - shipPlan:AddEquipToPlan(equip) + if shipPlan.freeVolume >= inst.volume and shipPlan.freeThreat >= equipThreat then + shipPlan:AddEquipToPlan(inst) end end diff --git a/data/modules/MissionUtils/ShipTemplates.lua b/data/modules/MissionUtils/ShipTemplates.lua index f8565d87d3..044e148394 100644 --- a/data/modules/MissionUtils/ShipTemplates.lua +++ b/data/modules/MissionUtils/ShipTemplates.lua @@ -135,7 +135,7 @@ ShipTemplates.GenericMercenary = ShipBuilder.Template:clone { utils.mixin(OutfitRules.DefaultLaserCooling, { minThreat = 40.0 }), utils.mixin(OutfitRules.DefaultShieldBooster, { minThreat = 30.0 }), -- Default equipment in remaining space - OutfitRules.DefaultHyperdrive, + OutfitRules.AnyHyperdrive, OutfitRules.DefaultAtmoShield, OutfitRules.DefaultRadar, } diff --git a/data/modules/SearchRescue/SearchRescue.lua b/data/modules/SearchRescue/SearchRescue.lua index 6291c5af4e..963e329750 100644 --- a/data/modules/SearchRescue/SearchRescue.lua +++ b/data/modules/SearchRescue/SearchRescue.lua @@ -526,6 +526,13 @@ local createTargetShipParameters = function (flavour, planet) end end + ----> cargo hold to transfer fuel + if flavour.id == 2 or flavour.id == 4 or flavour.id == 5 then + if def.cargo < 1 then + return false + end + end + ----> needs to have enough passenger space for pickup if flavour.id == 1 or flavour.id == 6 then local config = HullConfig.GetHullConfig(def.id) ---@type HullConfig @@ -678,17 +685,19 @@ local createTargetShip = function (mission) error("Could not fit all passengers to return into mission ship!") end + -- If this is not a refueling mission, the ship will have full engine and hyperdrive fuel tanks local is_refueling = mission.flavour.id == 2 or mission.flavour.id == 4 or mission.flavour.id == 5 if is_refueling then -- remove all fuel for refueling mission ship:SetFuelPercent(0) - else - -- add hydrogen for hyperjumping - -- FIXME(fuel): hyperdrives will have their own independent fuel tanks and we should not add fuel to the cargo bay - local drive = assert(ship:GetInstalledHyperdrive(), "No hyperdrive in stranded ship!") - local hypfuel = drive.capabilities.hyperclass ^ 2 -- fuel for max range - ship:GetComponent('CargoManager'):AddCommodity(drive.fuel or Commodities.hydrogen, hypfuel) + + local drive = ship:GetInstalledHyperdrive() + + -- Remove hyperdrive fuel for refueling mission + if drive then + drive:SetFuel(ship, 0) + end end return ship @@ -1668,6 +1677,14 @@ local deliverCommodity = function (mission, commodity) removeCargo(Game.player, commodity) addCargo(mission.target, commodity) + -- if commodity was fuel and the mission was local refuel the ship with it + -- prevents issues where the ship's spare cargo space is smaller than the fuel we're delivering + if commodity == Commodities.hydrogen then + if mission.flavour.id == 2 or mission.flavour.id == 4 or mission.flavour.id == 5 then + mission.target:Refuel(Commodities.hydrogen, 1) + end + end + -- show result message if done delivering this commodity mission.deliver_comm[commodity] = mission.deliver_comm[commodity] - 1 local done = mission.deliver_comm_orig[commodity] - mission.deliver_comm[commodity] @@ -1675,13 +1692,6 @@ local deliverCommodity = function (mission, commodity) local resulttxt = string.interp(l.RESULT_DELIVERY_COMM, {done = done, todo = todo, cargotype = commodity_name}) Comms.ImportantMessage(resulttxt) mission.deliver_comm_check[commodity] = "COMPLETE" - - -- if commodity was fuel and the mission was local refuel the ship with it - if commodity == Commodities.hydrogen then - if mission.flavour.id == 2 or mission.flavour.id == 4 or mission.flavour.id == 5 then - mission.target:Refuel(Commodities.hydrogen, mission.deliver_comm_orig[commodity]) - end - end end end end @@ -2001,6 +2011,7 @@ local onLeaveSystem = function (ship) end end +---@param ship Ship local onShipDocked = function (ship, station) if ship:IsPlayer() then for _,mission in pairs(missions) do @@ -2020,11 +2031,7 @@ local onShipDocked = function (ship, station) -- add hydrogen for hyperjumping local drive = ship:GetInstalledHyperdrive() if drive then - ---@type CargoManager - local cargoMgr = ship:GetComponent('CargoManager') - local hypfuel = drive.capabilities.hyperclass ^ 2 -- fuel for max range - hypfuel = hypfuel - cargoMgr:CountCommodity(Commodities.hydrogen) - cargoMgr:AddCommodity(Commodities.hydrogen, math.max(hypfuel, 0)) + drive:SetFuel(ship, drive:GetMaxFuel()) end discardShip(ship) diff --git a/data/modules/TradeShips/Events.lua b/data/modules/TradeShips/Events.lua index ef68922c46..83f5e88d33 100644 --- a/data/modules/TradeShips/Events.lua +++ b/data/modules/TradeShips/Events.lua @@ -130,7 +130,7 @@ local onShipDocked = function (ship, starport) ship:SetHullPercent() Trader.addEquip(ship) end - Trader.addFuel(ship) + Trader.addHyperdriveFuel(ship) ship:SetFuelPercent() if trader.status == 'docked' then diff --git a/data/modules/TradeShips/Flow.lua b/data/modules/TradeShips/Flow.lua index f298019459..8012377627 100644 --- a/data/modules/TradeShips/Flow.lua +++ b/data/modules/TradeShips/Flow.lua @@ -464,13 +464,9 @@ Flow.spawnInitialShips = function() Core.ships[ship] = { ts_error = "OK", status = 'inbound', starport = params.to, ship_name = params.id} Trader.addEquip(ship) - local fuel_added = Trader.addFuel(ship) + Trader.addHyperdriveFuel(ship, hj_route.fuel) Trader.addCargo(ship, 'import') - if fuel_added and fuel_added > 0 then - Trader.removeFuel(ship, math.min(hj_route.fuel, fuel_added)) - end - Space.PutShipOnRoute(ship, params.to, Engine.rand:Number(0.0, 0.999))-- don't generate at the destination ship:AIDockWith(params.to) diff --git a/data/modules/TradeShips/Trader.lua b/data/modules/TradeShips/Trader.lua index ab26ef3e85..2aedf1fac6 100644 --- a/data/modules/TradeShips/Trader.lua +++ b/data/modules/TradeShips/Trader.lua @@ -256,7 +256,10 @@ Trader.getNearestStarport = function(ship, current) return starport or current end -Trader.addFuel = function (ship) +-- Add fuel to the ship's hyperdrive +---@param ship Ship +---@param deducted number? Amount of fuel to leave empty in the drive +Trader.addHyperdriveFuel = function (ship, deducted) local drive = ship:GetInstalledHyperdrive() -- a drive must be installed @@ -265,30 +268,8 @@ Trader.addFuel = function (ship) return nil end - -- the last character of the fitted drive is the class - -- the fuel needed for max range is the square of the drive class - local count = drive.capabilities.hyperclass ^ 2 - - ---@type CargoManager - local cargoMgr = ship:GetComponent('CargoManager') - - -- account for fuel it already has - count = count - cargoMgr:CountCommodity(Commodities.hydrogen) - - -- don't add more fuel than the ship can hold - count = math.min(count, cargoMgr:GetFreeSpace()) - cargoMgr:AddCommodity(Commodities.hydrogen, count) - - return count -end - -Trader.removeFuel = function (ship, count) - ---@type CargoManager - local cargoMgr = ship:GetComponent('CargoManager') - - local removed = cargoMgr:RemoveCommodity(Commodities.hydrogen, count) - - return removed + -- fill the drive completely, less the amount that should be deducted + drive:SetFuel(ship, math.max(0, drive:GetMaxFuel() - (deducted or 0))) end Trader.checkDistBetweenStarport = function (ship) @@ -402,7 +383,7 @@ Trader.spawnInCloud = function(ship_name, cloud, route, dest_time) local ship = Space.SpawnShip(ship_name, 0, 0, {cloud.from, route.from:GetSystemBody().path, dest_time}) ship:SetLabel(Ship.MakeRandomLabel()) Trader.addEquip(ship) - Trader.addFuel(ship) + Trader.addHyperdriveFuel(ship) Trader.addCargo(ship, 'import') Core.ships[ship] = { status = 'hyperspace', diff --git a/data/pigui/modules/hyperjump-planner.lua b/data/pigui/modules/hyperjump-planner.lua index a76d953f76..c950e6e833 100644 --- a/data/pigui/modules/hyperjump-planner.lua +++ b/data/pigui/modules/hyperjump-planner.lua @@ -2,7 +2,6 @@ -- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt local Game = require 'Game' -local Equipment = require 'Equipment' local Commodities = require 'Commodities' local Lang = require 'Lang' @@ -78,14 +77,14 @@ local function showInfo() textIcon(icons.fuel, lui.REQUIRED_FUEL) ui.sameLine() - ui.text(total_fuel .. lc.UNIT_TONNES) + ui.text(string.format("%.1f%s", total_fuel, lc.UNIT_TONNES)) ui.sameLine() ui.text("[") ui.sameLine() ui.withStyleVars({ItemSpacing = Vector2(0.0)}, function() textIcon(icons.hull, lui.CURRENT_FUEL) ui.sameLine() - ui.text(" : " .. current_fuel .. lc.UNIT_TONNES) + ui.text(" : " .. string.format("%.1f%s", current_fuel, lc.UNIT_TONNES)) end) ui.sameLine() ui.text("]") @@ -116,9 +115,9 @@ local function buildJumpRouteList() local start = Game.system and Game.system.path or player:GetHyperspaceDestination() local drive = player:GetInstalledHyperdrive() - local fuel_type = drive and drive.fuel or Commodities.hydrogen + if not drive then return end - local cur_fuel = player:GetComponent('CargoManager'):CountCommodity(fuel_type) + local cur_fuel = drive.storedFuel local running_fuel = 0 for jumpIndex, jump in pairs(sectorView:GetRoute()) do @@ -138,7 +137,11 @@ local function buildJumpRouteList() hyperjump_route[jumpIndex] = { path = jump, color = color, - textLine = jumpIndex ..": ".. jump_sys.name .. " (" .. string.format("%.2f", distance) .. lc.UNIT_LY .. " - " .. fuel .. lc.UNIT_TONNES..")" + textLine = "{}: {} ({} - {})" % { + jumpIndex, jump_sys.name, + string.format("%.2f%s", distance, lc.UNIT_LY), + string.format("%.1f%s", fuel, lc.UNIT_TONNES) + } } running_fuel = fuel + running_fuel start = jump @@ -311,7 +314,7 @@ function hyperJumpPlanner.display() local fuel_type = drive and drive.fuel or Commodities.hydrogen current_system = Game.system -- will be nil during the hyperjump current_path = Game.system and current_system.path -- will be nil during the hyperjump - current_fuel = Game.player:GetComponent('CargoManager'):CountCommodity(fuel_type) + current_fuel = Game.player:GetComponent('CargoManager'):CountCommodity(fuel_type) + (drive and drive.storedFuel or 0) map_selected_path = sectorView:GetSelectedSystemPath() showHyperJumpPlannerWindow() end -- hyperJumpPlanner.display @@ -331,7 +334,7 @@ end ---@type EquipSet.Listener function hyperJumpPlanner.onShipEquipmentChanged(op, equip, slot) - if op == 'install' and slot and slot.type:match("^hyperdrive") then + if (op == 'install' or op == 'modify') and equip:IsA("Equipment.HyperdriveType") then buildJumpRouteList() end end diff --git a/data/pigui/modules/info-view/01-ship-info.lua b/data/pigui/modules/info-view/01-ship-info.lua index 5d2ba0e9c7..bc31dc2298 100644 --- a/data/pigui/modules/info-view/01-ship-info.lua +++ b/data/pigui/modules/info-view/01-ship-info.lua @@ -41,7 +41,7 @@ local function shipStats() local up_acc = player:GetAcceleration("up") local atmo_shield = equipSet:GetInstalledOfType("hull.atmo_shield")[1] - local atmo_shield_cap = player["atmo_shield_cap"] + local atmo_shield_cap = player["atmo_shield_cap"] or 1 textTable.draw({ { l.REGISTRATION_NUMBER..":", shipLabel}, diff --git a/data/pigui/modules/info-view/03-econ-trade.lua b/data/pigui/modules/info-view/03-econ-trade.lua index ce258951d2..a21e999025 100644 --- a/data/pigui/modules/info-view/03-econ-trade.lua +++ b/data/pigui/modules/info-view/03-econ-trade.lua @@ -25,10 +25,6 @@ local buttonSpaceSize = iconSize -- Need a style-var query system for best effect local itemSpacing = ui.rescaleUI(Vector2(6, 12), Vector2(1600, 900)) -local shipDef -local hyperdrive -local hyperdrive_fuel - local jettison = function (item) local enabled = Game.player.flightState == "FLYING" local variant = enabled and ui.theme.buttonColors.default or ui.theme.buttonColors.disabled @@ -146,21 +142,18 @@ end -- Gauge bar for internal, interplanetary, fuel tank local function gauge_fuel() local player = Game.player + local tankSize = ShipDef[player.shipId].fuelTankMass local text = string.format(l.FUEL .. ": %dt \t" .. l.DELTA_V .. ": %d km/s", - shipDef.fuelTankMass/100 * player.fuel, player:GetRemainingDeltaV()/1000) + tankSize/100 * player.fuel, player:GetRemainingDeltaV()/1000) gauge_bar(player.fuel, text, 0, 100, icons.fuel) end -- Gauge bar for hyperdrive fuel / range -local function gauge_hyperdrive() - ---@type CargoManager - local cargoMgr = Game.player:GetComponent('CargoManager') - local fuel = cargoMgr:CountCommodity(hyperdrive_fuel) +local function gauge_hyperdrive(drive) + local text = string.format(l.FUEL .. ": %%0.1ft \t" .. l.HYPERSPACE_RANGE .. ": %0.1f " .. l.LY, Game.player:GetHyperspaceRange()) - local text = string.format(l.FUEL .. ": %%dt \t" .. l.HYPERSPACE_RANGE .. ": %d " .. l.LY, Game.player:GetHyperspaceRange()) - - gauge_bar(fuel, text, 0, cargoMgr:GetFreeSpace() + fuel, icons.hyperspace) + gauge_bar(drive.storedFuel, text, 0, drive:GetMaxFuel(), icons.hyperspace) end -- Gauge bar for used/free cargo space @@ -183,6 +176,92 @@ local function gauge_cabins() 0, berths_total, icons.personal) end +---@param hyperdrive Equipment.HyperdriveType +local function transfer_hyperfuel_hydrogen(hyperdrive, amt) + local fuelTankSize = ShipDef[Game.player.shipId].fuelTankMass + local fuelMassLeft = Game.player.fuelMassLeft + + -- Ensure we're not transferring more than the hyperdrive holds + local delta = math.clamp(amt, -hyperdrive.storedFuel, hyperdrive:GetMaxFuel() - hyperdrive.storedFuel) + -- Ensure we're not transferring more than the fuel tank holds + delta = math.clamp(delta, fuelMassLeft - fuelTankSize, fuelMassLeft) + + if math.abs(delta) > 0.0001 then + Game.player:SetFuelPercent((fuelMassLeft - delta) * 100 / fuelTankSize) + hyperdrive:SetFuel(Game.player, hyperdrive.storedFuel + delta) + end +end + +---@param hyperdrive Equipment.HyperdriveType +local function transfer_hyperfuel_mil(hyperdrive, amt) + local cargoMgr = Game.player:GetComponent('CargoManager') + local availableFuel = cargoMgr:CountCommodity(hyperdrive.fuel) + local availableCargo = cargoMgr:GetFreeSpace() + + -- Ensure we're not transferring more than the hyperdrive holds + local delta = math.clamp(amt, -hyperdrive.storedFuel, hyperdrive:GetMaxFuel() - hyperdrive.storedFuel) + -- Ensure we're not transferring more than the cargo bay holds + delta = math.clamp(delta, -availableCargo, availableFuel) + + -- TODO(CargoManager): liquid tanks / partially-filled cargo containers + -- Until then, we round down to a whole integer in both directions since we're dealing with integer cargo masses + delta = math.modf(delta) + + if delta > 0 then + cargoMgr:RemoveCommodity(hyperdrive.fuel, delta) + hyperdrive:SetFuel(Game.player, hyperdrive.storedFuel + delta) + elseif delta < 0 then + cargoMgr:AddCommodity(hyperdrive.fuel, math.abs(delta)) + hyperdrive:SetFuel(Game.player, hyperdrive.storedFuel + delta) + end +end + +local function fuelTransferButton(drive, amt) + local icon = amt < 0 and icons.chevron_down or icons.chevron_up + + if ui.button(ui.get_icon_glyph(icon) .. tostring(math.abs(amt))) then + + if drive.fuel == Commodities.hydrogen then + transfer_hyperfuel_hydrogen(drive, amt) + elseif drive.fuel == Commodities.military_fuel then + transfer_hyperfuel_mil(drive, amt) + end + + end +end + +local function drawCentered(id, fun) + if not ui.beginTable(id .. "##centered", 3) then return end + + ui.tableSetupColumn("leftPadding") + ui.tableSetupColumn("content", { "WidthFixed" }) + ui.tableSetupColumn("rightPadding") + + ui.tableNextRow() + ui.tableSetColumnIndex(1) + + fun() + + ui.endTable() +end + +local function drawFuelTransfer(drive) + -- Don't allow transferring fuel while the hyperdrive is doing its thing + if Game.player:IsHyperspaceActive() then return end + + drawCentered("Hyperdrive", function() + ui.horizontalGroup(function() + fuelTransferButton(drive, 10) + fuelTransferButton(drive, 1) + + ui.text(l.TRANSFER_FUEL) + + fuelTransferButton(drive, -1) + fuelTransferButton(drive, -10) + end) + end) +end + local function drawPumpDialog() local width1 = ui.calcTextSize(l.PUMP_DOWN) local width2 = ui.calcTextSize(l.REFUEL) @@ -224,13 +303,22 @@ end local function drawEconTrade() local player = Game.player + local drive = player:GetInstalledHyperdrive() ui.withFont(orbiteer.heading, function() ui.text(l.FUEL) end) gauge_fuel() - gauge_hyperdrive() - drawPumpDialog() + drawCentered("Pump Dialog", function() + drawPumpDialog() + end) + + if drive then + ui.withFont(orbiteer.heading, function() ui.text(l.HYPERDRIVE) end) + + gauge_hyperdrive(drive) + drawFuelTransfer(drive) + end ui.newLine() ui.withFont(orbiteer.heading, function() ui.text(l.CABINS) end) @@ -287,10 +375,6 @@ InfoView:registerView({ Game.player:GetComponent('CargoManager'):AddListener('econ-trade', function (type, count) if type:Class() == CommodityType then cachedCargoList = nil end end) - - shipDef = ShipDef[Game.player.shipId] - hyperdrive = Game.player:GetInstalledHyperdrive() - hyperdrive_fuel = hyperdrive and hyperdrive.fuel or Commodities.hydrogen end, debugReload = function() diff --git a/data/pigui/modules/station-view/01-lobby.lua b/data/pigui/modules/station-view/01-lobby.lua index c7efcf3bec..e8185d2145 100644 --- a/data/pigui/modules/station-view/01-lobby.lua +++ b/data/pigui/modules/station-view/01-lobby.lua @@ -45,7 +45,7 @@ local face = nil local stationSeed = 0 local shipDef -local hyperdrive +local hyperdrive ---@type Equipment.HyperdriveType? local hyperdrive_fuel local hydrogenIcon = PiImage.New("icons/goods/Hydrogen.png") local hyperdriveIcon = PiImage.New("icons/goods/Hydrogen.png") @@ -134,43 +134,27 @@ local refuelInternalTank = function (delta) end local refuelHyperdrive = function (mass) - local station = Game.player:GetDockedWith() + assert(hyperdrive) + local station = assert(Game.player:GetDockedWith()) local stock = station:GetCommodityStock(hyperdrive_fuel) local price = station:GetCommodityPrice(hyperdrive_fuel) - ---@type CargoManager - local cargoMgr = Game.player:GetComponent('CargoManager') - if mass > 0 then if stock == 0 then popupMsg = l.ITEM_IS_OUT_OF_STOCK popup:open() return end - - mass = math.clamp(mass, 0, cargoMgr:GetFreeSpace()) - else - mass = math.clamp(mass, -cargoMgr:CountCommodity(hyperdrive_fuel), 0) end - local total = price * mass - if total > Game.player:GetMoney() then - mass = math.floor(Game.player:GetMoney() / price) - total = price * mass - end + mass = math.clamp(mass, -hyperdrive.storedFuel, hyperdrive:GetMaxFuel() - hyperdrive.storedFuel) - if stock < mass then - mass = stock - total = price * mass - end + -- Can't buy any more than the station has in stock or we have money for + mass = math.min(mass, math.min(stock, Game.player:GetMoney() / price)) + Game.player:AddMoney(-price * mass) - Game.player:AddMoney(-total) - if mass < 0 then - cargoMgr:RemoveCommodity(hyperdrive_fuel, math.abs(mass)) - else - cargoMgr:AddCommodity(hyperdrive_fuel, mass) - end - station:AddCommodityStock(hyperdrive_fuel, -mass) + hyperdrive:SetFuel(Game.player, hyperdrive.storedFuel + mass) + station:AddCommodityStock(hyperdrive_fuel, -math.round(mass)) end local function lobbyMenu() @@ -215,12 +199,12 @@ local function lobbyMenu() -- hyperspace fuel ui.nextColumn() + if not hyperdrive then return end + hyperdriveIcon:Draw(widgetSizes.iconSize) ui.nextColumn() - ---@type CargoManager - local cargoMgr = Game.player:GetComponent('CargoManager') - local stored_hyperfuel = cargoMgr:CountCommodity(hyperdrive_fuel) + local stored_hyperfuel = hyperdrive.storedFuel -- hyperspace fuel prices ui.withFont(pionillium.body, function() @@ -242,9 +226,9 @@ local function lobbyMenu() -- hyperspace fuel gauge gaugePos = ui.getCursorScreenPos() gaugePos.y = gaugePos.y + widgetSizes.buttonSizeBase.y/2 - ui.gauge(gaugePos, stored_hyperfuel, '', string.format(l.FUEL .. ": %dt \t" .. l.HYPERSPACE_RANGE .. ": %d " .. l.LY, + ui.gauge(gaugePos, stored_hyperfuel, '', string.format(l.FUEL .. ": %0.1ft \t" .. l.HYPERSPACE_RANGE .. ": %d " .. l.LY, stored_hyperfuel, Game.player:GetHyperspaceRange()), - 0, cargoMgr:GetFreeSpace() + stored_hyperfuel, + 0, hyperdrive:GetMaxFuel(), icons.hyperspace, colors.gaugeEquipmentMarket, '', gaugeWidth, gaugeHeight, pionillium.body) diff --git a/data/pigui/modules/station-view/04-shipMarket.lua b/data/pigui/modules/station-view/04-shipMarket.lua index d7516b9f51..ae11cbe520 100644 --- a/data/pigui/modules/station-view/04-shipMarket.lua +++ b/data/pigui/modules/station-view/04-shipMarket.lua @@ -206,7 +206,7 @@ local function buyShip (mkt, sos) if equipSet:CanInstallInSlot(handle, pair[2]) then equipSet:Install(pair[2], handle) else - logWarning("Default equipment item {} for ship slot {}.{} is not compatible with slot." % { slot.default, player.shipId, slot.id }) + logWarning("Default equipment item {} for ship slot {}.{} is not compatible with slot." % { handle.default, player.shipId, handle.id }) end end diff --git a/data/pigui/views/map-sector-view.lua b/data/pigui/views/map-sector-view.lua index bfc4d36c28..c1ff280c26 100644 --- a/data/pigui/views/map-sector-view.lua +++ b/data/pigui/views/map-sector-view.lua @@ -139,7 +139,7 @@ sectorViewLayout.mainFont = font local function draw_jump_status(item) textIcon(statusIcons[item.jumpStatus].icon, lui[item.jumpStatus]) - ui.text(string.format("%.2f%s %d%s %s", + ui.text(string.format("%.2f%s %.1f%s %s", item.distance, lc.UNIT_LY, item.fuelRequired, lc.UNIT_TONNES, ui.Format.Duration(item.duration, 2))) end @@ -471,6 +471,7 @@ ui.registerModule("game", { id = 'map-sector-view', draw = function() if ui.ctrlHeld() and ui.isKeyReleased(ui.keys.delete) then systemEconView = package.reimport('pigui.modules.system-econ-view').New() + package.reimport('pigui.modules.hyperjump-planner') package.reimport() end end