From 29fc5e60a9a729046366ddff79bb732cb84b4461 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 4 Jan 2022 02:28:16 -0500 Subject: [PATCH 01/10] Add new ship equipment display widget - Break out ship equipment by slot type - Detailed equipment display with quick stats for each item - UI paradigm is forwards compatible for physical-slot equipment model - Replace existing equipment market screen with new filtered market - Integrate new equipment widget into ship info screen --- data/lang/equipment-core/en.json | 28 + data/lang/ui-core/en.json | 8 + data/libs/utils.lua | 8 + data/pigui/libs/equipment-market.lua | 30 +- data/pigui/libs/ship-equipment.lua | 618 ++++++++++++++++++ data/pigui/modules/info-view/01-ship-info.lua | 140 +--- .../station-view/05-equipmentMarket.lua | 165 +---- data/pigui/themes/default.lua | 7 +- 8 files changed, 726 insertions(+), 278 deletions(-) create mode 100644 data/pigui/libs/ship-equipment.lua diff --git a/data/lang/equipment-core/en.json b/data/lang/equipment-core/en.json index a4f87ac3c86..9f6f22b1835 100644 --- a/data/lang/equipment-core/en.json +++ b/data/lang/equipment-core/en.json @@ -354,5 +354,33 @@ "UNOCCUPIED_CABIN_DESCRIPTION": { "description": "", "message": "Required for transport of a single passenger" + }, + "EMPTY_SLOT": { + "description": "Text indicating an empty equipment slot.", + "message": "EMPTY" + }, + "EQUIPMENT_WEIGHT": { + "description": "Tooltip explaining equipment weight", + "message": "Equipment Weight" + }, + "EQUIPMENT_INTEGRITY": { + "description": "Tooltip explaining remaining equipment integrity", + "message": "Equipment Integrity" + }, + "SHOTS_PER_MINUTE": { + "description": "Tooltip explaining weapon fire rate / RPM counter", + "message": "Firing Rate / Minute" + }, + "DAMAGE_PER_SHOT": { + "description": "Tooltip explaining weapon damage per shot", + "message": "Damage Per Shot" + }, + "TOTAL_MODULE_CAPACITY": { + "description": "Tooltip explaining module capacity of specific slot", + "message": "Total Capacity" + }, + "TOTAL_MODULE_WEIGHT": { + "description": "Tooltip explaining total equipped weight of specific slot", + "message": "Total Weight" } } diff --git a/data/lang/ui-core/en.json b/data/lang/ui-core/en.json index 9cc19dfde4a..88963cea028 100644 --- a/data/lang/ui-core/en.json +++ b/data/lang/ui-core/en.json @@ -2146,5 +2146,13 @@ "ZOOM": { "description": "Label for a zoom (magnification) control bar.", "message": "Zoom" + }, + "OCCUPIED_PASSENGER_CABINS": { + "description": "", + "message": "Occupied Passenger Cabins" + }, + "UNOCCUPIED_PASSENGER_CABINS": { + "description": "", + "message": "Unoccupied Passenger Cabins" } } diff --git a/data/libs/utils.lua b/data/libs/utils.lua index 3e49e40fcf0..3231bcfc2c5 100644 --- a/data/libs/utils.lua +++ b/data/libs/utils.lua @@ -251,6 +251,14 @@ utils.count = function(t) return i end +utils.contains = function(t, val) + for _, v in pairs(t) do + if v == val then return true end + end + + return false +end + utils.take = function(t, n) local res = {} local i = 0 diff --git a/data/pigui/libs/equipment-market.lua b/data/pigui/libs/equipment-market.lua index 7a62ce2be8a..47fcdccc5df 100644 --- a/data/pigui/libs/equipment-market.lua +++ b/data/pigui/libs/equipment-market.lua @@ -52,18 +52,14 @@ local defaultFuncs = { if not self.funcs.onClickBuy(self, e) then return end if self.funcs.getStock(self, e) <= 0 then - self.popup.msg = l.ITEM_IS_OUT_OF_STOCK - self.popup:open() - return + return self.funcs.onBuyFailed(self, e, l.ITEM_IS_OUT_OF_STOCK) end local player = Game.player -- if this ship model doesn't support fitting of this equip: if player:GetEquipSlotCapacity(e:GetDefaultSlot(player)) < 1 then - self.popup.msg = string.interp(l.NOT_SUPPORTED_ON_THIS_SHIP, {equipment = e:GetName(),}) - self.popup:open() - return + return self.funcs.onBuyFailed(self, e, string.interp(l.NOT_SUPPORTED_ON_THIS_SHIP, {equipment = e:GetName(),})) end -- add to first free slot @@ -77,24 +73,18 @@ local defaultFuncs = { -- if ship maxed out in any valid slot for e if not slot then - self.popup.msg = l.SHIP_IS_FULLY_EQUIPPED - self.popup:open() - return + return self.funcs.onBuyFailed(self, e, l.SHIP_IS_FULLY_EQUIPPED) end -- if ship too heavy to support more if player.freeCapacity < e.capabilities.mass then - self.popup.msg = l.SHIP_IS_FULLY_LADEN - self.popup:open() - return + return self.funcs.onBuyFailed(self, e, l.SHIP_IS_FULLY_LADEN) end local price = self.funcs.getBuyPrice(self, e) if player:GetMoney() < self.funcs.getBuyPrice(self, e) then - self.popup.msg = l.YOU_NOT_ENOUGH_MONEY - self.popup:open() - return + return self.funcs.onBuyFailed(self, e, l.YOU_NOT_ENOUGH_MONEY) end assert(player:AddEquip(e, 1, slot) == 1) @@ -109,6 +99,11 @@ local defaultFuncs = { Game.player:GetDockedWith():AddEquipmentStock(e, -count) end, + onBuyFailed = function (self, e, reason) + self.popup.msg = reason + self.popup:open() + end, + -- do something when a "sell" button is clicked -- return true if the buy can proceed onClickSell = function (self, e) @@ -180,7 +175,9 @@ local defaultFuncs = { end } -local MarketWidget = {} +local MarketWidget = { + defaultFuncs = defaultFuncs +} function MarketWidget.New(id, title, config) local self @@ -205,6 +202,7 @@ function MarketWidget.New(id, title, config) self.funcs.onClickSell = config.onClickSell or defaultFuncs.onClickSell self.funcs.buy = config.buy or defaultFuncs.buy self.funcs.bought = config.bought or defaultFuncs.bought + self.funcs.onBuyFailed = config.onBuyFailed or defaultFuncs.onBuyFailed self.funcs.sell = config.sell or defaultFuncs.sell self.funcs.sold = config.sold or defaultFuncs.sold self.funcs.initTable = config.initTable or defaultFuncs.initTable diff --git a/data/pigui/libs/ship-equipment.lua b/data/pigui/libs/ship-equipment.lua new file mode 100644 index 00000000000..2b87a1360d7 --- /dev/null +++ b/data/pigui/libs/ship-equipment.lua @@ -0,0 +1,618 @@ +-- Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details +-- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt + +local Equipment = require 'Equipment' +local Format = require 'Format' +local Game = require 'Game' +local ShipDef = require 'ShipDef' +local ModelSpinner = require 'PiGui.Modules.ModelSpinner' +local EquipMarket = require 'pigui.libs.equipment-market' +local EquipType = require 'EquipType' +local Vector2 = Vector2 +local utils = require 'utils' + +local Lang = require 'Lang' +local l = Lang.GetResource("ui-core") +local le = Lang.GetResource("equipment-core") + +local ui = require 'pigui' +local colors = ui.theme.colors +local icons = ui.theme.icons +local pionillium = ui.fonts.pionillium + +local lineSpacing = ui.rescaleUI(Vector2(8, 6)) +local iconSize = Vector2(pionillium.body.size) + +local equipmentInfoTab + +local EquipmentWidget = utils.inherits(nil, "EquipmentWidget") + +-- Slot information for the empty slot + example slot data layout +local emptySlot = { + -- type = "Slot", name = "[EMPTY]" + icon = icons.autopilot_dock, --size = "S1", + -- { icons.ecm_advanced, "0 KW", "Max Power Draw" }, + -- { icons.temperature, "0 KW", "Operating Heat" }, + { icons.hull, ui.Format.Mass(0, 1), le.EQUIPMENT_WEIGHT }, + -- { icons.repairs, "100%", le.EQUIPMENT_INTEGRITY } +} + +-- Equipment item grouping by underlying slot type +-- TODO: significant refactor to slot system to reduce highly-specialized slots +local sections = { + { name = "Propulsion", slot = "engine", showCapacity = true }, + { name = "Weapons", slot = "laser_front", showCapacity = true }, + { name = "Missiles", slot = "missile", showCapacity = true }, + { name = "Scoops", slot = "scoop", showCapacity = true }, + { name = "Sensors", slot = "sensor", showCapacity = true }, + { name = "Shields", slot = "shield" }, + { name = "Utility", slots = { + "cabin", "ecm", "radar", "target_scanner", + "hypercloud", "hull_autorepair", + "energy_booster", "atmo_shield", + "laser_cooler", "cargo_life_support", + "autopilot", "trade_computer", "thruster" + } } +} + +-- +-- ============================================================================= +-- Equipment Market Widget +-- ============================================================================= +-- + +-- Copied from 05-equipmentMarket.lua +local hasTech = function (station, e) + local equip_tech_level = e.tech_level or 1 -- default to 1 + + if type(equip_tech_level) == "string" then + if equip_tech_level == "MILITARY" then + return station.techLevel == 11 + else + error("Unknown tech level:\t"..equip_tech_level) + end + end + + assert(type(equip_tech_level) == "number") + return station.techLevel >= equip_tech_level +end + +local function makeEquipmentMarket() +return EquipMarket.New("EquipmentMarket", l.AVAILABLE_FOR_PURCHASE, { + itemTypes = { Equipment.cargo, Equipment.misc, Equipment.laser, Equipment.hyperspace }, + columnCount = 5, + initTable = function(self) + ui.setColumnWidth(0, self.style.size.x / 2.5) + ui.setColumnWidth(3, ui.calcTextSize(l.MASS).x + self.style.itemSpacing.x + self.style.itemPadding.x) + ui.setColumnWidth(4, ui.calcTextSize(l.IN_STOCK).x + self.style.itemSpacing.x + self.style.itemPadding.x) + end, + renderHeaderRow = function(self) + ui.text(l.NAME_OBJECT) + ui.nextColumn() + ui.text(l.BUY) + ui.nextColumn() + ui.text(l.SELL) + ui.nextColumn() + ui.text(l.MASS) + ui.nextColumn() + ui.text(l.IN_STOCK) + ui.nextColumn() + end, + renderItem = function(self, item) + ui.withTooltip(item:GetDescription(), function() + ui.text(item:GetName()) + ui.nextColumn() + ui.text(Format.Money(self.funcs.getBuyPrice(self, item))) + ui.nextColumn() + ui.text(Format.Money(self.funcs.getSellPrice(self, item))) + ui.nextColumn() + ui.text(item.capabilities.mass.."t") + ui.nextColumn() + ui.text(self.funcs.getStock(self, item)) + ui.nextColumn() + end) + end, + canDisplayItem = function (s, e) + local filterSlot = not s.owner.selectedEquip + if s.owner.selectedEquip then + for k, v in pairs(s.owner.selectedEquipSlots) do + filterSlot = filterSlot or utils.contains(e.slots, v) + end + end + return e.purchasable and hasTech(s.owner.station, e) and filterSlot + end, + onMouseOverItem = function(s, e) + local tooltip = e:GetDescription() + if string.len(tooltip) > 0 then + ui.withFont(pionillium.medium, function() ui.setTooltip(tooltip) end) + end + end, + onClickItem = function(s,e) + s.funcs.buy(s, e) + s:refresh() + end, + -- If we have an equipment item selected, we're replacing it. + onClickBuy = function(s,e) + if s.owner.selectedEquip[1] then + s.owner.ship:RemoveEquip(s.owner.selectedEquip[1], 1, s.owner.selectedEquip.slot) + s.owner.ship:AddMoney(s.funcs.getSellPrice(s, s.owner.selectedEquip[1])) + end + + return true + end, + -- If the purchase failed, undo the sale of the item previously in the slot + onBuyFailed = function(s, e, reason) + if s.owner.selectedEquip[1] then + s.owner.ship:AddEquip(s.owner.selectedEquip[1], 1, s.owner.selectedEquip.slot) + s.owner.ship:AddMoney(-s.funcs.getSellPrice(s, s.owner.selectedEquip[1])) + end + + s.defaultFuncs.onBuyFailed(s, e, reason) + end +}) +end + +-- +-- ============================================================================= +-- Ship Equipment Widget Display +-- ============================================================================= +-- + +function EquipmentWidget.New(id) + local self = setmetatable({}, EquipmentWidget.meta) + + self.station = nil + self.showShipNameEdit = false + self.showEmptySlots = true + + self.selectedEquip = nil + self.selectedEquipSlots = nil + self.modelSpinner = ModelSpinner() + self.lastHoveredEquipLine = nil + self.lastHoveredEquipTag = nil + self.equipmentMarket = makeEquipmentMarket() + self.equipmentMarket.owner = self + self.tabs = { equipmentInfoTab } + self.activeTab = 1 + + self.id = id or "EquipmentWidget" + return self +end + +function EquipmentWidget:onEquipmentClicked(equipDetail, slots) + if self.station then + self.selectedEquip = equipDetail + self.selectedEquipSlots = slots + self.equipmentMarket:refresh() + self.equipmentMarket.scrollReset = true + end +end + +function EquipmentWidget:onEmptySlotClicked(slots) + if self.station then + self.selectedEquip = { nil, nil } + self.selectedEquipSlots = slots + self.equipmentMarket:refresh() + self.equipmentMarket.scrollReset = true + end +end + +equipmentInfoTab = { + name = l.EQUIPMENT, + draw = function(self) + local lineStartPos + ui.withFont(pionillium.body, function() + for i, v in ipairs(sections) do + lineStartPos = self:drawSection(v, lineStartPos) + end + end) + self.lastHoveredEquipLine = lineStartPos + end +} + +-- +-- ============================================================================= +-- Equipment Item Drawing Functions +-- ============================================================================= +-- + +-- Generate all UI data appropriate to the passed equipment item +local function makeEquipmentData(equip) + local out = { + icon = icons.systems_management, + name = equip:GetName(), + equip = equip + } + + if equip:Class() == EquipType.LaserType then + out.icon = icons.combattarget + table.insert(out, { + icons.comms, -- PLACEHOLDER + string.format("%d RPM", 60 / equip.laser_stats.rechargeTime), + le.SHOTS_PER_MINUTE + }) + table.insert(out, { + icons.ecm_advanced, + string.format("%.1f KW", equip.laser_stats.damage), + le.DAMAGE_PER_SHOT + }) + elseif equip:Class() == EquipType.HyperdriveType then + out.icon = icons.galaxy_map + elseif equip:Class() == EquipType.SensorType then + out.icon = icons.scanner + elseif equip == EquipType.misc.missile_unguided then + -- the existing missile icons are not properly sized / oriented + out.icon = icons.light_cargo_shuttle + elseif equip == EquipType.misc.missile_guided then + out.icon = icons.light_passenger_transport + elseif equip == EquipType.misc.missile_smart then + out.icon = icons.medium_passenger_transport + elseif equip == EquipType.misc.missile_naval then + out.icon = icons.heavy_courier + elseif utils.contains(equip.slots, "shield") then + out.icon = icons.shield + elseif utils.contains(equip.slots, "cabin") then + out.icon = icons.personal + elseif utils.contains(equip.slots, "radar") then + out.icon = icons.broadcast + elseif utils.contains(equip.slots, "autopilot") then + out.icon = icons.comms + end -- TODO: more data for different equip types + + local equipHealth = 1 + local equipMass = equip.capabilities.mass * 1000 + table.insert(out, { icons.hull, ui.Format.Mass(equipMass, 1), le.EQUIPMENT_WEIGHT }) + table.insert(out, { icons.repairs, string.format("%d%%", equipHealth * 100), le.EQUIPMENT_INTEGRITY }) + + return out +end + +-- Draw all visuals related to an individual equipment item. +-- This includes the background, highlight, icon, [slot type], +-- name, [size], and up to 4 sub-stats directly on the icon card +-- +-- DrawEquipmentItem* functions take a "data" argument table with the form: +-- name - translated name to display on the slot +-- equip - equipment object being drawn (or none for an empty slot) +-- type* - translated "slot type" name to display +-- size* - (short) string to be displayed in the "equipment size" field +-- [...] - up to 4 { icon, value, tooltip } data items for the stats line +function EquipmentWidget:drawEquipmentItem(data, isSelected, outPos) + -- initial indent + ui.setCursorPos(ui.getCursorPos() + Vector2(lineSpacing.x * 2, 0)) + local iconHeight = pionillium.body.size + pionillium.details.size + lineSpacing.y + local totalHeight = iconHeight + lineSpacing.y * 2 + local textWidth = ui.getContentRegion().x - iconHeight - lineSpacing.x * 2 + + -- calculate the background area + local highlightBegin = ui.getCursorScreenPos() + local highlightEnd = highlightBegin + Vector2(ui.getContentRegion().x, totalHeight) + + -- if we're hovered, we want to draw a little bar to the left of the background + local isHovered = ui.isMouseHoveringRect(highlightBegin, highlightEnd + Vector2(lineSpacing.y)) and ui.isWindowHovered() + if isHovered or isSelected then + ui.addRectFilled(highlightBegin - Vector2(4, 0), highlightBegin + Vector2(0, totalHeight), colors.equipScreenHighlight, 2, 5) + end + local bgColor = (isSelected and colors.tableSelection) or (isHovered and colors.tableHighlight) or colors.tableBackground + ui.addRectFilled(highlightBegin, highlightEnd, bgColor, 4, (isHovered or isSelected) and 10 or 0) -- 10 == top-right | bottom-right + local isClicked = isHovered and ui.isMouseClicked(0) + local hasTooltip = false + + ui.withStyleVars({ ItemSpacing = lineSpacing }, function() + -- Set up padding for the top and left sides + local pos = ui.getCursorPos() + lineSpacing + ui.setCursorPos(pos) + + -- Draw the icon and add some spacing next to it + ui.icon(data.icon, Vector2(iconHeight), colors.white) + pos = pos + Vector2(iconHeight + lineSpacing.x, 0) + ui.setCursorPos(pos) + + -- Draw the slot type + if data.type then + ui.text(data.type .. ":") + ui.sameLine() + end + + -- Draw the name of what's in the slot + local fontColor = data.name and colors.white or colors.equipScreenBgText + local name = data.name or ("[" .. le.EMPTY_SLOT .. "]") + ui.withStyleColors({ Text = fontColor }, function() ui.text(name) end) + + -- Draw the size of the slot + if data.size then + ui.setCursorPos(pos + Vector2(textWidth - ui.calcTextSize(data.size).x - lineSpacing.x, 0)) + ui.withStyleColors({ Text = colors.equipScreenBgText }, function() + ui.text(data.size) + end) + end + + -- Set up the details line + pos = pos + Vector2(0, ui.getTextLineHeightWithSpacing()) + ui.setCursorPos(pos) + ui.withFont(pionillium.details, function() + -- size of the small details icons + local smIconSize = Vector2(ui.getTextLineHeight()) + local fieldSize = textWidth * (1 / (4 - 0.3)) + + -- do all of the text first to generate as few draw commands as possible + for i, v in ipairs(data) do + local offset = fieldSize * (i - 1) + smIconSize.x + 2 + ui.setCursorPos(pos + Vector2(offset, 1)) -- HACK: force 1-pixel offset here to align baselines + ui.text(v[2]) + if v[3] and ui.isItemHovered() then + ui.withStyleVars({WindowPadding = lineSpacing, WindowRounding = 4}, function() + ui.setTooltip(v[3]) + hasTooltip = true + end) + end + end + + -- Then draw the icons + for i, v in ipairs(data) do + local offset = fieldSize * (i - 1) + ui.setCursorPos(pos + Vector2(offset, 0)) + ui.icon(v[1], smIconSize, colors.white) + end + + -- ensure we consume the appropriate amount of space if we don't have any details + if #data == 0 then + ui.newLine() + end + end) + + -- Add a bit of spacing after the slot + ui.spacing() + + if isHovered and data.equip and not hasTooltip then + self:drawEquipmentItemTooltip(data, isSelected) + end + end) + + return isClicked, isHovered and data.tagName and highlightEnd - Vector2(0, totalHeight / 2) or outPos +end + +-- Override this to draw any detailed tooltips +function EquipmentWidget:drawEquipmentItemTooltip(data, isSelected) + if data.equip then + local desc = data.equip:GetDescription() + if desc and #desc > 0 then ui.setTooltip(desc) end + end +end + +-- +-- ============================================================================= +-- Equipment Section Drawing Functions +-- ============================================================================= +-- + +-- Show an inline detail on a section header line with optional tooltip +local function drawHeaderDetail(cellEnd, text, icon, tooltip, textOffsetY) + local textStart = cellEnd - Vector2(ui.calcTextSize(text).x + lineSpacing.x, 0) + local iconPos = textStart - Vector2(iconSize.x + lineSpacing.x / 2, 0) + ui.setCursorPos(iconPos) + ui.icon(icon, iconSize, colors.white) + ui.setCursorPos(textStart + Vector2(0, textOffsetY or 0)) + ui.text(text) + local wp = ui.getWindowPos() + if tooltip and ui.isMouseHoveringRect(wp + iconPos, wp + cellEnd + Vector2(0, iconSize.y)) then + ui.setTooltip(tooltip) + end +end + +-- Draw an equipment section and all contained equipment items +function EquipmentWidget:drawSection(data, outPos) + local equipment = {} + local maxSlots = 0 + local totalWeight = 0 + + -- Gather all equipment items in the specified slot(s) for this section + -- TODO: this can be refactored once the equipment system has been overhauled + local slots = data.slots or { data.slot } + for _, name in ipairs(slots) do + local slot = Game.player:GetEquip(name) + maxSlots = maxSlots + Game.player:GetEquipSlotCapacity(name) + + for i, equip in pairs(slot) do + table.insert(equipment, { + equip, i, + slot = name, + mass = equip.capabilities.mass, + name = equip:GetName() + }) + totalWeight = totalWeight + (equip.capabilities.mass or 0) + end + end + + -- This function makes heavy use of draw cursor maniupulation to achieve + -- complicated layout goals + local sectionOpen, contentsPos, cursorPos + local cellWidth = ui.getContentRegion().x / 5 + local textOffsetY = (pionillium.heading.size - pionillium.body.size) / 2 + + ui.withFont(pionillium.heading, function() + ui.withStyleVars({FramePadding = lineSpacing}, function() + sectionOpen = ui.treeNode(data.name, { "FramePadding", (self.showEmptySlots or #equipment > 0) and "DefaultOpen" or nil }) + contentsPos = ui.getCursorPos() + ui.sameLine(0, 0) + cursorPos = ui.getCursorPos() + Vector2(0, lineSpacing.y) + end) + end) + + -- Show the total weight of all items in this section + local weightStr = ui.Format.Mass(totalWeight * 1000, 1) + local cellEnd = cursorPos + Vector2(ui.getContentRegion().x - lineSpacing.x, 0) + drawHeaderDetail(cellEnd, weightStr, icons.hull, le.TOTAL_MODULE_WEIGHT, textOffsetY) + + -- For sections with definite slot counts, show the number of used and total slots + if data.showCapacity then + local capacityStr = maxSlots > 0 and string.format("%d/%d", #equipment, maxSlots) or tostring(#equipment) + cellEnd = cellEnd - Vector2(cellWidth, 0) + drawHeaderDetail(cellEnd, capacityStr, icons.antinormal, le.TOTAL_MODULE_CAPACITY, textOffsetY) + end + + ui.setCursorPos(contentsPos) + if sectionOpen then + -- heaviest items to the top, then stably sort based on name + table.sort(equipment, function(a, b) + local mass = (a.mass or 0) - (b.mass or 0) + return mass > 0 or (mass == 0 and a.name < b.name) + end) + + -- Draw each equipment item in this section + for i, v in ipairs(equipment) do + local equipData, isClicked = makeEquipmentData(v[1]) + local isSelected = self.selectedEquip and (self.selectedEquip[1] == v[1] and self.selectedEquip[2] == v[2]) + isClicked, outPos = self:drawEquipmentItem(equipData, isSelected, outPos) + if isClicked then + self:onEquipmentClicked(v, slots) + end + end + + -- If we have more slots available in this section, show an empty slot + if maxSlots > 0 and #equipment < maxSlots and self.showEmptySlots then + local isClicked + local isSelected = self.selectedEquip and (not self.selectedEquip[1] and self.selectedEquipSlots[1] == slots[1]) + isClicked, outPos = self:drawEquipmentItem(emptySlot, isSelected, outPos) + + if isClicked then + self:onEmptySlotClicked(slots) + end + end + + ui.treePop() + end + + return outPos +end + +-- +-- ============================================================================= +-- Ship Spinner / Station Market Display +-- ============================================================================= +-- + +function EquipmentWidget:drawShipSpinner() + if not self.modelSpinner then self:refresh() end + + local shipDef = ShipDef[self.ship.shipId] + ui.group(function () + ui.withFont(ui.fonts.orbiteer.large, function() + if self.showShipNameEdit then + ui.alignTextToFramePadding() + ui.text(shipDef.name) + ui.sameLine() + ui.pushItemWidth(-1.0) + local entry, apply = ui.inputText("##ShipNameEntry", self.ship.shipName, ui.InputTextFlags {"EnterReturnsTrue"}) + ui.popItemWidth() + + if (apply) then self.ship:SetShipName(entry) end + else + ui.text(shipDef.name) + end + end) + + local startPos = ui.getCursorScreenPos() + + self.modelSpinner:setSize(ui.getContentRegion()) + self.modelSpinner:draw() + + -- WIP "physicalized component" display - draw a line between the equipment item + -- and the location in the ship where it is mounted + local lineStartPos = self.lastHoveredEquipLine + if lineStartPos then + local tagPos = startPos + self.modelSpinner:getTagPos(self.lastHoveredEquipTag) + local lineTurnPos = lineStartPos + Vector2(40, 0) + local dir = (tagPos - lineTurnPos):normalized() + ui.addLine(lineStartPos, lineTurnPos, colors.white, 2) + ui.addLine(lineTurnPos, tagPos - dir * 4, colors.white, 2) + ui.addCircle(tagPos, 4, colors.white, 16, 2) + end + end) +end + +function EquipmentWidget:drawMarketButtons(buttonLinePos) + ui.setCursorPos(buttonLinePos) + + if ui.button(l.GO_BACK, Vector2(0, 0)) then + self.selectedEquip = nil + return + end + ui.sameLine() + + if self.selectedEquip[1] then + local price = self.equipmentMarket.funcs.getSellPrice(self.equipmentMarket, self.selectedEquip[1]) + + if ui.button(l.SELL, Vector2(0, 0)) then + Game.player:RemoveEquip(self.selectedEquip[1], 1, self.selectedEquip.slot) + Game.player:AddMoney(price) + self.selectedEquip = { nil, nil } + return + end + ui.sameLine() + + local _pos = ui.getCursorPos() + ui.setCursorPos(buttonLinePos - Vector2(0, ui.getTextLineHeightWithSpacing())) + ui.text("Sell Price: " .. Format.Money(price)) + ui.setCursorPos(_pos) + end +end + +function EquipmentWidget:draw() + ui.withFont(pionillium.body, function() + ui.child("ShipInfo", Vector2(ui.getContentRegion().x * 1 / 3, 0), { "NoSavedSettings" }, function() + if #self.tabs > 1 then + if ui.beginTabBar("##tabs") then + for i = 1, #self.tabs do + if ui.beginTabItem(self.tabs[i].name) then + ui.spacing() + self.activeTab = i + self.tabs[i].draw(self) + ui.endTabItem() + end + end + ui.endTabBar() + end + else + self.tabs[1].draw(self) + end + end) + + ui.sameLine(0, lineSpacing.x * 2) + + ui.child("##container", function() + if self.tabs[self.activeTab] == equipmentInfoTab and self.station and self.selectedEquip then + local bottomControlsHeight = 0 + local _pos = ui.getCursorPos() + + ui.withFont(pionillium.heading, function() + bottomControlsHeight = ui.getFrameHeightWithSpacing() + ui.getTextLineHeightWithSpacing() + lineSpacing.y + local buttonLinePos = ui.getCursorPos() + Vector2(0, ui.getContentRegion().y - ui.getFrameHeightWithSpacing()) + self:drawMarketButtons(buttonLinePos) + ui.sameLine() + end) + + ui.setCursorPos(_pos) + self.equipmentMarket.style.size = ui.getContentRegion() - Vector2(0, bottomControlsHeight) + self.equipmentMarket:render() + else + self:drawShipSpinner() + end + end) + end) +end + +function EquipmentWidget:refresh() + self.selectedEquip = nil + self.selectedEquipSlots = nil + + local shipDef = ShipDef[self.ship.shipId] + self.modelSpinner:setModel(shipDef.modelName, self.ship:GetSkin(), self.ship.model.pattern) + self.modelSpinner.spinning = false +end + +function EquipmentWidget:debugReload() + package.reimport() +end + +return EquipmentWidget diff --git a/data/pigui/modules/info-view/01-ship-info.lua b/data/pigui/modules/info-view/01-ship-info.lua index 1cf15af60ec..3b3fe2523db 100644 --- a/data/pigui/modules/info-view/01-ship-info.lua +++ b/data/pigui/modules/info-view/01-ship-info.lua @@ -14,64 +14,22 @@ local ui = require 'pigui' local l = Lang.GetResource("ui-core") local fonts = ui.fonts - local textTable = require 'pigui.libs.text-table' --- use the old InfoView style layout instead of the new sidebar layout. -local _OLD_LAYOUT = true - -local modelSpinner - -local function resetModelSpinner() - modelSpinner = ModelSpinner() - local player = Game.player - local shipDef = ShipDef[player.shipId] - modelSpinner:setModel(shipDef.modelName, player:GetSkin(), player.model.pattern) -end - -local function shipSpinner() - if not modelSpinner then resetModelSpinner() end - local spinnerWidth = ui.getColumnWidth() - modelSpinner:setSize(Vector2(spinnerWidth, spinnerWidth / 1.5)) - - local player = Game.player - local shipDef = ShipDef[player.shipId] - ui.group(function () - local font = ui.fonts.orbiteer.large - ui.withFont(font.name, font.size, function() - ui.alignTextToFramePadding() - ui.text(shipDef.name) - ui.sameLine() - ui.pushItemWidth(-1.0) - local entry, apply = ui.inputText("##ShipNameEntry", player.shipName, ui.InputTextFlags {"EnterReturnsTrue"}) - ui.popItemWidth() - - if (apply) then player:SetShipName(entry) end - end) - modelSpinner:draw() - end) -end - -local collapsingHeaderFlags = ui.TreeNodeFlags { "DefaultOpen" } +local equipmentWidget = require 'pigui.libs.ship-equipment'.New("ShipInfo") local function shipStats() - local closed = ui.withFont(fonts.pionillium.medlarge, function() - return not ui.collapsingHeader(l.SHIP_INFORMATION, collapsingHeaderFlags) - end) - - -- TODO: draw info ontop of the header - - if closed then return end - local player = Game.player -- Taken directly from ShipInfo.lua. - local shipDef = ShipDef[player.shipId] - local shipLabel = player:GetLabel() - local hyperdrive = table.unpack(player:GetEquip("engine")) - local frontWeapon = table.unpack(player:GetEquip("laser_front")) - local rearWeapon = table.unpack(player:GetEquip("laser_rear")) + local shipDef = ShipDef[player.shipId] + local shipLabel = player:GetLabel() + local hyperdrive = table.unpack(player:GetEquip("engine")) + local frontWeapon = table.unpack(player:GetEquip("laser_front")) + local rearWeapon = table.unpack(player:GetEquip("laser_rear")) + local cabinEmpty = player:CountEquip(Equipment.misc.cabin, "cabin") + local cabinOccupied = player:CountEquip(Equipment.misc.cabin_occupied, "cabin") hyperdrive = hyperdrive or nil frontWeapon = frontWeapon or nil @@ -89,7 +47,7 @@ local function shipStats() atmo_shield_cap = atmo_shield.capabilities.atmo_shield end - textTable.draw { + textTable.draw({ { l.REGISTRATION_NUMBER..":", shipLabel}, { l.HYPERDRIVE..":", hyperdrive and hyperdrive:GetName() or l.NONE }, { @@ -116,51 +74,27 @@ local function shipStats() { l.BACKWARD_ACCEL..":", string.format("%.2f m/s² (%.1f g)", bwd_acc, bwd_acc / 9.81) }, { l.UP_ACCEL..":", string.format("%.2f m/s² (%.1f g)", up_acc, up_acc / 9.81) }, false, - { l.MINIMUM_CREW..":", shipDef.minCrew }, - { l.CREW_CABINS..":", shipDef.maxCrew }, + { l.MINIMUM_CREW..":", shipDef.minCrew }, + { l.CREW_CABINS..":", shipDef.maxCrew }, + { l.UNOCCUPIED_PASSENGER_CABINS..":", cabinEmpty }, + { l.OCCUPIED_PASSENGER_CABINS..":", cabinOccupied }, false, { l.MISSILE_MOUNTS..":", shipDef.equipSlotCapacity.missile}, { l.SCOOP_MOUNTS..":", shipDef.equipSlotCapacity.scoop}, false, { l.ATMOSPHERIC_SHIELDING..":", shipDef.equipSlotCapacity.atmo_shield > 0 and l.YES or l.NO }, { l.ATMO_PRESS_LIMIT..":", string.format("%d atm", shipDef.atmosphericPressureLimit * atmo_shield_cap) }, - } + }) end -local function equipmentList() - local closed = ui.withFont(fonts.pionillium.medlarge, function() - return not ui.collapsingHeader(l.EQUIPMENT, collapsingHeaderFlags) - end) - - if closed then return end - - -- TODO: there's definitely a better way to do this, but it's copied from ShipInfo.lua for now. - local equipItems = {} - local equips = {Equipment.cargo, Equipment.misc, Equipment.hyperspace, Equipment.laser} - for _,t in pairs(equips) do - for k,et in pairs(t) do - local slot = et:GetDefaultSlot(Game.player) - if (slot ~= "cargo" and slot ~= "missile" and slot ~= "engine" and slot ~= "laser_front" and slot ~= "laser_rear") then - local count = Game.player:CountEquip(et) - if count > 0 then - if count > 1 then - if et == Equipment.misc.shield_generator then - ui.text(string.interp(l.N_SHIELD_GENERATORS, { quantity = string.format("%d", count) })) - elseif et == Equipment.misc.cabin_occupied then - ui.text(string.interp(l.N_OCCUPIED_PASSENGER_CABINS, { quantity = string.format("%d", count) })) - elseif et == Equipment.misc.cabin then - ui.text(string.interp(l.N_UNOCCUPIED_PASSENGER_CABINS, { quantity = string.format("%d", count) })) - else - ui.text(et:GetName()) - end - else - ui.text(et:GetName()) - end - end - end - end +table.insert(equipmentWidget.tabs, 1, { + name = l.SHIP_INFORMATION, + draw = function() + ui.withStyleVars({ ItemSpacing = Vector2(8, 6) }, function() + shipStats() + end) end -end +}) InfoView:registerView({ id = "shipInfo", @@ -168,28 +102,20 @@ InfoView:registerView({ icon = ui.theme.icons.info, showView = true, draw = function() - ui.withFont(fonts.pionillium.medlarge, function() - if _OLD_LAYOUT then - ui.columns(2, "shipInfo") - - shipStats() - equipmentList() - ui.nextColumn() - - shipSpinner() - ui.columns(1, "") - else - shipSpinner() - shipStats() - equipmentList() - end - end) + equipmentWidget:draw() + end, + refresh = function() + equipmentWidget.ship = Game.player + equipmentWidget.showShipNameEdit = true + equipmentWidget.showEmptySlots = false + equipmentWidget:refresh() end, - refresh = function() end, - debugReload = function() package.reimport() end + debugReload = function() + equipmentWidget:debugReload() + package.reimport() + end }) -Event.Register("onGameStart", resetModelSpinner) Event.Register("onShipTypeChanged", function(ship) - if ship == Game.player then resetModelSpinner() end + if ship == Game.player then equipmentWidget:refresh() end end) diff --git a/data/pigui/modules/station-view/05-equipmentMarket.lua b/data/pigui/modules/station-view/05-equipmentMarket.lua index 506c86a63ee..c66e23c2703 100644 --- a/data/pigui/modules/station-view/05-equipmentMarket.lua +++ b/data/pigui/modules/station-view/05-equipmentMarket.lua @@ -3,171 +3,28 @@ local Lang = require 'Lang' local Game = require 'Game' -local Format = require 'Format' -local Equipment = require 'Equipment' local StationView = require 'pigui.views.station-view' -local EquipMarket = require 'pigui.libs.equipment-market' local ui = require 'pigui' -local pionillium = ui.fonts.pionillium local l = Lang.GetResource("ui-core") -local itemSpacing = ui.rescaleUI(Vector2(8, 4)) - -local hasTech = function (e) - local station = Game.player:GetDockedWith() - local equip_tech_level = e.tech_level or 1 -- default to 1 - - if type(equip_tech_level) == "string" then - if equip_tech_level == "MILITARY" then - return station.techLevel == 11 - else - error("Unknown tech level:\t"..equip_tech_level) - end - end - - assert(type(equip_tech_level) == "number") - return station.techLevel >= equip_tech_level -end - -local equipmentMarketStation -local equipmentMarketPlayer - -equipmentMarketStation = EquipMarket.New("EquipmentMarket", l.AVAILABLE_FOR_PURCHASE, { - itemTypes = { Equipment.cargo, Equipment.misc, Equipment.laser, Equipment.hyperspace }, - columnCount = 5, - initTable = function(self) - ui.setColumnWidth(0, self.style.size.x / 2.5) - ui.setColumnWidth(3, ui.calcTextSize(l.MASS).x + self.style.itemSpacing.x + self.style.itemPadding.x) - ui.setColumnWidth(4, ui.calcTextSize(l.IN_STOCK).x + self.style.itemSpacing.x + self.style.itemPadding.x) - end, - renderHeaderRow = function(self) - ui.text(l.NAME_OBJECT) - ui.nextColumn() - ui.text(l.BUY) - ui.nextColumn() - ui.text(l.SELL) - ui.nextColumn() - ui.text(l.MASS) - ui.nextColumn() - ui.text(l.IN_STOCK) - ui.nextColumn() - end, - renderItem = function(self, item) - ui.withTooltip(item:GetDescription(), function() - ui.text(item:GetName()) - ui.nextColumn() - ui.text(Format.Money(self.funcs.getBuyPrice(self, item))) - ui.nextColumn() - ui.text(Format.Money(self.funcs.getSellPrice(self, item))) - ui.nextColumn() - ui.text(item.capabilities.mass.."t") - ui.nextColumn() - ui.text(self.funcs.getStock(self, item)) - ui.nextColumn() - end) - end, - canDisplayItem = function (s, e) return e.purchasable and hasTech(e) and not e:IsValidSlot("cargo", Game.player) end, - onMouseOverItem = function(s, e) - local tooltip = e:GetDescription() - if string.len(tooltip) > 0 then - ui.withFont(pionillium.medium, function() ui.setTooltip(tooltip) end) - end - end, - onClickItem = function(s,e) - if s.funcs.onClickBuy(s, e) then - s.funcs.buy(s, e) - equipmentMarketStation:refresh() - equipmentMarketPlayer:refresh() - end - end -}) - -equipmentMarketPlayer = EquipMarket.New("EquipmentMarketPlayer", l.EQUIPPED, { - itemTypes = { Equipment.cargo, Equipment.misc, Equipment.laser, Equipment.hyperspace }, - columnCount = 4, - initTable = function(self) - ui.setColumnWidth(0, self.style.size.x / 3) - end, - renderHeaderRow = function(self) - ui.text(l.NAME_OBJECT) - ui.nextColumn() - ui.text(l.AMOUNT) - ui.nextColumn() - ui.text(l.MASS) - ui.nextColumn() - ui.text(l.TOTAL_MASS) - ui.nextColumn() - end, - renderItem = function(self, item) - ui.text(item:GetName()) - ui.nextColumn() - ui.text(self.funcs.getStock(self, item)) - ui.nextColumn() - ui.text(item.capabilities.mass.."t") - ui.nextColumn() - ui.text(tostring(self.funcs.getStock(self, item) * item.capabilities.mass) .. "t") - ui.nextColumn() - end, - onClickSell = function (self, e) - if e:IsValidSlot("cargo", Game.player) and not e.purchasable then - self.popup.msg = l.CANNOT_SELL_ITEM - self.popup:open() - return false - end - - if not hasTech(e) then - self.popup.msg = l.STATION_TECH_TOO_LOW - self.popup:open() - return false - end - - return true - end, - canDisplayItem = function (s, e) return e.purchasable and Game.player:CountEquip(e) > 0 and not e:IsValidSlot("cargo", Game.player) end, - getStock = function (s, e) return Game.player:CountEquip(e) end, - onMouseOverItem = function(s, e) - local tooltip = e:GetDescription() - if string.len(tooltip) > 0 then ui.setTooltip(tooltip) end - end, - onClickItem = function(s,e) - if s.funcs.onClickSell(s, e) then - s.funcs.sell(s, e) - equipmentMarketStation:refresh() - equipmentMarketPlayer:refresh() - end - end -}) - -local function drawEquipmentView() - ui.withFont(pionillium.medlarge.name, pionillium.medlarge.size, function() - local padding = equipmentMarketStation.style.itemPadding.x - local width = (ui.getContentRegion().x - padding) / 2.0 - - ui.child("equipmentMarketStation", Vector2(width, 0), {}, function() - equipmentMarketStation.style.size = ui.getContentRegion() - equipmentMarketStation:render() - end) - - ui.sameLine(0, padding) - - ui.child("equipmentMarketPlayer", Vector2(width, 0), {}, function() - equipmentMarketPlayer.style.size = ui.getContentRegion() - equipmentMarketPlayer:render() - end) - end) -end +local equipmentWidget = require 'pigui.libs.ship-equipment'.New("ShipInfo") StationView:registerView({ id = "equipmentMarketView", name = l.EQUIPMENT_MARKET, icon = ui.theme.icons.equipment, showView = true, - draw = drawEquipmentView, + draw = function() + equipmentWidget:draw() + end, refresh = function() - equipmentMarketStation:refresh() - equipmentMarketPlayer:refresh() - equipmentMarketStation.scrollReset = true - equipmentMarketPlayer.scrollReset = true + equipmentWidget.ship = Game.player + equipmentWidget.station = Game.player:GetDockedWith() + equipmentWidget:refresh() end, + debugReload = function() + equipmentWidget:debugReload() + package.reimport() + end }) diff --git a/data/pigui/themes/default.lua b/data/pigui/themes/default.lua index dcdc4ff01ea..0ce95f8238c 100644 --- a/data/pigui/themes/default.lua +++ b/data/pigui/themes/default.lua @@ -102,6 +102,7 @@ theme.colors = { blueFrame = styleColors.accent_100:shade(0.50), tableHighlight = styleColors.primary_700, tableSelection = styleColors.accent_300:shade(0.40), + tableBackground = styleColors.primary_800, commsWindowBackground = styleColors.primary_700:opacity(0.30), buttonBlue = styleColors.primary_300, buttonInk = styleColors.white, @@ -163,12 +164,16 @@ theme.colors = { systemMapLagrangePoint = styleColors.accent_200, sectorMapLabelHighlight = styleColors.white:opacity(0.5), - sectorMapLabelShade = styleColors.primary_700:opacity(0.8) + sectorMapLabelShade = styleColors.primary_700:opacity(0.8), + + equipScreenHighlight = styleColors.gray_300, + equipScreenBgText = styleColors.gray_400, } -- ImGui global theming styles theme.styles = { WindowBorderSize = 0.0, + TabRounding = 0.0, } theme.icons = { From d538302d9f06f3e23bca655fc453a8478bc21eae Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Sun, 9 Jan 2022 17:54:05 -0500 Subject: [PATCH 02/10] Add new equipment icons --- data/icons/icons.svg | 15892 +++++++++++++++++++++++---- data/libs/Equipment.lua | 122 +- data/pigui/baseui.lua | 8 - data/pigui/libs/icons.lua | 23 +- data/pigui/libs/ship-equipment.lua | 31 +- data/pigui/themes/default.lua | 43 + 6 files changed, 13669 insertions(+), 2450 deletions(-) diff --git a/data/icons/icons.svg b/data/icons/icons.svg index 3f66e6da090..e6ecd4208ac 100644 --- a/data/icons/icons.svg +++ b/data/icons/icons.svg @@ -1,2389 +1,13531 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 819  - -205  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Icon + + + + + + + Icon + + + + + + + + + + Icon + + + + Icon + + + + + + + + + + + Icon + + + + + + + + + + + + + + Icon + + + + + + + + + + + + + + + + + + + + Icon + + + + Icon + + + + + + + + + + + Icon + + + + + + + + + + Icon + + + + + + + + + Icon + + + + + Icon + + + + + + + + + + Icon + + + + + + + + + + ! + + + + + ! + ! + + + + ! + + ! + ! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ! + + ! + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Icon Medium Courier + + + + + + + + + Icon Light courier + + + + + + + + Icon Medium Passegner Shuttle + + + + + Icon Light Passegner Shuttle + + + + + + + + + Icon Heavy Courier + + + + + + + + + Icon Heavy Passegner Shuttle + + + + + Icon Medium Passegner Transport + + + + + Icon Heavy Passegner Transport + + + + + Icon Light Passegner Transport + + + + + Icon Medium Cargo Shuttle + + + + + + + + Icon Light Cargo Shuttle + + + + + + + + Icon Heavy Cargo Shuttle + + + + + + Icon Medium Cargo Transport + + + + + + + + Icon Light Cargo Transport + + + + + + + + Icon Heavy Cargo Transport + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Icon + + + + + Icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + follow-ori + + + + + + + follow-pos + + + + + + + follow-icon-circle + + + + + + + follow-icon-circle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + follow-icon-filled-circle + + + + - - + + manual-flight + + + + + + + - - - - - - - + + manual-flight + + + + + + + - - + + follow-icon-circle + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + follow-icon-circle + + + + + + + + + + - - + + + + + + + + + + + + - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Icon - - - - - - - Icon - - - - - - - - - - Icon - - - - Icon - - - - - - - - - - - Icon - - - - - - - - - - - - - - Icon - - - - - - - - - - - - - - - - - - - - Icon - - - - Icon - - - - - - - - - - - Icon - - - - - - - - - - Icon - - - - - - - - - Icon - - - - - Icon - - - - - - - - - - Icon - - - - - - - - - - ! - - - - - ! - ! - - - - ! - - ! - ! - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ! - - ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Icon Medium Courier - - - - - - - - - Icon Light courier - - - - - - - - Icon Medium Passegner Shuttle - - - - - Icon Light Passegner Shuttle - - - - - - - - - Icon Heavy Courier - - - - - - - - - Icon Heavy Passegner Shuttle - - - - - Icon Medium Passegner Transport - - - - - Icon Heavy Passegner Transport - - - - - Icon Light Passegner Transport - - - - - Icon Medium Cargo Shuttle - - - - - - - - Icon Light Cargo Shuttle - - - - - - - - Icon Heavy Cargo Shuttle - - - - - - Icon Medium Cargo Transport - - - - - - - - Icon Light Cargo Transport - - - - - - - - Icon Heavy Cargo Transport - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Icon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Icon - - - - - Icon - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Icon + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/libs/Equipment.lua b/data/libs/Equipment.lua index 27badb1a89d..52ea437e5d8 100644 --- a/data/libs/Equipment.lua +++ b/data/libs/Equipment.lua @@ -54,35 +54,37 @@ misc.missile_unguided = EquipType.New({ l10n_key="MISSILE_UNGUIDED", slots="missile", price=30, missile_type="missile_unguided", tech_level=1, capabilities={mass=1, missile=1}, purchasable=true, - icon_name="missile_unguided" + icon_name="equip_missile_unguided" }) misc.missile_guided = EquipType.New({ l10n_key="MISSILE_GUIDED", slots="missile", price=50, missile_type="missile_guided", tech_level=5, capabilities={mass=1}, purchasable=true, - icon_name="missile_guided" + icon_name="equip_missile_guided" }) misc.missile_smart = EquipType.New({ l10n_key="MISSILE_SMART", slots="missile", price=95, missile_type="missile_smart", tech_level=10, capabilities={mass=1}, purchasable=true, - icon_name="missile_smart" + icon_name="equip_missile_smart" }) misc.missile_naval = EquipType.New({ l10n_key="MISSILE_NAVAL", slots="missile", price=160, missile_type="missile_naval", tech_level="MILITARY", capabilities={mass=1}, purchasable=true, - icon_name="missile_naval" + icon_name="equip_missile_naval" }) misc.atmospheric_shielding = EquipType.New({ l10n_key="ATMOSPHERIC_SHIELDING", slots="atmo_shield", price=200, capabilities={mass=1, atmo_shield=9}, - purchasable=true, tech_level=3 + purchasable=true, tech_level=3, + icon_name="equip_atmo_shield_generator" }) misc.heavy_atmospheric_shielding = EquipType.New({ l10n_key="ATMOSPHERIC_SHIELDING_HEAVY", slots="atmo_shield", price=900, capabilities={mass=2, atmo_shield=19}, - purchasable=true, tech_level=5 + purchasable=true, tech_level=5, + icon_name="equip_atmo_shield_generator" }) misc.ecm_basic = EquipType.New({ l10n_key="ECM_BASIC", slots="ecm", price=6000, @@ -97,20 +99,24 @@ misc.ecm_advanced = EquipType.New({ misc.radar = EquipType.New({ l10n_key="RADAR", slots="radar", price=680, capabilities={mass=1, radar=1}, - purchasable=true, tech_level=3 + purchasable=true, tech_level=3, + icon_name="equip_radar" }) misc.cabin = EquipType.New({ l10n_key="UNOCCUPIED_CABIN", slots="cabin", price=1350, capabilities={mass=1, cabin=1}, - purchasable=true, tech_level=1 + purchasable=true, tech_level=1, + icon_name="equip_cabin_empty" }) misc.cabin_occupied = EquipType.New({ l10n_key="PASSENGER_CABIN", slots="cabin", price=0, - capabilities={mass=1}, purchasable=false, tech_level=1 + capabilities={mass=1}, purchasable=false, tech_level=1, + icon_name="equip_cabin_occupied" }) misc.shield_generator = EquipType.New({ l10n_key="SHIELD_GENERATOR", slots="shield", price=2500, - capabilities={mass=4, shield=1}, purchasable=true, tech_level=8 + capabilities={mass=4, shield=1}, purchasable=true, tech_level=8, + icon_name="equip_shield_generator" }) misc.laser_cooling_booster = EquipType.New({ l10n_key="LASER_COOLING_BOOSTER", slots="laser_cooler", price=380, @@ -122,31 +128,38 @@ misc.cargo_life_support = EquipType.New({ }) misc.autopilot = EquipType.New({ l10n_key="AUTOPILOT", slots="autopilot", price=1400, - capabilities={mass=1, set_speed=1, autopilot=1}, purchasable=true, tech_level=1 + capabilities={mass=1, set_speed=1, autopilot=1}, purchasable=true, tech_level=1, + icon_name="equip_autopilot" }) misc.target_scanner = EquipType.New({ l10n_key="TARGET_SCANNER", slots="target_scanner", price=900, - capabilities={mass=1, target_scanner_level=1}, purchasable=true, tech_level=9 + capabilities={mass=1, target_scanner_level=1}, purchasable=true, tech_level=9, + icon_name="equip_scanner" }) misc.advanced_target_scanner = EquipType.New({ l10n_key="ADVANCED_TARGET_SCANNER", slots="target_scanner", price=1200, - capabilities={mass=1, target_scanner_level=2}, purchasable=true, tech_level="MILITARY" + capabilities={mass=1, target_scanner_level=2}, purchasable=true, tech_level="MILITARY", + icon_name="equip_scanner" }) misc.fuel_scoop = EquipType.New({ l10n_key="FUEL_SCOOP", slots="scoop", price=3500, - capabilities={mass=6, fuel_scoop=3}, purchasable=true, tech_level=4 + capabilities={mass=6, fuel_scoop=3}, purchasable=true, tech_level=4, + icon_name="equip_fuel_scoop" }) misc.cargo_scoop = EquipType.New({ l10n_key="CARGO_SCOOP", slots="scoop", price=3900, - capabilities={mass=7, cargo_scoop=1}, purchasable=true, tech_level=5 + capabilities={mass=7, cargo_scoop=1}, purchasable=true, tech_level=5, + icon_name="equip_cargo_scoop" }) misc.multi_scoop = EquipType.New({ l10n_key="MULTI_SCOOP", slots="scoop", price=12000, - capabilities={mass=9, cargo_scoop=1, fuel_scoop=2}, purchasable=true, tech_level=9 + capabilities={mass=9, cargo_scoop=1, fuel_scoop=2}, purchasable=true, tech_level=9, + icon_name="equip_multi_scoop" }) misc.hypercloud_analyzer = EquipType.New({ l10n_key="HYPERCLOUD_ANALYZER", slots="hypercloud", price=1500, - capabilities={mass=1, hypercloud_analyzer=1}, purchasable=true, tech_level=10 + capabilities={mass=1, hypercloud_analyzer=1}, purchasable=true, tech_level=10, + icon_name="equip_scanner" }) misc.shield_energy_booster = EquipType.New({ l10n_key="SHIELD_ENERGY_BOOSTER", slots="energy_booster", price=10000, @@ -154,109 +167,130 @@ misc.shield_energy_booster = EquipType.New({ }) misc.hull_autorepair = EquipType.New({ l10n_key="HULL_AUTOREPAIR", slots="hull_autorepair", price=16000, - capabilities={mass=40, hull_autorepair=1}, purchasable=true, tech_level="MILITARY" + capabilities={mass=40, hull_autorepair=1}, purchasable=true, tech_level="MILITARY", + icon_name="repairs" }) misc.thrusters_basic = EquipType.New({ l10n_key="THRUSTERS_BASIC", slots="thruster", price=3000, tech_level=5, capabilities={mass=0, thruster_power=1}, purchasable=true, - icon_name="thrusters_basic" + icon_name="equip_thrusters_basic" }) misc.thrusters_medium = EquipType.New({ l10n_key="THRUSTERS_MEDIUM", slots="thruster", price=6500, tech_level=8, capabilities={mass=0, thruster_power=2}, purchasable=true, - icon_name="thrusters_medium" + icon_name="equip_thrusters_medium" }) misc.thrusters_best = EquipType.New({ l10n_key="THRUSTERS_BEST", slots="thruster", price=14000, tech_level="MILITARY", capabilities={mass=0, thruster_power=3}, purchasable=true, - icon_name="thrusters_best" + icon_name="equip_thrusters_best" }) misc.trade_computer = EquipType.New({ l10n_key="TRADE_COMPUTER", slots="trade_computer", price=400, - capabilities={mass=0, trade_computer=1}, purchasable=true, tech_level=9 + capabilities={mass=0, trade_computer=1}, purchasable=true, tech_level=9, + icon_name="equip_trade_computer" }) misc.planetscanner = BodyScannerType.New({ l10n_key = 'PLANETSCANNER', slots="sensor", price=15000, capabilities={mass=1,sensor=1}, purchasable=false, tech_level=1, icon_on_name="body_scanner_on", icon_off_name="body_scanner_off", max_range=100000000, target_altitude=0, state="HALTED", progress=0, - bodyscanner_stats={scan_speed=3, scan_tolerance=0.05} + bodyscanner_stats={scan_speed=3, scan_tolerance=0.05}, + icon_name="equip_planet_scanner" }) hyperspace.hyperdrive_1 = HyperdriveType.New({ l10n_key="DRIVE_CLASS1", fuel=cargo.hydrogen, slots="engine", price=700, capabilities={mass=4, hyperclass=1}, purchasable=true, tech_level=3, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_2 = HyperdriveType.New({ l10n_key="DRIVE_CLASS2", fuel=cargo.hydrogen, slots="engine", price=1300, capabilities={mass=10, hyperclass=2}, purchasable=true, tech_level=4, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_3 = HyperdriveType.New({ l10n_key="DRIVE_CLASS3", fuel=cargo.hydrogen, slots="engine", price=2500, capabilities={mass=20, hyperclass=3}, purchasable=true, tech_level=4, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_4 = HyperdriveType.New({ l10n_key="DRIVE_CLASS4", fuel=cargo.hydrogen, slots="engine", price=5000, capabilities={mass=40, hyperclass=4}, purchasable=true, tech_level=5, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_5 = HyperdriveType.New({ l10n_key="DRIVE_CLASS5", fuel=cargo.hydrogen, slots="engine", price=10000, capabilities={mass=120, hyperclass=5}, purchasable=true, tech_level=5, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_6 = HyperdriveType.New({ l10n_key="DRIVE_CLASS6", fuel=cargo.hydrogen, slots="engine", price=20000, capabilities={mass=225, hyperclass=6}, purchasable=true, tech_level=6, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_7 = HyperdriveType.New({ l10n_key="DRIVE_CLASS7", fuel=cargo.hydrogen, slots="engine", price=30000, capabilities={mass=400, hyperclass=7}, purchasable=true, tech_level=8, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_8 = HyperdriveType.New({ l10n_key="DRIVE_CLASS8", fuel=cargo.hydrogen, slots="engine", price=60000, capabilities={mass=580, hyperclass=8}, purchasable=true, tech_level=9, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_9 = HyperdriveType.New({ l10n_key="DRIVE_CLASS9", fuel=cargo.hydrogen, slots="engine", price=120000, capabilities={mass=740, hyperclass=9}, purchasable=true, tech_level=10, + icon_name="equip_hyperdrive" }) hyperspace.hyperdrive_mil1 = HyperdriveType.New({ l10n_key="DRIVE_MIL1", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=23000, capabilities={mass=3, hyperclass=1}, purchasable=true, tech_level=10, + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil2 = HyperdriveType.New({ l10n_key="DRIVE_MIL2", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=47000, capabilities={mass=8, hyperclass=2}, purchasable=true, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil3 = HyperdriveType.New({ l10n_key="DRIVE_MIL3", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=85000, capabilities={mass=16, hyperclass=3}, purchasable=true, tech_level=11, + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil4 = HyperdriveType.New({ l10n_key="DRIVE_MIL4", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=214000, capabilities={mass=30, hyperclass=4}, purchasable=true, tech_level=12, + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil5 = HyperdriveType.New({ l10n_key="DRIVE_MIL5", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=540000, capabilities={mass=53, hyperclass=5}, purchasable=false, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil6 = HyperdriveType.New({ l10n_key="DRIVE_MIL6", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=1350000, capabilities={mass=78, hyperclass=6}, purchasable=false, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil7 = HyperdriveType.New({ l10n_key="DRIVE_MIL7", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=3500000, capabilities={mass=128, hyperclass=7}, purchasable=false, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil8 = HyperdriveType.New({ l10n_key="DRIVE_MIL8", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=8500000, capabilities={mass=196, hyperclass=8}, purchasable=false, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) hyperspace.hyperdrive_mil9 = HyperdriveType.New({ l10n_key="DRIVE_MIL9", fuel=cargo.military_fuel, byproduct=cargo.radioactives, slots="engine", price=22000000, capabilities={mass=285, hyperclass=9}, purchasable=false, tech_level="MILITARY", + icon_name="equip_hyperdrive_mil" }) laser.pulsecannon_1mw = LaserType.New({ @@ -264,28 +298,32 @@ laser.pulsecannon_1mw = LaserType.New({ slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=1000, rechargeTime=0.25, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 255, rgba_g = 51, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=3 + }, purchasable=true, tech_level=3, + icon_name="equip_pulsecannon" }) laser.pulsecannon_dual_1mw = LaserType.New({ l10n_key="PULSECANNON_DUAL_1MW", price=1100, capabilities={mass=4}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=1000, rechargeTime=0.25, length=30, width=5, beam=0, dual=1, mining=0, rgba_r = 255, rgba_g = 51, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=4 + }, purchasable=true, tech_level=4, + icon_name="equip_dual_pulsecannon" }) laser.pulsecannon_2mw = LaserType.New({ l10n_key="PULSECANNON_2MW", price=1000, capabilities={mass=3}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=2000, rechargeTime=0.25, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 255, rgba_g = 127, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=5 + }, purchasable=true, tech_level=5, + icon_name="equip_pulsecannon" }) laser.pulsecannon_rapid_2mw = LaserType.New({ l10n_key="PULSECANNON_RAPID_2MW", price=1800, capabilities={mass=7}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=2000, rechargeTime=0.13, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 255, rgba_g = 127, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=5 + }, purchasable=true, tech_level=5, + icon_name="equip_pulsecannon_rapid" }) laser.beamlaser_1mw = LaserType.New({ l10n_key="BEAMLASER_1MW", price=2400, capabilities={mass=3}, @@ -293,7 +331,8 @@ laser.beamlaser_1mw = LaserType.New({ lifespan=8, speed=1000, damage=1500, rechargeTime=0.25, length=10000, width=1, beam=1, dual=0, mining=0, rgba_r = 255, rgba_g = 51, rgba_b = 127, rgba_a = 255, heatrate=0.02, coolrate=0.01 - }, purchasable=true, tech_level=4 + }, purchasable=true, tech_level=4, + icon_name="equip_beamlaser" }) laser.beamlaser_dual_1mw = LaserType.New({ l10n_key="BEAMLASER_DUAL_1MW", price=4800, capabilities={mass=6}, @@ -301,7 +340,8 @@ laser.beamlaser_dual_1mw = LaserType.New({ lifespan=8, speed=1000, damage=1500, rechargeTime=0.5, length=10000, width=1, beam=1, dual=1, mining=0, rgba_r = 255, rgba_g = 51, rgba_b = 127, rgba_a = 255, heatrate=0.02, coolrate=0.01 - }, purchasable=true, tech_level=5 + }, purchasable=true, tech_level=5, + icon_name="equip_dual_beamlaser" }) laser.beamlaser_2mw = LaserType.New({ l10n_key="BEAMLASER_RAPID_2MW", price=5600, capabilities={mass=7}, @@ -309,56 +349,64 @@ laser.beamlaser_2mw = LaserType.New({ lifespan=8, speed=1000, damage=3000, rechargeTime=0.13, length=20000, width=1, beam=1, dual=0, mining=0, rgba_r = 255, rgba_g = 192, rgba_b = 192, rgba_a = 255, heatrate=0.02, coolrate=0.01 - }, purchasable=true, tech_level=6 + }, purchasable=true, tech_level=6, + icon_name="equip_beamlaser" }) laser.pulsecannon_4mw = LaserType.New({ l10n_key="PULSECANNON_4MW", price=2200, capabilities={mass=10}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=4000, rechargeTime=0.25, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 255, rgba_g = 255, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=6 + }, purchasable=true, tech_level=6, + icon_name="equip_pulsecannon" }) laser.pulsecannon_10mw = LaserType.New({ l10n_key="PULSECANNON_10MW", price=4900, capabilities={mass=30}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=10000, rechargeTime=0.25, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 51, rgba_g = 255, rgba_b = 51, rgba_a = 255 - }, purchasable=true, tech_level=7 + }, purchasable=true, tech_level=7, + icon_name="equip_pulsecannon" }) laser.pulsecannon_20mw = LaserType.New({ l10n_key="PULSECANNON_20MW", price=12000, capabilities={mass=65}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=20000, rechargeTime=0.25, length=30, width=5, beam=0, dual=0, mining=0, rgba_r = 0.1, rgba_g = 51, rgba_b = 255, rgba_a = 255 - }, purchasable=true, tech_level="MILITARY" + }, purchasable=true, tech_level="MILITARY", + icon_name="equip_pulsecannon" }) laser.miningcannon_5mw = LaserType.New({ l10n_key="MININGCANNON_5MW", price=3700, capabilities={mass=6}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=5000, rechargeTime=1.5, length=30, width=5, beam=0, dual=0, mining=1, rgba_r = 51, rgba_g = 127, rgba_b = 0, rgba_a = 255 - }, purchasable=true, tech_level=5 + }, purchasable=true, tech_level=5, + icon_name="equip_mining_laser" }) laser.miningcannon_17mw = LaserType.New({ l10n_key="MININGCANNON_17MW", price=10600, capabilities={mass=10}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=17000, rechargeTime=2, length=30, width=5, beam=0, dual=0, mining=1, rgba_r = 51, rgba_g = 127, rgba_b = 0, rgba_a = 255 - }, purchasable=true, tech_level=8 + }, purchasable=true, tech_level=8, + icon_name="equip_mining_laser" }) laser.small_plasma_accelerator = LaserType.New({ l10n_key="SMALL_PLASMA_ACCEL", price=120000, capabilities={mass=22}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=50000, rechargeTime=0.3, length=42, width=7, beam=0, dual=0, mining=0, rgba_r = 51, rgba_g = 255, rgba_b = 255, rgba_a = 255 - }, purchasable=true, tech_level=10 + }, purchasable=true, tech_level=10, + icon_name="equip_plasma_accelerator" }) laser.large_plasma_accelerator = LaserType.New({ l10n_key="LARGE_PLASMA_ACCEL", price=390000, capabilities={mass=50}, slots = {"laser_front", "laser_rear"}, laser_stats = { lifespan=8, speed=1000, damage=100000, rechargeTime=0.3, length=42, width=7, beam=0, dual=0, mining=0, rgba_r = 127, rgba_g = 255, rgba_b = 255, rgba_a = 255 - }, purchasable=true, tech_level=12 + }, purchasable=true, tech_level=12, + icon_name="equip_plasma_accelerator" }) local serialize = function() diff --git a/data/pigui/baseui.lua b/data/pigui/baseui.lua index 0dd0a37c094..cadebcfe690 100644 --- a/data/pigui/baseui.lua +++ b/data/pigui/baseui.lua @@ -40,14 +40,6 @@ function ui.makeFullScreenHandler(window_name, window_fnc) end end -function ui.get_icon_tex_coords(icon) - assert(icon, "no icon given") - local count = 16.0 -- icons per row/column - local rem = math.floor(icon % count) - local quot = math.floor(icon / count) - return Vector2(rem / count, quot/count), Vector2((rem+1) / count, (quot+1)/count) -end - function ui.circleSegments(radius) if radius < 5 then return 8 diff --git a/data/pigui/libs/icons.lua b/data/pigui/libs/icons.lua index aa1946c92d0..0be96ce3fa4 100644 --- a/data/pigui/libs/icons.lua +++ b/data/pigui/libs/icons.lua @@ -4,17 +4,26 @@ local Engine = require 'Engine' local ui = require 'pigui.baseui' local pigui = Engine.pigui +local iconsX = 16 +local iconsY = 19 + +local icons_texture_small = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), iconsX * 24, iconsY * 24) +local icons_texture_med = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), iconsX * 32, iconsY * 32) +local icons_texture_large = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), iconsX * 64, iconsY * 64) + local function get_wide_icon_tex_coords(icon) assert(icon, "no icon given") - local count = 16.0 -- icons per row/column - local rem = math.floor(icon % count) - local quot = math.floor(icon / count) - return Vector2(rem / count, quot/count), Vector2((rem+2) / count, (quot+1)/count) + local rem = math.floor(icon % iconsX) + local quot = math.floor(icon / iconsX) + return Vector2(rem / iconsX, quot/iconsY), Vector2((rem+2) / iconsX, (quot+1)/iconsY) end -local icons_texture_small = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), 16 * 24, 16 * 24) -local icons_texture_med = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), 16 * 32, 16 * 32) -local icons_texture_large = pigui:LoadTextureFromSVG(pigui.DataDirPath({"icons", "icons.svg"}), 16 * 64, 16 * 64) +function ui.get_icon_tex_coords(icon) + assert(icon, "no icon given") + local rem = math.floor(icon % iconsX) + local quot = math.floor(icon / iconsX) + return Vector2(rem / iconsX, quot/iconsY), Vector2((rem+1) / iconsX, (quot+1)/iconsY) +end function ui.get_icons_texture(size) if size.x > 32.0 or size.y > 32.0 then diff --git a/data/pigui/libs/ship-equipment.lua b/data/pigui/libs/ship-equipment.lua index 2b87a1360d7..2478c8c2f1b 100644 --- a/data/pigui/libs/ship-equipment.lua +++ b/data/pigui/libs/ship-equipment.lua @@ -219,13 +219,12 @@ equipmentInfoTab = { -- Generate all UI data appropriate to the passed equipment item local function makeEquipmentData(equip) local out = { - icon = icons.systems_management, + icon = equip.icon_name and icons[equip.icon_name] or icons.systems_management, name = equip:GetName(), equip = equip } if equip:Class() == EquipType.LaserType then - out.icon = icons.combattarget table.insert(out, { icons.comms, -- PLACEHOLDER string.format("%d RPM", 60 / equip.laser_stats.rechargeTime), @@ -236,27 +235,13 @@ local function makeEquipmentData(equip) string.format("%.1f KW", equip.laser_stats.damage), le.DAMAGE_PER_SHOT }) - elseif equip:Class() == EquipType.HyperdriveType then - out.icon = icons.galaxy_map - elseif equip:Class() == EquipType.SensorType then - out.icon = icons.scanner - elseif equip == EquipType.misc.missile_unguided then - -- the existing missile icons are not properly sized / oriented - out.icon = icons.light_cargo_shuttle - elseif equip == EquipType.misc.missile_guided then - out.icon = icons.light_passenger_transport - elseif equip == EquipType.misc.missile_smart then - out.icon = icons.medium_passenger_transport - elseif equip == EquipType.misc.missile_naval then - out.icon = icons.heavy_courier - elseif utils.contains(equip.slots, "shield") then - out.icon = icons.shield - elseif utils.contains(equip.slots, "cabin") then - out.icon = icons.personal - elseif utils.contains(equip.slots, "radar") then - out.icon = icons.broadcast - elseif utils.contains(equip.slots, "autopilot") then - out.icon = icons.comms + -- elseif equip:Class() == EquipType.HyperdriveType then + -- elseif equip:Class() == EquipType.SensorType then + -- elseif utils.contains(equip.slots, "missile") then + -- elseif utils.contains(equip.slots, "shield") then + -- elseif utils.contains(equip.slots, "cabin") then + -- elseif utils.contains(equip.slots, "radar") then + -- elseif utils.contains(equip.slots, "autopilot") then end -- TODO: more data for different equip types local equipHealth = 1 diff --git a/data/pigui/themes/default.lua b/data/pigui/themes/default.lua index 0ce95f8238c..0c4a1121c3d 100644 --- a/data/pigui/themes/default.lua +++ b/data/pigui/themes/default.lua @@ -438,6 +438,49 @@ theme.icons = { station_orbital_small = 248, station_observatory = 249, cargo_crate_illegal = 255, + -- seventeenth row + -- reticle icons 256..268 + -- EMPTY = 269, + -- EMPTY = 270, + -- EMPTY = 271, + -- eighteenth row + equip_cargo_scoop = 272, + equip_fuel_scoop = 273, + equip_multi_scoop = 274, + equip_beamlaser = 275, + equip_plasma_accelerator = 276, + equip_pulsecannon = 277, + equip_pulsecannon_rapid = 278, + equip_mining_laser = 279, + equip_dual_beamlaser = 280, + equip_dual_plasma_accelerator = 281, + equip_dual_pulsecannon = 282, + equip_dual_pulsecannon_rapid = 283, + equip_dual_mining_laser = 284, + -- EMPTY = 285, + -- EMPTY = 286, + -- EMPTY = 287, + -- nineteenth row + equip_missile_unguided = 288, + equip_missile_guided = 289, + equip_missile_smart = 290, + equip_missile_naval = 291, + equip_shield_generator = 292, + equip_atmo_shield_generator = 293, + equip_scanner = 294, + equip_radar = 295, + equip_planet_scanner = 296, + equip_generic = 297, + equip_cabin_empty = 298, + equip_cabin_occupied = 299, + equip_thrusters = 300, + -- TODO: distinct icons for these + equip_thrusters_basic = 300, + equip_thrusters_medium = 300, + equip_thrusters_best = 300, + equip_trade_computer = 301, + equip_autopilot = 302, + equip_hyperdrive = 303, -- TODO: manual / autopilot -- dummy, until actually defined correctly From b3d98215af3d60baafc2e791b2a9b2eb06d81008 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Mon, 10 Jan 2022 23:45:40 -0500 Subject: [PATCH 03/10] Update station stock when exchanging equipment --- data/pigui/libs/ship-equipment.lua | 27 +++++++++++-------- .../pigui/modules/info-view/03-econ-trade.lua | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/data/pigui/libs/ship-equipment.lua b/data/pigui/libs/ship-equipment.lua index 2478c8c2f1b..4833c52a7bf 100644 --- a/data/pigui/libs/ship-equipment.lua +++ b/data/pigui/libs/ship-equipment.lua @@ -40,13 +40,13 @@ local emptySlot = { -- Equipment item grouping by underlying slot type -- TODO: significant refactor to slot system to reduce highly-specialized slots local sections = { - { name = "Propulsion", slot = "engine", showCapacity = true }, - { name = "Weapons", slot = "laser_front", showCapacity = true }, - { name = "Missiles", slot = "missile", showCapacity = true }, - { name = "Scoops", slot = "scoop", showCapacity = true }, - { name = "Sensors", slot = "sensor", showCapacity = true }, - { name = "Shields", slot = "shield" }, - { name = "Utility", slots = { + { name = le.PROPULSION, slot = "engine", showCapacity = true }, + { name = le.WEAPONS, slot = "laser_front", showCapacity = true }, + { name = le.MISSILES, slot = "missile", showCapacity = true }, + { name = le.SCOOPS, slot = "scoop", showCapacity = true }, + { name = le.SENSORS, slot = "sensor", showCapacity = true }, + { name = le.SHIELDS, slot = "shield" }, + { name = le.UTILITY, slots = { "cabin", "ecm", "radar", "target_scanner", "hypercloud", "hull_autorepair", "energy_booster", "atmo_shield", @@ -133,18 +133,23 @@ return EquipMarket.New("EquipmentMarket", l.AVAILABLE_FOR_PURCHASE, { end, -- If we have an equipment item selected, we're replacing it. onClickBuy = function(s,e) - if s.owner.selectedEquip[1] then + local selected = s.owner.selectedEquip + if selected[1] then + s:sell(selected[1], selected.slot) s.owner.ship:RemoveEquip(s.owner.selectedEquip[1], 1, s.owner.selectedEquip.slot) s.owner.ship:AddMoney(s.funcs.getSellPrice(s, s.owner.selectedEquip[1])) + s.owner.ship:GetDockedWith():AddEquipmentStock(e, 1) end return true end, -- If the purchase failed, undo the sale of the item previously in the slot onBuyFailed = function(s, e, reason) - if s.owner.selectedEquip[1] then - s.owner.ship:AddEquip(s.owner.selectedEquip[1], 1, s.owner.selectedEquip.slot) - s.owner.ship:AddMoney(-s.funcs.getSellPrice(s, s.owner.selectedEquip[1])) + local selected = s.owner.selectedEquip + if selected[1] then + s.owner.ship:AddEquip(selected[1], 1, selected.slot) + s.owner.ship:AddMoney(-s.funcs.getSellPrice(s, selected[1])) + s.owner.ship:GetDockedWith():AddEquipmentStock(e, -1) end s.defaultFuncs.onBuyFailed(s, e, reason) diff --git a/data/pigui/modules/info-view/03-econ-trade.lua b/data/pigui/modules/info-view/03-econ-trade.lua index 04b0e3e5dc6..cebb9e2e138 100644 --- a/data/pigui/modules/info-view/03-econ-trade.lua +++ b/data/pigui/modules/info-view/03-econ-trade.lua @@ -7,7 +7,7 @@ local Lang = require 'Lang' local Game = require "Game" local Equipment = require "Equipment" local ShipDef = require "ShipDef" -local StationView = require 'pigui/views/station-view' +local StationView = require 'pigui.views.station-view' local Format = require "Format" local l = Lang.GetResource("ui-core") From 3f7cbcc4ddd33543267bece007de09e7259fa0ea Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Mon, 10 Jan 2022 23:48:50 -0500 Subject: [PATCH 04/10] Add lang entries for equipment categories --- data/lang/equipment-core/en.json | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/data/lang/equipment-core/en.json b/data/lang/equipment-core/en.json index 9f6f22b1835..7a8f49f9f61 100644 --- a/data/lang/equipment-core/en.json +++ b/data/lang/equipment-core/en.json @@ -382,5 +382,33 @@ "TOTAL_MODULE_WEIGHT": { "description": "Tooltip explaining total equipped weight of specific slot", "message": "Total Weight" + }, + "PROPULSION": { + "description": "Category name of propulsion-related equipment", + "message": "Propulsion" + }, + "WEAPONS": { + "description": "Category name of weapon-related equipment", + "message": "Weapons" + }, + "MISSILES": { + "description": "Category name of missile-related equipment", + "message": "Missiles" + }, + "SCOOPS": { + "description": "Category name of scoop-related equipment", + "message": "Scoops" + }, + "SENSORS": { + "description": "Category name of sensor-related equipment", + "message": "Sensors" + }, + "SHIELDS": { + "description": "Category name of shield-related equipment", + "message": "Shields" + }, + "UTILITY": { + "description": "Category name of utility equipment", + "message": "Utility" } } From ef18f6e2f7fa4ae1b151841c0e9f08e79327fc28 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 11 Jan 2022 03:01:51 -0500 Subject: [PATCH 05/10] Unify button theming, use rescaleUI in theme - Add ui.button wrapper with themed padding and color variant support. - Setup default button colors to use Pioneer theme style. - Add ui.getButtonHeightWithSpacing(), ui.alignTextToButtonPadding(). - Expose current ItemSpacing value as ui.getItemSpacing(). - Engine.pigui now available when loading themes. Other Engine methods not guaranteed, --- data/pigui/baseui.lua | 3 +- data/pigui/libs/buttons.lua | 51 ++++++++++++++++++++++++++++ data/pigui/libs/forwarded.lua | 6 ++-- data/pigui/libs/rescale-ui.lua | 62 ++++++++++++++++++++++++++++++++++ data/pigui/libs/wrappers.lua | 59 -------------------------------- data/pigui/themes/default.lua | 10 ++++++ src/lua/Lua.cpp | 6 ++-- src/lua/LuaPiGui.cpp | 7 ++++ 8 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 data/pigui/libs/rescale-ui.lua diff --git a/data/pigui/baseui.lua b/data/pigui/baseui.lua index cadebcfe690..e62fd929a63 100644 --- a/data/pigui/baseui.lua +++ b/data/pigui/baseui.lua @@ -3,10 +3,11 @@ local Engine = require 'Engine' local pigui = Engine.pigui + local ui = require 'pigui.libs.forwarded' +ui.rescaleUI = require 'pigui.libs.rescale-ui' require 'pigui.libs.wrappers' - local defaultTheme = require 'pigui.themes.default' local pi = 3.14159264 diff --git a/data/pigui/libs/buttons.lua b/data/pigui/libs/buttons.lua index 0ce63662e5f..bb678a31f7a 100644 --- a/data/pigui/libs/buttons.lua +++ b/data/pigui/libs/buttons.lua @@ -4,6 +4,57 @@ local Engine = require 'Engine' local ui = require 'pigui.baseui' local pigui = Engine.pigui +-- +-- Function: ui.button +-- +-- > clicked = ui.button(label, button_size, variant, tooltip) +-- +-- Example: +-- +-- > clicked = ui.button("Click me", Vector2(100,0), "Does the thing") +-- +-- Parameters: +-- +-- label - string, text rendered on the button, must be unique. +-- Append any text following "##" to make a unique ID +-- button_size - [optional] Vector2, giving size of button +-- variant - [optional] Table, color variants used for this button; +-- contains Color fields 'normal', 'hovered', and 'active' +-- tooltip - [optional] string, mouseover text +-- +-- Returns: +-- +-- clicked - true if button was clicked +-- +function ui.button(label, button_size, variant, tooltip) + if variant then + pigui.PushStyleColor("Button", variant.normal) + pigui.PushStyleColor("ButtonHovered", variant.hovered) + pigui.PushStyleColor("ButtonActive", variant.active) + end + + pigui.PushStyleVar("FramePadding", ui.theme.styles.ButtonPadding) + local res = pigui.Button(label, button_size or Vector2(0, 0)) + pigui.PopStyleVar(1) + + if variant then + pigui.PopStyleColor(3) + end + + if pigui.IsItemHovered() and tooltip then pigui.SetTooltip(tooltip) end + return res +end + +function ui.alignTextToButtonPadding() + pigui.PushStyleVar("FramePadding", ui.theme.styles.ButtonPadding) + ui.alignTextToFramePadding() + pigui.PopStyleVar() +end + +function ui.getButtonHeightWithSpacing() + return ui.getTextLineHeightWithSpacing() + ui.theme.styles.ButtonPadding.y * 2.0 +end + -- -- Function: ui.imageButton -- diff --git a/data/pigui/libs/forwarded.lua b/data/pigui/libs/forwarded.lua index f4a8132b68a..3d64ade5349 100644 --- a/data/pigui/libs/forwarded.lua +++ b/data/pigui/libs/forwarded.lua @@ -48,8 +48,6 @@ ui.setCursorPos = pigui.SetCursorPos ui.getCursorPos = pigui.GetCursorPos ui.setCursorScreenPos = pigui.SetCursorScreenPos ui.getCursorScreenPos = pigui.GetCursorScreenPos -ui.getTextLineHeight = pigui.GetTextLineHeight -ui.getTextLineHeightWithSpacing = pigui.GetTextLineHeightWithSpacing ui.lowThrustButton = pigui.LowThrustButton ui.thrustIndicator = pigui.ThrustIndicator ui.isMouseClicked = pigui.IsMouseClicked @@ -67,6 +65,7 @@ ui.getTextLineHeight = pigui.GetTextLineHeight ui.getTextLineHeightWithSpacing = pigui.GetTextLineHeightWithSpacing ui.getFrameHeight = pigui.GetFrameHeight ui.getFrameHeightWithSpacing = pigui.GetFrameHeightWithSpacing +ui.getItemSpacing = pigui.GetItemSpacing ui.getTargetsNearby = pigui.GetTargetsNearby ui.getProjectedBodies = pigui.GetProjectedBodies ui.getProjectedBodiesGrouped = pigui.GetProjectedBodiesGrouped @@ -113,7 +112,8 @@ ui.InputTextFlags = pigui.InputTextFlags ui.WindowFlags = pigui.WindowFlags ui.HoveredFlags = pigui.HoveredFlags -ui.button = pigui.Button +-- Wrapped in buttons.lua +-- ui.button = pigui.Button ui.dataDirPath = pigui.DataDirPath ui.userDirPath = pigui.UserDirPath diff --git a/data/pigui/libs/rescale-ui.lua b/data/pigui/libs/rescale-ui.lua new file mode 100644 index 00000000000..6eecc216bf2 --- /dev/null +++ b/data/pigui/libs/rescale-ui.lua @@ -0,0 +1,62 @@ +-- Copyright © 2008-2022 Pioneer Developers. See AUTHORS.txt for details +-- Licensed under the terms of the GPL v3. See licenses/GPL-3.txt + +local pigui = require 'Engine'.pigui +local Vector2 = Vector2 + +local defaultBaseResolution = Vector2(1600, 900) + +-- +-- Function: ui.rescaleUI +-- +-- ui.rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) +-- +-- Scales a set of values (normally a size or a position) based on a base +-- resolution and the current or target resultion. +-- +-- +-- Example: +-- +-- > size = ui.rescaleUI(Vector2(96, 96), Vector2(1600, 900)) +-- +-- Parameters: +-- +-- val - number|Vector2|Table, the values to scale +-- baseResolution - (Optional) Vector2, the resolution at which val is valid +-- rescaleToScreenAspect - (Optional) number, when scaling a Vector2, scale x and y +-- appropriately to match the given aspect ratio +-- targetResolution - (Optional) Vector2, the target resolution to scale +-- the value to. Default: current screen resolution. +-- +-- Returns: +-- +-- number|Vector2|Table - the scaled value +-- +local function rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) + if not targetResolution then + targetResolution = Vector2(pigui.screen_width, pigui.screen_height) + end + + if not baseResolution then + baseResolution = defaultBaseResolution + end + + local rescaleVector = Vector2(targetResolution.x / baseResolution.x, targetResolution.y / baseResolution.y) + local rescaleFactor = math.min(rescaleVector.x, rescaleVector.y) + local type = type(val) + + if type == 'table' then + local result = {} + for k, v in pairs(val) do + result[k] = rescaleUI(v, baseResolution, rescaleToScreenAspect, targetResolution) + end + + return result + elseif type == 'userdata' and val.x and val.y then + return Vector2(val.x * ((rescaleToScreenAspect and rescaleVector.x) or rescaleFactor), val.y * ((rescaleToScreenAspect and rescaleVector.y) or rescaleFactor)) + elseif type == 'number' then + return val * rescaleFactor + end +end + +return rescaleUI diff --git a/data/pigui/libs/wrappers.lua b/data/pigui/libs/wrappers.lua index 86d18c15625..95241ece9de 100644 --- a/data/pigui/libs/wrappers.lua +++ b/data/pigui/libs/wrappers.lua @@ -8,65 +8,6 @@ local utils = require 'utils' local pigui = Engine.pigui local ui = require 'pigui.libs.forwarded' -local defaultBaseResolution = Vector2(1600, 900) - --- --- Function: ui.rescaleUI --- --- ui.rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) --- --- Scales a set of values (normally a size or a position) based on a base --- resolution and the current or target resultion. --- --- --- Example: --- --- > size = ui.rescaleUI(Vector2(96, 96), Vector2(1600, 900)) --- --- Parameters: --- --- val - number|Vector2|Table, the values to scale --- baseResolution - Vector2, the resolution at which val is valid --- rescaleToScreenAspect - (Optional) number, when scaling a Vector2, scale x and y --- appropriately to match the given aspect ratio --- targetResolution - (Optional) Vector2, the target resolution to scale --- the value to. Default: current screen resolution. --- --- Returns: --- --- number|Vector2|Table - the scaled value --- -function ui.rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) - if not baseResolution then - baseResolution = Vector2(1600, 900) - end - - if not targetResolution then - targetResolution = Vector2(pigui.screen_width, pigui.screen_height) - end - - if not baseResolution then - baseResolution = defaultBaseResolution - end - - local rescaleVector = Vector2(targetResolution.x / baseResolution.x, targetResolution.y / baseResolution.y) - local rescaleFactor = math.min(rescaleVector.x, rescaleVector.y) - local type = type(val) - - if type == 'table' then - local result = {} - for k, v in pairs(val) do - result[k] = ui.rescaleUI(v, baseResolution, rescaleToScreenAspect, targetResolution) - end - - return result - elseif type == 'userdata' and val.x and val.y then - return Vector2(val.x * ((rescaleToScreenAspect and rescaleVector.x) or rescaleFactor), val.y * ((rescaleToScreenAspect and rescaleVector.y) or rescaleFactor)) - elseif type == 'number' then - return val * rescaleFactor - end -end - -- -- Function: ui.pcall -- diff --git a/data/pigui/themes/default.lua b/data/pigui/themes/default.lua index 0c4a1121c3d..ebb210598b3 100644 --- a/data/pigui/themes/default.lua +++ b/data/pigui/themes/default.lua @@ -3,6 +3,8 @@ local theme = {} +local rescaleUI = require 'pigui.libs.rescale-ui' + -- theme.styleColors -- This table provides a coherent theme palette that can be referenced by -- component-specific semantic colors for consistent styling across the UI @@ -107,6 +109,11 @@ theme.colors = { buttonBlue = styleColors.primary_300, buttonInk = styleColors.white, + -- ImGui theme default colors + Button = styleColors.primary_600, + ButtonHovered = styleColors.primary_400, + ButtonActive = styleColors.primary_300, + unknown = styleColors.unknown, -- used as an invalid color transparent = styleColors.transparent, font = styleColors.white, @@ -174,6 +181,9 @@ theme.colors = { theme.styles = { WindowBorderSize = 0.0, TabRounding = 0.0, + TabPadding = rescaleUI(Vector2(8, 6)), + ButtonPadding = rescaleUI(Vector2(8, 6)), + ItemSpacing = rescaleUI(Vector2(8, 6)) } theme.icons = { diff --git a/src/lua/Lua.cpp b/src/lua/Lua.cpp index 88a846ec1e7..056b97ef75e 100644 --- a/src/lua/Lua.cpp +++ b/src/lua/Lua.cpp @@ -59,9 +59,13 @@ namespace Lua { // initialize standalone math types as the "extended standard library" for all lua instances void InitMath() { + LuaObject::RegisterClass(); + LuaVector::Register(manager->GetLuaState()); LuaVector2::Register(manager->GetLuaState()); LuaColor::Register(manager->GetLuaState()); + + LuaEngine::Register(); } void InitModules() @@ -87,7 +91,6 @@ namespace Lua { LuaObject::RegisterClass(); LuaObject::RegisterClass(); LuaObject::RegisterClass(); - LuaObject::RegisterClass(); LuaObject::RegisterClass(); Pi::luaSerializer = new LuaSerializer(); @@ -98,7 +101,6 @@ namespace Lua { LuaConstants::Register(Lua::manager->GetLuaState()); LuaLang::Register(); - LuaEngine::Register(); LuaEconomy::Register(); LuaInput::Register(); LuaFileSystem::Register(); diff --git a/src/lua/LuaPiGui.cpp b/src/lua/LuaPiGui.cpp index 8708a806f8f..dc43f178442 100644 --- a/src/lua/LuaPiGui.cpp +++ b/src/lua/LuaPiGui.cpp @@ -819,6 +819,12 @@ static int l_pigui_get_frame_height_with_spacing(lua_State *l) return 1; } +static int l_pigui_get_item_spacing(lua_State *l) +{ + LuaPush(l, ImGui::GetStyle().ItemSpacing); + return 1; +} + static int l_pigui_add_line(lua_State *l) { PROFILE_SCOPED() @@ -2919,6 +2925,7 @@ void LuaObject::RegisterClass() { "GetTextLineHeightWithSpacing", l_pigui_get_text_line_height_with_spacing }, { "GetFrameHeight", l_pigui_get_frame_height }, { "GetFrameHeightWithSpacing", l_pigui_get_frame_height_with_spacing }, + { "GetItemSpacing", l_pigui_get_item_spacing }, { "InputText", l_pigui_input_text }, { "Combo", l_pigui_combo }, { "ListBox", l_pigui_listbox }, From 82b683f0a9054d8d39f10ca488ba64ae23e7cead Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 11 Jan 2022 03:02:14 -0500 Subject: [PATCH 06/10] Add ui.tabBarFont for concise themed tab bars --- data/pigui/libs/wrappers.lua | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/data/pigui/libs/wrappers.lua b/data/pigui/libs/wrappers.lua index 95241ece9de..a4ec4db8a68 100644 --- a/data/pigui/libs/wrappers.lua +++ b/data/pigui/libs/wrappers.lua @@ -458,6 +458,61 @@ function ui.tabBar(id, items) return true end + +-- +-- Function: ui.tabBarFont +-- +-- ui.tabBarFont(id, tabs, font, [args...]) +-- +-- +-- Example: +-- +-- > +-- +-- Parameters: +-- id - String, unique id to identify the group of tabs by +-- items - Table, a list of contents. Each item should contain a 'name' +-- field and a 'draw' field with a function that displays that +-- tab's contents. +-- font - Font Table, the header font for the tab +-- args - [optional] varargs to pass to the draw function of each tab +-- +-- Returns: +-- +-- index - index of the open tab if the tab bar is open, 0 otherwise +-- +function ui.tabBarFont(id, items, font, ...) + local active_index = 0 + + pigui.PushStyleVar("FramePadding", ui.theme.styles.TabPadding) + local _fnt = pigui:PushFont(font.name, font.size) + local open = pigui.BeginTabBar(id) + if _fnt then pigui.PopFont() end + pigui.PopStyleVar(1) + + if not open then return active_index end + + for i, item in ipairs(items) do + pigui.PushStyleVar("FramePadding", ui.theme.styles.TabPadding) + local _fnt = pigui:PushFont(font.name, font.size) + local tab_open = pigui.BeginTabItem(item.name or item[1]) + if _fnt then pigui.PopFont() end + pigui.PopStyleVar(1) + + if tab_open then + ui.spacing() + + active_index = (item.draw or item[2])(...) + + pigui.EndTabItem() + end + + pigui.EndTabItem() + end + + return active_index +end + -- -- Function: ui.withFont -- From f528aa2d5763aeb258c45ab38f0f1e6e5f7abb59 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 11 Jan 2022 03:03:30 -0500 Subject: [PATCH 07/10] Finish translating ship equipment view, tweaks - Refactor category displays (radar, scanners in sensors category) - Add context information when replacing selected equipment - More documentation --- data/lang/ui-core/en.json | 12 +++++-- data/pigui/libs/ship-equipment.lua | 53 ++++++++++++++---------------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/data/lang/ui-core/en.json b/data/lang/ui-core/en.json index 88963cea028..78e7d8459f4 100644 --- a/data/lang/ui-core/en.json +++ b/data/lang/ui-core/en.json @@ -56,8 +56,8 @@ "message": "Auto Route" }, "AVAILABLE_FOR_PURCHASE": { - "description": "", - "message": "Available for purchase" + "description": "Market header when buying items", + "message": "Available For Purchase" }, "AVERAGE": { "description": "", @@ -2154,5 +2154,13 @@ "UNOCCUPIED_PASSENGER_CABINS": { "description": "", "message": "Unoccupied Passenger Cabins" + }, + "REPLACE_EQUIPMENT_WITH": { + "description": "Market header when replacing equipped items", + "message": "Replace Equipment With" + }, + "SELL_EQUIPPED": { + "description": "Button text to sell selected ship equipment", + "message": "Sell Equipped" } } diff --git a/data/pigui/libs/ship-equipment.lua b/data/pigui/libs/ship-equipment.lua index 4833c52a7bf..795370322ba 100644 --- a/data/pigui/libs/ship-equipment.lua +++ b/data/pigui/libs/ship-equipment.lua @@ -44,11 +44,12 @@ local sections = { { name = le.WEAPONS, slot = "laser_front", showCapacity = true }, { name = le.MISSILES, slot = "missile", showCapacity = true }, { name = le.SCOOPS, slot = "scoop", showCapacity = true }, - { name = le.SENSORS, slot = "sensor", showCapacity = true }, + { name = le.SENSORS, showCapacity = true, slots = { + "sensor", "radar", "target_scanner", "hypercloud" + } }, { name = le.SHIELDS, slot = "shield" }, { name = le.UTILITY, slots = { - "cabin", "ecm", "radar", "target_scanner", - "hypercloud", "hull_autorepair", + "cabin", "ecm", "hull_autorepair", "energy_booster", "atmo_shield", "laser_cooler", "cargo_life_support", "autopilot", "trade_computer", "thruster" @@ -184,6 +185,17 @@ function EquipmentWidget.New(id) return self end +--[[ +self.selectedEquip format: +{ + [1] = equipment table or nil + [2] = equipment index in slot or nil + slot = name of slot currently selected + mass = mass of current equipment + name = name of current equipment +} +--]] + function EquipmentWidget:onEquipmentClicked(equipDetail, slots) if self.station then self.selectedEquip = equipDetail @@ -521,9 +533,7 @@ function EquipmentWidget:drawShipSpinner() end) end -function EquipmentWidget:drawMarketButtons(buttonLinePos) - ui.setCursorPos(buttonLinePos) - +function EquipmentWidget:drawMarketButtons() if ui.button(l.GO_BACK, Vector2(0, 0)) then self.selectedEquip = nil return @@ -533,18 +543,14 @@ function EquipmentWidget:drawMarketButtons(buttonLinePos) if self.selectedEquip[1] then local price = self.equipmentMarket.funcs.getSellPrice(self.equipmentMarket, self.selectedEquip[1]) - if ui.button(l.SELL, Vector2(0, 0)) then + if ui.button(l.SELL_EQUIPPED, Vector2(0, 0)) then Game.player:RemoveEquip(self.selectedEquip[1], 1, self.selectedEquip.slot) Game.player:AddMoney(price) self.selectedEquip = { nil, nil } return end ui.sameLine() - - local _pos = ui.getCursorPos() - ui.setCursorPos(buttonLinePos - Vector2(0, ui.getTextLineHeightWithSpacing())) - ui.text("Sell Price: " .. Format.Money(price)) - ui.setCursorPos(_pos) + ui.text(l.PRICE .. ": " .. Format.Money(price)) end end @@ -552,17 +558,7 @@ function EquipmentWidget:draw() ui.withFont(pionillium.body, function() ui.child("ShipInfo", Vector2(ui.getContentRegion().x * 1 / 3, 0), { "NoSavedSettings" }, function() if #self.tabs > 1 then - if ui.beginTabBar("##tabs") then - for i = 1, #self.tabs do - if ui.beginTabItem(self.tabs[i].name) then - ui.spacing() - self.activeTab = i - self.tabs[i].draw(self) - ui.endTabItem() - end - end - ui.endTabBar() - end + self.activeTab = ui.tabBarFont("##tabs", self.tabs, pionillium.heading, self) else self.tabs[1].draw(self) end @@ -573,16 +569,17 @@ function EquipmentWidget:draw() ui.child("##container", function() if self.tabs[self.activeTab] == equipmentInfoTab and self.station and self.selectedEquip then local bottomControlsHeight = 0 - local _pos = ui.getCursorPos() + local _pos = ui.getCursorPos() ui.withFont(pionillium.heading, function() - bottomControlsHeight = ui.getFrameHeightWithSpacing() + ui.getTextLineHeightWithSpacing() + lineSpacing.y - local buttonLinePos = ui.getCursorPos() + Vector2(0, ui.getContentRegion().y - ui.getFrameHeightWithSpacing()) - self:drawMarketButtons(buttonLinePos) + bottomControlsHeight = ui.getButtonHeightWithSpacing() + ui.setCursorPos(ui.getCursorPos() + Vector2(0, ui.getContentRegion().y - bottomControlsHeight)) + self:drawMarketButtons() ui.sameLine() end) - ui.setCursorPos(_pos) + + self.equipmentMarket.title = self.selectedEquip[1] and l.REPLACE_EQUIPMENT_WITH or l.AVAILABLE_FOR_PURCHASE self.equipmentMarket.style.size = ui.getContentRegion() - Vector2(0, bottomControlsHeight) self.equipmentMarket:render() else From cff1e1d004e8a31fd17a26e83b1eedf28c501302 Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 11 Jan 2022 03:22:16 -0500 Subject: [PATCH 08/10] UI rescaling snap to integer values Non-integer values (more specifically sub-pixel offsets) produce blurry results with UI icon drawing and calculations. ui.rescaleUI defaults to snapping result values to the next whole number. --- data/pigui/libs/rescale-ui.lua | 15 ++++++++++----- data/pigui/libs/text.lua | 3 ++- data/pigui/modules/time-window.lua | 2 +- data/pigui/themes/default.lua | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/data/pigui/libs/rescale-ui.lua b/data/pigui/libs/rescale-ui.lua index 6eecc216bf2..d990f997522 100644 --- a/data/pigui/libs/rescale-ui.lua +++ b/data/pigui/libs/rescale-ui.lua @@ -13,7 +13,7 @@ local defaultBaseResolution = Vector2(1600, 900) -- -- Scales a set of values (normally a size or a position) based on a base -- resolution and the current or target resultion. --- +-- Scaled values are rounded up to whole numbers -- -- Example: -- @@ -23,8 +23,9 @@ local defaultBaseResolution = Vector2(1600, 900) -- -- val - number|Vector2|Table, the values to scale -- baseResolution - (Optional) Vector2, the resolution at which val is valid --- rescaleToScreenAspect - (Optional) number, when scaling a Vector2, scale x and y +-- rescaleToScreenAspect - (Optional) boolean, when scaling a Vector2, scale x and y -- appropriately to match the given aspect ratio +-- disableCeil - (Optional) boolean, controls returning fractional or whole numbers -- targetResolution - (Optional) Vector2, the target resolution to scale -- the value to. Default: current screen resolution. -- @@ -32,7 +33,7 @@ local defaultBaseResolution = Vector2(1600, 900) -- -- number|Vector2|Table - the scaled value -- -local function rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResolution) +local function rescaleUI(val, baseResolution, rescaleToScreenAspect, disableCeil, targetResolution) if not targetResolution then targetResolution = Vector2(pigui.screen_width, pigui.screen_height) end @@ -41,6 +42,8 @@ local function rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResol baseResolution = defaultBaseResolution end + local ceil = disableCeil and function(x) return x end or math.ceil + local rescaleVector = Vector2(targetResolution.x / baseResolution.x, targetResolution.y / baseResolution.y) local rescaleFactor = math.min(rescaleVector.x, rescaleVector.y) local type = type(val) @@ -53,9 +56,11 @@ local function rescaleUI(val, baseResolution, rescaleToScreenAspect, targetResol return result elseif type == 'userdata' and val.x and val.y then - return Vector2(val.x * ((rescaleToScreenAspect and rescaleVector.x) or rescaleFactor), val.y * ((rescaleToScreenAspect and rescaleVector.y) or rescaleFactor)) + return Vector2( + ceil(val.x * ((rescaleToScreenAspect and rescaleVector.x) or rescaleFactor)), + ceil(val.y * ((rescaleToScreenAspect and rescaleVector.y) or rescaleFactor))) elseif type == 'number' then - return val * rescaleFactor + return ceil(val * rescaleFactor) end end diff --git a/data/pigui/libs/text.lua b/data/pigui/libs/text.lua index c658664ebda..1b052b916b3 100644 --- a/data/pigui/libs/text.lua +++ b/data/pigui/libs/text.lua @@ -9,7 +9,8 @@ local pigui = Engine.pigui local lc = Lang.GetResource("core"); -local font_factor = ui.rescaleUI(1, Vector2(1920, 1200)) +-- get a fractional font factor +local font_factor = ui.rescaleUI(1, Vector2(1920, 1200), false, true) local textBackgroundMarginPixels = 2 diff --git a/data/pigui/modules/time-window.lua b/data/pigui/modules/time-window.lua index 9faef6f5cd9..8e9a63152fb 100644 --- a/data/pigui/modules/time-window.lua +++ b/data/pigui/modules/time-window.lua @@ -55,7 +55,7 @@ local function displayTimeWindow() ui.withFont(pionillium.large.name, pionillium.large.size, function() local text_size = ui.calcTextSize(date) - local window_size = Vector2(math.max(text_size.x, (button_size.x + frame_padding * 2 + 7) * 6) + 15, text_size.y + button_size.y + frame_padding * 2 + 20) + local window_size = Vector2(math.max(text_size.x, (button_size.x + frame_padding * 2 + 7) * 6) + 15, text_size.y + button_size.y + frame_padding * 2 + 22) ui.timeWindowSize = window_size ui.setNextWindowSize(window_size, "Always") ui.setNextWindowPos(Vector2(0, ui.screenHeight - window_size.y), "Always") diff --git a/data/pigui/themes/default.lua b/data/pigui/themes/default.lua index ebb210598b3..531725d7653 100644 --- a/data/pigui/themes/default.lua +++ b/data/pigui/themes/default.lua @@ -183,7 +183,7 @@ theme.styles = { TabRounding = 0.0, TabPadding = rescaleUI(Vector2(8, 6)), ButtonPadding = rescaleUI(Vector2(8, 6)), - ItemSpacing = rescaleUI(Vector2(8, 6)) + ItemSpacing = rescaleUI(Vector2(8, 6)), } theme.icons = { From 1a4f903357aa984ecf434c13fdb9fedb3759dead Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Tue, 11 Jan 2022 17:17:18 -0500 Subject: [PATCH 09/10] Bugfixes, handle equipment stock updates --- data/pigui/libs/ship-equipment.lua | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/data/pigui/libs/ship-equipment.lua b/data/pigui/libs/ship-equipment.lua index 795370322ba..b3d3123511f 100644 --- a/data/pigui/libs/ship-equipment.lua +++ b/data/pigui/libs/ship-equipment.lua @@ -136,10 +136,9 @@ return EquipMarket.New("EquipmentMarket", l.AVAILABLE_FOR_PURCHASE, { onClickBuy = function(s,e) local selected = s.owner.selectedEquip if selected[1] then - s:sell(selected[1], selected.slot) - s.owner.ship:RemoveEquip(s.owner.selectedEquip[1], 1, s.owner.selectedEquip.slot) - s.owner.ship:AddMoney(s.funcs.getSellPrice(s, s.owner.selectedEquip[1])) - s.owner.ship:GetDockedWith():AddEquipmentStock(e, 1) + s.owner.ship:RemoveEquip(selected[1], 1, selected.slot) + s.owner.ship:AddMoney(s.funcs.getSellPrice(s, selected[1])) + s.owner.ship:GetDockedWith():AddEquipmentStock(selected[1], 1) end return true @@ -544,8 +543,9 @@ function EquipmentWidget:drawMarketButtons() local price = self.equipmentMarket.funcs.getSellPrice(self.equipmentMarket, self.selectedEquip[1]) if ui.button(l.SELL_EQUIPPED, Vector2(0, 0)) then - Game.player:RemoveEquip(self.selectedEquip[1], 1, self.selectedEquip.slot) - Game.player:AddMoney(price) + self.ship:RemoveEquip(self.selectedEquip[1], 1, self.selectedEquip.slot) + self.ship:AddMoney(price) + self.ship:GetDockedWith():AddEquipmentStock(self.selectedEquip[1], 1) self.selectedEquip = { nil, nil } return end @@ -579,6 +579,7 @@ function EquipmentWidget:draw() end) ui.setCursorPos(_pos) + if not self.selectedEquip then return end self.equipmentMarket.title = self.selectedEquip[1] and l.REPLACE_EQUIPMENT_WITH or l.AVAILABLE_FOR_PURCHASE self.equipmentMarket.style.size = ui.getContentRegion() - Vector2(0, bottomControlsHeight) self.equipmentMarket:render() From 845a9fc117ffbdbf53c6942a6003cbf05cb0ae1f Mon Sep 17 00:00:00 2001 From: Webster Sheets Date: Fri, 14 Jan 2022 00:43:27 -0500 Subject: [PATCH 10/10] Remove deprecated GL_POINT_SPRITE in GL3.2+ --- src/graphics/opengl/RendererGL.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/graphics/opengl/RendererGL.cpp b/src/graphics/opengl/RendererGL.cpp index d6ea9ab7250..122f243409d 100644 --- a/src/graphics/opengl/RendererGL.cpp +++ b/src/graphics/opengl/RendererGL.cpp @@ -239,11 +239,12 @@ namespace Graphics { glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glEnable(GL_PROGRAM_POINT_SIZE); - if (!vs.gl3ForwardCompatible) glEnable(GL_POINT_SPRITE); // GL_POINT_SPRITE hack for compatibility contexts glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST); glHint(GL_FRAGMENT_SHADER_DERIVATIVE_HINT, GL_NICEST); + CHECKERRORS(); + // create the state cache immediately after establishing baseline state. m_renderStateCache.reset(new OGL::RenderStateCache()); @@ -573,7 +574,6 @@ namespace Graphics { void RendererOGL::CheckErrors(const char *func, const int line) { -#ifndef PIONEER_PROFILER GLenum err = glGetError(); if (err) { // static-cache current err that sparked this @@ -607,7 +607,6 @@ namespace Graphics { else Log::Info("{}", ss.str()); } -#endif } bool RendererOGL::SwapBuffers()