Normalize line endings and enforce LF via .gitattributes

This commit is contained in:
2026-02-12 18:00:24 -05:00
parent 14f7b7bd4a
commit 633ebb4ac4
6 changed files with 493 additions and 127 deletions

View File

@@ -3,4 +3,5 @@ if not TowBarMod.Config then TowBarMod.Config = {} end
TowBarMod.Config.lowLevelAnimation = "RemoveGrass"
TowBarMod.Config.rigidTowbarDistance = 1.0
TowBarMod.Config.devMode = true
TowBarMod.Config.largeTowbarModelScaleThreshold = 1.2

View File

@@ -33,13 +33,66 @@ local function getTowBarItem(playerObj)
return inventory:getItemFromTypeRecurse("TowBar.TowBar")
end
local TowbarVariantSize = 24
local TowbarNormalStart = 0
local TowbarLargeStart = 24
local TowbarMaxIndex = TowbarVariantSize - 1
local function getVehicleModelScale(script)
if not script then return nil end
local ok, result = pcall(function()
return script:getModelScale()
end)
if ok and type(result) == "number" then
return result
end
ok, result = pcall(function()
local model = script:getModel()
if model then
return model:getScale()
end
return nil
end)
if ok and type(result) == "number" then
return result
end
return nil
end
local function shouldUseLargeTowbarModel(script)
local modelScale = getVehicleModelScale(script)
if modelScale == nil then
return false
end
local configuredThreshold = TowBarMod.Config and tonumber(TowBarMod.Config.largeTowbarModelScaleThreshold)
local threshold = configuredThreshold or 1.2
return modelScale < threshold
end
local function getTowbarModelSlot(script)
local chassisZ = script:getPhysicsChassisShape():z()
local index = 0
if chassisZ > 3.0 then
local halfZ = chassisZ / 2
index = math.floor((halfZ - 1.0) * 16 - 1)
end
index = math.max(0, math.min(TowbarMaxIndex, index))
local slotStart = shouldUseLargeTowbarModel(script) and TowbarLargeStart or TowbarNormalStart
return slotStart + index, index, slotStart
end
local function setTowBarModelVisible(vehicle, isVisible)
if not vehicle then return end
local part = vehicle:getPartById("towbar")
if part == nil then return end
for j = 0, 23 do
for j = 0, (TowbarVariantSize * 2) - 1 do
part:setModelVisible("towbar" .. j, false)
end
@@ -54,11 +107,8 @@ local function setTowBarModelVisible(vehicle, isVisible)
return
end
local scale = script:getModelScale()
if scale >= 1.5 and scale <= 2 then
local z = script:getPhysicsChassisShape():z()/2 - 0.1
part:setModelVisible("towbar" .. math.floor((z*2/3 - 1)*10), true)
end
local slot = getTowbarModelSlot(script)
part:setModelVisible("towbar" .. slot, true)
vehicle:doDamageOverlay()
end
@@ -238,6 +288,10 @@ function TowBarMod.Hook.setVehiclePostAttach(playerObj, towedVehicle, retriesLef
towedVehicle:setBrakingForce(0)
towedVehicle:constraintChanged()
towedVehicle:updateTotalMass()
-- Re-show the towbar model after the script name has been restored.
-- setScriptName() resets model visibility, so we must set it again here.
setTowBarModelVisible(towedVehicle, true)
end
function TowBarMod.Hook.performAttachTowBar(playerObj, towingVehicle, towedVehicle, attachmentA, attachmentB)
@@ -463,6 +517,65 @@ function TowBarMod.Hook.OnGameStart()
end
end
---------------------------------------------------------------------------
--- Dev / debug helpers
---------------------------------------------------------------------------
function TowBarMod.Hook.devShowAllTowbarModels(playerObj, vehicle)
if not vehicle then return end
local part = vehicle:getPartById("towbar")
if part == nil then
print("[TowBar DEV] No 'towbar' part found on vehicle " .. tostring(vehicle:getScriptName()))
return
end
local script = vehicle:getScript()
local chassisZ = script and script:getPhysicsChassisShape():z() or 0
local halfZ = chassisZ / 2
local modelScale = script and getVehicleModelScale(script) or nil
local slot, index, slotStart = 0, 0, TowbarNormalStart
if script then
slot, index, slotStart = getTowbarModelSlot(script)
end
print("[TowBar DEV] Vehicle: " .. tostring(vehicle:getScriptName()))
print("[TowBar DEV] chassisShape.z = " .. tostring(chassisZ) .. ", half = " .. tostring(halfZ))
print("[TowBar DEV] modelScale = " .. tostring(modelScale) .. ", largeModel = " .. tostring(slotStart == TowbarLargeStart))
print("[TowBar DEV] Formula picks index = " .. tostring(index) .. " (towbar" .. tostring(slot) .. " at Z offset " .. tostring(1.0 + index * 0.1) .. ") [chassisZ > 3.0: " .. tostring(chassisZ > 3.0) .. "]")
print("[TowBar DEV] Showing ALL 48 towbar models (towbar0..towbar47)")
for j = 0, (TowbarVariantSize * 2) - 1 do
part:setModelVisible("towbar" .. j, true)
end
vehicle:doDamageOverlay()
end
function TowBarMod.Hook.devHideAllTowbarModels(playerObj, vehicle)
if not vehicle then return end
local part = vehicle:getPartById("towbar")
if part == nil then
print("[TowBar DEV] No 'towbar' part found on vehicle " .. tostring(vehicle:getScriptName()))
return
end
print("[TowBar DEV] Hiding ALL towbar models on " .. tostring(vehicle:getScriptName()))
for j = 0, (TowbarVariantSize * 2) - 1 do
part:setModelVisible("towbar" .. j, false)
end
vehicle:doDamageOverlay()
end
function TowBarMod.Hook.devShowSingleTowbar(playerObj, vehicle, index)
if not vehicle then return end
local part = vehicle:getPartById("towbar")
if part == nil then
print("[TowBar DEV] No 'towbar' part found on vehicle " .. tostring(vehicle:getScriptName()))
return
end
for j = 0, (TowbarVariantSize * 2) - 1 do
part:setModelVisible("towbar" .. j, false)
end
print("[TowBar DEV] Showing only towbar" .. tostring(index) .. " (Z offset " .. tostring(1.0 + index * 0.1) .. ") on " .. tostring(vehicle:getScriptName()))
part:setModelVisible("towbar" .. index, true)
vehicle:doDamageOverlay()
end
Events.OnSpawnVehicleEnd.Add(TowBarMod.Hook.OnSpawnVehicle)
if Events.OnGameStart then
Events.OnGameStart.Add(TowBarMod.Hook.OnGameStart)

View File

@@ -126,6 +126,71 @@ function TowBarMod.UI.addUnhookOptionToMenu(playerObj, vehicle)
)
end
---------------------------------------------------------------------------
--- Dev menu
---------------------------------------------------------------------------
function TowBarMod.UI.showDevSingleTowbarMenu(playerObj, vehicle)
local playerIndex = playerObj:getPlayerNum()
local menu = getPlayerRadialMenu(playerIndex)
menu:clear()
for j = 0, 47 do
local zIndex = j % 24
local modelType = (j >= 24) and "large" or "normal"
menu:addSlice(
"towbar" .. j .. " [" .. modelType .. "] (Z=" .. tostring(1.0 + zIndex * 0.1) .. ")",
getTexture("media/textures/tow_bar_icon.png"),
TowBarMod.Hook.devShowSingleTowbar,
playerObj,
vehicle,
j
)
end
menu:setX(getPlayerScreenLeft(playerIndex) + getPlayerScreenWidth(playerIndex) / 2 - menu:getWidth() / 2)
menu:setY(getPlayerScreenTop(playerIndex) + getPlayerScreenHeight(playerIndex) / 2 - menu:getHeight() / 2)
menu:addToUIManager()
if JoypadState.players[playerObj:getPlayerNum()+1] then
menu:setHideWhenButtonReleased(Joypad.DPadUp)
setJoypadFocus(playerObj:getPlayerNum(), menu)
playerObj:setJoypadIgnoreAimUntilCentered(true)
end
end
function TowBarMod.UI.addDevOptionsToMenu(playerObj, vehicle)
if not TowBarMod.Config.devMode then return end
if not vehicle then return end
local menu = getPlayerRadialMenu(playerObj:getPlayerNum())
if menu == nil then return end
menu:addSlice(
"[DEV] Show ALL Towbars",
getTexture("media/textures/tow_bar_icon.png"),
TowBarMod.Hook.devShowAllTowbarModels,
playerObj,
vehicle
)
menu:addSlice(
"[DEV] Hide ALL Towbars",
getTexture("media/textures/tow_bar_icon.png"),
TowBarMod.Hook.devHideAllTowbarModels,
playerObj,
vehicle
)
menu:addSlice(
"[DEV] Pick Single Towbar...",
getTexture("media/textures/tow_bar_icon.png"),
TowBarMod.UI.showDevSingleTowbarMenu,
playerObj,
vehicle
)
end
---------------------------------------------------------------------------
--- Mod compability
---------------------------------------------------------------------------
@@ -157,5 +222,7 @@ function ISVehicleMenu.showRadialMenu(playerObj)
elseif not vehicle:getVehicleTowing() and not vehicle:getVehicleTowedBy() then
TowBarMod.UI.addHookOptionToMenu(playerObj, vehicle)
end
TowBarMod.UI.addDevOptionsToMenu(playerObj, vehicle)
end