Feature Complete Shipping V1.0

This commit is contained in:
2026-08-12 22:57:52 -04:00
parent 19e4ac0cce
commit 56b6a46811
30 changed files with 9934 additions and 9361 deletions
@@ -4,6 +4,16 @@ PaintMyKI5.PaintInventory = PaintMyKI5.PaintInventory or {}
local PaintInventory = PaintMyKI5.PaintInventory
local EPSILON = 0.0001
local EMPTY_BUCKET = "Base.PaintbucketEmpty"
local TOOL_REQUIREMENTS = {
{
item = "PaintMyKI5.Sandpaper",
alternatives = { "PaintMyKI5.Sandpaper" },
},
{
item = "Base.Paintbrush",
alternatives = { "Base.Paintbrush", "Base.PaintbrushCrafted" },
},
}
local function getItems(character, itemType)
if not character or not character:getInventory() then return nil end
@@ -41,6 +51,27 @@ function PaintInventory.checkRequirements(character, requirements)
return #missing == 0, missing
end
local function hasAnyItem(character, itemTypes)
for _, itemType in ipairs(itemTypes) do
local items = getItems(character, itemType)
if items and items:size() > 0 then return true end
end
return false
end
function PaintInventory.checkPaintingRequirements(character, requirements)
local hasPaint, missingPaint = PaintInventory.checkRequirements(
character, requirements
)
local missingTools = {}
for _, tool in ipairs(TOOL_REQUIREMENTS) do
if not hasAnyItem(character, tool.alternatives) then
table.insert(missingTools, { item = tool.item })
end
end
return hasPaint and #missingTools == 0, missingPaint, missingTools
end
local function buildPlan(character, requirements)
local enough = PaintInventory.checkRequirements(character, requirements)
if not enough then return nil end
File diff suppressed because it is too large Load Diff
@@ -79,7 +79,7 @@ function PaintRequirements.findInteractionArea(vehicle, character)
return nil
end
function PaintRequirements.isValidTarget(character, vehicle, skinIndex, area)
function PaintRequirements.isValidSelection(character, vehicle, skinIndex)
if not character or not vehicle or vehicle:isRemovedFromWorld() then return false end
if character:getVehicle() then return false end
if math.abs(vehicle:getCurrentSpeedKmHour()) > 0.8 then return false end
@@ -87,6 +87,13 @@ function PaintRequirements.isValidTarget(character, vehicle, skinIndex, area)
if skinIndex < 0 or skinIndex >= vehicle:getSkinCount() then return false end
if vehicle:getSkinIndex() == skinIndex then return false end
if not PaintRequirements.getTextureData(vehicle, skinIndex) then return false end
return true
end
function PaintRequirements.isValidTarget(character, vehicle, skinIndex, area)
if not PaintRequirements.isValidSelection(character, vehicle, skinIndex) then
return false
end
if not area or not vehicle:isInArea(area, character) then return false end
return true
end
@@ -0,0 +1,65 @@
PaintMyKI5 = PaintMyKI5 or {}
PaintMyKI5.TextureName = PaintMyKI5.TextureName or {}
local TextureName = PaintMyKI5.TextureName
local function filename(textureData)
local reference = textureData and textureData.texture or ""
if type(reference) ~= "string" then return "" end
local name = string.match(reference, "([^/\\]+)$") or reference
if string.lower(string.sub(name, -4)) == ".png" then
name = string.sub(name, 1, -5)
end
return name
end
local function commonPrefix(names)
local prefix = names[1] or ""
for index = 2, #names do
local other = names[index]
local length = math.min(#prefix, #other)
local matching = 0
for character = 1, length do
if string.lower(string.sub(prefix, character, character))
~= string.lower(string.sub(other, character, character)) then
break
end
matching = character
end
prefix = string.sub(prefix, 1, matching)
if prefix == "" then break end
end
return prefix
end
local function shortenedLabels(names)
if #names < 2 then return nil end
local prefix = commonPrefix(names)
local separator = string.match(prefix, "^.*()[_%- ]")
if not separator then return nil end
prefix = string.sub(prefix, 1, separator)
local labels = {}
local distinct = {}
local distinctCount = 0
for index, name in ipairs(names) do
local label = string.sub(name, #prefix + 1)
if label == "" or #label > 32 then return nil end
label = string.gsub(label, "[_%-]+", " ")
if not distinct[string.lower(label)] then
distinct[string.lower(label)] = true
distinctCount = distinctCount + 1
end
labels[index] = label
end
return distinctCount > 1 and labels or nil
end
function TextureName.buildLabels(textures)
local names = {}
for index, textureData in ipairs(textures or {}) do
names[index] = filename(textureData)
end
return shortenedLabels(names) or names
end
@@ -17,7 +17,10 @@ function ISPaintMyKI5Vehicle:isValid()
self.vehicle, self.skinIndex
)
if not requirements then return false end
return PaintMyKI5.PaintInventory.checkRequirements(self.character, requirements)
local ready = PaintMyKI5.PaintInventory.checkPaintingRequirements(
self.character, requirements
)
return ready
end
function ISPaintMyKI5Vehicle:waitToStart()
@@ -78,7 +81,7 @@ function ISPaintMyKI5Vehicle:complete()
self.vehicle, self.skinIndex
)
if not requirements then return false end
local enough = PaintMyKI5.PaintInventory.checkRequirements(
local enough = PaintMyKI5.PaintInventory.checkPaintingRequirements(
self.character, requirements
)
if not enough then return false end
@@ -5,5 +5,9 @@
"IGUI_PaintMyKI5_Requirements": "Paint requirements",
"IGUI_PaintMyKI5_RequirementLine": "%1: %2%%, %3 uses needed, %4 available",
"IGUI_PaintMyKI5_OneBucket": "Total: %1 uses — one full bucket",
"IGUI_PaintMyKI5_PreviewMissing": "Texture preview unavailable"
"IGUI_PaintMyKI5_PreviewMissing": "Texture preview unavailable",
"IGUI_PaintMyKI5_MissingRequirements": "Missing requirements:",
"IGUI_PaintMyKI5_MissingTool": "Missing %1",
"IGUI_PaintMyKI5_MissingPaint": "Missing %1 (%2 uses needed, %3 available)",
"IGUI_PaintMyKI5_Unavailable": "The vehicle must be parked and a different skin selected."
}
@@ -0,0 +1,3 @@
{
"PaintMyKI5.Sandpaper": "Sandpaper"
}