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
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

@@ -4,6 +4,7 @@ require "ISUI/ISButton"
require "Vehicles/TimedActions/ISPathFindAction"
require "PaintMyKI5/PaintRequirements"
require "PaintMyKI5/PaintInventory"
require "PaintMyKI5/TextureName"
require "PaintMyKI5/TimedActions/ISPaintMyKI5Vehicle"
ISPaintMyKI5UI = ISCollapsableWindow:derive("ISPaintMyKI5UI")
@@ -14,9 +15,9 @@ local FONT_MEDIUM = UIFont.Medium
local SMALL_HEIGHT = getTextManager():getFontHeight(FONT_SMALL)
local MEDIUM_HEIGHT = getTextManager():getFontHeight(FONT_MEDIUM)
local function textureLabel(textureData)
local name = string.match(textureData.texture or "", "([^/]+)$") or ""
return getText("IGUI_PaintMyKI5_Skin", textureData.skinIndex + 1) .. " - " .. name
local function textureLabel(textureData, displayName)
return getText("IGUI_PaintMyKI5_Skin", textureData.skinIndex + 1)
.. " - " .. displayName
end
local function getPaletteColor(itemType)
@@ -28,6 +29,24 @@ local function getPaletteColor(itemType)
return 0.5, 0.5, 0.5
end
local function buildMissingTooltip(missingPaint, missingTools)
local lines = { getText("IGUI_PaintMyKI5_MissingRequirements") }
for _, missing in ipairs(missingTools or {}) do
table.insert(lines, getText(
"IGUI_PaintMyKI5_MissingTool",
getItemNameFromFullType(missing.item)
))
end
for _, missing in ipairs(missingPaint or {}) do
local available = math.floor(missing.available * 100 + 0.5) / 100
table.insert(lines, getText(
"IGUI_PaintMyKI5_MissingPaint",
getItemNameFromFullType(missing.item), missing.required, available
))
end
return table.concat(lines, "\n")
end
function ISPaintMyKI5UI.drawSkinItem(list, y, item, alt)
if item.itemindex == list.selected then
list:drawRect(0, y, list:getWidth(), item.height, 0.25, 0.3, 0.7, 1.0)
@@ -49,8 +68,10 @@ function ISPaintMyKI5UI:createChildren()
self.skinList.drawBorder = true
self:addChild(self.skinList)
for _, textureData in ipairs(self.vehicleData.textures or {}) do
self.skinList:addItem(textureLabel(textureData), textureData)
local textures = self.vehicleData.textures or {}
local textureNames = PaintMyKI5.TextureName.buildLabels(textures)
for index, textureData in ipairs(textures) do
self.skinList:addItem(textureLabel(textureData, textureNames[index]), textureData)
end
local currentIndex = self.vehicle:getSkinIndex()
for index, row in ipairs(self.skinList.items) do
@@ -84,6 +105,8 @@ function ISPaintMyKI5UI:prerender()
ISCollapsableWindow.prerender(self)
local textureData = self:getSelectedTexture()
local enabled = false
local missingPaint = {}
local missingTools = {}
if textureData then
local area = PaintMyKI5.PaintRequirements.findInteractionArea(
self.vehicle, self.character
@@ -91,13 +114,26 @@ function ISPaintMyKI5UI:prerender()
local requirements = PaintMyKI5.PaintRequirements.getRequirements(
self.vehicle, textureData.skinIndex
)
enabled = requirements ~= nil
and PaintMyKI5.PaintRequirements.isValidTarget(
self.character, self.vehicle, textureData.skinIndex, area
local ready = false
if requirements then
ready, missingPaint, missingTools =
PaintMyKI5.PaintInventory.checkPaintingRequirements(
self.character, requirements
)
end
enabled = ready and area ~= nil
and PaintMyKI5.PaintRequirements.isValidSelection(
self.character, self.vehicle, textureData.skinIndex
)
and PaintMyKI5.PaintInventory.checkRequirements(self.character, requirements)
end
self.paintButton:setEnable(enabled)
if enabled then
self.paintButton:setTooltip(nil)
elseif #missingPaint > 0 or #missingTools > 0 then
self.paintButton:setTooltip(buildMissingTooltip(missingPaint, missingTools))
else
self.paintButton:setTooltip(getText("IGUI_PaintMyKI5_Unavailable"))
end
end
function ISPaintMyKI5UI:render()
@@ -162,12 +198,14 @@ function ISPaintMyKI5UI:onPaint()
self.vehicle, textureData.skinIndex
)
if not requirements then return end
local enough = PaintMyKI5.PaintInventory.checkRequirements(self.character, requirements)
local enough = PaintMyKI5.PaintInventory.checkPaintingRequirements(
self.character, requirements
)
if not enough then return end
local area = PaintMyKI5.PaintRequirements.findInteractionArea(self.vehicle, self.character)
if not area then return end
if not PaintMyKI5.PaintRequirements.isValidTarget(
self.character, self.vehicle, textureData.skinIndex, area
if not PaintMyKI5.PaintRequirements.isValidSelection(
self.character, self.vehicle, textureData.skinIndex
) then return end
ISTimedActionQueue.add(ISPathFindAction:pathToVehicleArea(self.character, self.vehicle, area))
@@ -38,7 +38,7 @@ function PaintVehicleContextMenu.onFillWorldObjectContextMenu(player, context, w
PaintVehicleContextMenu.open,
vehicle
)
option.iconTexture = getTexture("media/textures/PaintBrush.png")
option.iconTexture = getTexture("media/textures/PaintMyKI5_ContextMenu.png")
return true
end
@@ -0,0 +1,75 @@
PaintMyKI5 = PaintMyKI5 or {}
PaintMyKI5.SandpaperDistribution = PaintMyKI5.SandpaperDistribution or {}
local SandpaperDistribution = PaintMyKI5.SandpaperDistribution
local SANDPAPER_ITEM = "PaintMyKI5.Sandpaper"
local SANDPAPER_WEIGHT = 0.1
local FULL_PAINT_CANS = {
PaintBlack = true,
PaintBlue = true,
PaintBrown = true,
PaintCyan = true,
PaintGreen = true,
PaintGrey = true,
PaintLightBlue = true,
PaintLightBrown = true,
PaintOrange = true,
PaintPink = true,
PaintPurple = true,
PaintRed = true,
PaintTurquoise = true,
PaintWhite = true,
PaintYellow = true,
}
local function isFullPaintCan(itemType)
if type(itemType) ~= "string" then return false end
if FULL_PAINT_CANS[itemType] then return true end
local moduleName, shortType = string.match(itemType, "^([^.]+)%.([^.]+)$")
return moduleName == "Base" and FULL_PAINT_CANS[shortType] == true
end
local function inspectItems(items)
local hasPaint = false
local hasSandpaper = false
if type(items) ~= "table" then return hasPaint, hasSandpaper end
for index = 1, #items, 2 do
local itemType = items[index]
if itemType == SANDPAPER_ITEM then
hasSandpaper = true
elseif isFullPaintCan(itemType) then
hasPaint = true
end
end
return hasPaint, hasSandpaper
end
local function injectIntoItems(items)
local hasPaint, hasSandpaper = inspectItems(items)
if not hasPaint or hasSandpaper then return 0 end
table.insert(items, SANDPAPER_ITEM)
table.insert(items, SANDPAPER_WEIGHT)
return 1
end
function SandpaperDistribution.inject(distributions, clutterTables)
local list = distributions and distributions.list
local added = 0
if type(list) == "table" then
for _, distribution in pairs(list) do
if type(distribution) == "table" then
added = added + injectIntoItems(distribution.items)
if type(distribution.junk) == "table" then
added = added + injectIntoItems(distribution.junk.items)
end
end
end
end
if type(clutterTables) == "table" then
added = added + injectIntoItems(clutterTables.ClosetItems)
end
return added
end
SandpaperDistribution.inject(ProceduralDistributions, ClutterTables)
@@ -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"
}
+10
View File
@@ -0,0 +1,10 @@
module PaintMyKI5
{
item Sandpaper
{
DisplayCategory = Tool,
ItemType = base:normal,
Weight = 0.1,
Icon = Sandpaper,
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

+2 -2
View File
@@ -1,11 +1,11 @@
name=Paint my KI5
id=hrsys_paint_my_ki5
poster=../common/media/textures/preview.png
poster=preview.png
description=A mod allowing for painting of KI5 vehicles.
author=Riggs0
category=vehicle
require=damnlib
icon=../common/media/textures/paint_my_ki5_icon.png
icon=icon.png
url=https://hudsonriggs.systems
modversion=1.1.0
versionMin=42.20
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 265 KiB