diff --git a/42.13/media/lua/client/TowBar/Config.lua b/42.13/media/lua/client/TowBar/Config.lua index 25e1dc0..77f509f 100644 --- a/42.13/media/lua/client/TowBar/Config.lua +++ b/42.13/media/lua/client/TowBar/Config.lua @@ -4,4 +4,6 @@ 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 \ No newline at end of file +TowBarMod.Config.vanillaTowbarModelScaleMin = 1.5 +TowBarMod.Config.vanillaTowbarModelScaleMax = 2.0 +TowBarMod.Config.smallScaleTowbarIndexOffset = 2 diff --git a/42.13/media/lua/client/TowBar/TowingHooking.lua b/42.13/media/lua/client/TowBar/TowingHooking.lua index 7f01460..28d7f7a 100644 --- a/42.13/media/lua/client/TowBar/TowingHooking.lua +++ b/42.13/media/lua/client/TowBar/TowingHooking.lua @@ -37,6 +37,8 @@ local TowbarVariantSize = 24 local TowbarNormalStart = 0 local TowbarLargeStart = 24 local TowbarMaxIndex = TowbarVariantSize - 1 +local VanillaScaleMin = 1.5 +local VanillaScaleMax = 2.0 local function getVehicleModelScale(script) if not script then return nil end @@ -62,38 +64,76 @@ local function getVehicleModelScale(script) return nil end -local function shouldUseLargeTowbarModel(script) +local function isVanillaScale(script) local modelScale = getVehicleModelScale(script) if modelScale == nil then - return false + return true end - local configuredThreshold = TowBarMod.Config and tonumber(TowBarMod.Config.largeTowbarModelScaleThreshold) - local threshold = configuredThreshold or 1.2 - return modelScale < threshold + local configuredMin = TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMin) + local configuredMax = TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMax) + local minScale = configuredMin or VanillaScaleMin + local maxScale = configuredMax or VanillaScaleMax + return modelScale >= minScale and modelScale <= maxScale +end + +local function getTowbarIndexVanilla(script) + local z = script:getPhysicsChassisShape():z() / 2 - 0.1 + local index = math.floor((z * 2 / 3 - 1) * 10) + return math.max(0, math.min(TowbarMaxIndex, index)) +end + +local function getTowbarIndexSmallScale(script) + if not script then return nil end + + local maxAbsTowZ = nil + local trailer = script:getAttachmentById("trailer") + if trailer then + maxAbsTowZ = math.abs(trailer:getOffset():z()) + end + local trailerFront = script:getAttachmentById("trailerfront") + if trailerFront then + local frontAbsZ = math.abs(trailerFront:getOffset():z()) + if not maxAbsTowZ or frontAbsZ > maxAbsTowZ then + maxAbsTowZ = frontAbsZ + end + end + + if maxAbsTowZ ~= nil then + -- Match KI5-size vehicles by anchoring to tow attachment depth. + -- +0.1 keeps the bar slightly beyond the attachment point. + local index = math.floor((maxAbsTowZ + 0.1 - 1.0) * 10) + return math.max(0, math.min(TowbarMaxIndex, index)) + end + + return nil 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) + local isVanilla = isVanillaScale(script) + local index = getTowbarIndexVanilla(script) + if not isVanilla then + local attachmentIndex = getTowbarIndexSmallScale(script) + if attachmentIndex ~= nil then + index = attachmentIndex + else + local offset = TowBarMod.Config and tonumber(TowBarMod.Config.smallScaleTowbarIndexOffset) or 2 + index = math.max(0, math.min(TowbarMaxIndex, index + offset)) + end end - index = math.max(0, math.min(TowbarMaxIndex, index)) - - local slotStart = shouldUseLargeTowbarModel(script) and TowbarLargeStart or TowbarNormalStart - return slotStart + index, index, slotStart + return index, isVanilla end local function setTowBarModelVisible(vehicle, isVisible) if not vehicle then return end - local part = vehicle:getPartById("towbar") - if part == nil then return end + local normalPart = vehicle:getPartById("towbar") + local largePart = vehicle:getPartById("towbarLarge") + if normalPart == nil and largePart == nil then return end - for j = 0, (TowbarVariantSize * 2) - 1 do - part:setModelVisible("towbar" .. j, false) + for j = 0, TowbarVariantSize - 1 do + if normalPart then normalPart:setModelVisible("towbar" .. j, false) end + if largePart then largePart:setModelVisible("towbar" .. j, false) end end if not isVisible then @@ -107,8 +147,14 @@ local function setTowBarModelVisible(vehicle, isVisible) return end - local slot = getTowbarModelSlot(script) - part:setModelVisible("towbar" .. slot, true) + local index, isVanilla = getTowbarModelSlot(script) + local part = isVanilla and normalPart or largePart + if part == nil then + part = normalPart or largePart + end + if part then + part:setModelVisible("towbar" .. index, true) + end vehicle:doDamageOverlay() end @@ -523,56 +569,74 @@ end 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())) + local normalPart = vehicle:getPartById("towbar") + local largePart = vehicle:getPartById("towbarLarge") + if normalPart == nil and largePart == nil then + print("[TowBar DEV] No 'towbar' or 'towbarLarge' 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 + local index, isVanilla = 0, true if script then - slot, index, slotStart = getTowbarModelSlot(script) + index, isVanilla = getTowbarModelSlot(script) end + local selectedPart = isVanilla and "towbar" or "towbarLarge" 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) + print("[TowBar DEV] modelScale = " .. tostring(modelScale) .. ", part = " .. selectedPart) + print("[TowBar DEV] Formula picks index = " .. tostring(index) .. " (towbar" .. tostring(index) .. " at Z offset " .. tostring(1.0 + index * 0.1) .. ")") + print("[TowBar DEV] Showing towbar0..towbar23 on both parts") + for j = 0, TowbarVariantSize - 1 do + if normalPart then normalPart:setModelVisible("towbar" .. j, true) end + if largePart then largePart:setModelVisible("towbar" .. j, true) end 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())) + local normalPart = vehicle:getPartById("towbar") + local largePart = vehicle:getPartById("towbarLarge") + if normalPart == nil and largePart == nil then + print("[TowBar DEV] No 'towbar' or 'towbarLarge' 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) + for j = 0, TowbarVariantSize - 1 do + if normalPart then normalPart:setModelVisible("towbar" .. j, false) end + if largePart then largePart:setModelVisible("towbar" .. j, false) end 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())) + local normalPart = vehicle:getPartById("towbar") + local largePart = vehicle:getPartById("towbarLarge") + if normalPart == nil and largePart == nil then + print("[TowBar DEV] No 'towbar' or 'towbarLarge' part found on vehicle " .. tostring(vehicle:getScriptName())) return end - for j = 0, (TowbarVariantSize * 2) - 1 do - part:setModelVisible("towbar" .. j, false) + + local localIndex = math.max(0, math.min(TowbarMaxIndex, index % TowbarVariantSize)) + local useLargePart = index >= TowbarVariantSize + + for j = 0, TowbarVariantSize - 1 do + if normalPart then normalPart:setModelVisible("towbar" .. j, false) end + if largePart then largePart:setModelVisible("towbar" .. j, false) end + end + + local part = useLargePart and largePart or normalPart + if part == nil then + part = normalPart or largePart + end + print("[TowBar DEV] Showing only towbar" .. tostring(localIndex) .. " on part " .. tostring(useLargePart and "towbarLarge" or "towbar") .. " (Z offset " .. tostring(1.0 + localIndex * 0.1) .. ") on " .. tostring(vehicle:getScriptName())) + if part then + part:setModelVisible("towbar" .. localIndex, true) 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 diff --git a/42.13/media/lua/server/BTTow.lua b/42.13/media/lua/server/BTTow.lua index bc7ff50..c5e3e06 100644 --- a/42.13/media/lua/server/BTTow.lua +++ b/42.13/media/lua/server/BTTow.lua @@ -6,6 +6,8 @@ local TowbarVariantSize = 24 local TowbarNormalStart = 0 local TowbarLargeStart = 24 local TowbarMaxIndex = TowbarVariantSize - 1 +local VanillaScaleMin = 1.5 +local VanillaScaleMax = 2.0 local function getVehicleModelScale(script) if not script then return nil end @@ -31,47 +33,85 @@ local function getVehicleModelScale(script) return nil end -local function shouldUseLargeTowbarModel(script) +local function isVanillaScale(script) local modelScale = getVehicleModelScale(script) if modelScale == nil then - return false + return true end - local configuredThreshold = TowBarMod and TowBarMod.Config and tonumber(TowBarMod.Config.largeTowbarModelScaleThreshold) - local threshold = configuredThreshold or 1.2 - return modelScale < threshold + local configuredMin = TowBarMod and TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMin) + local configuredMax = TowBarMod and TowBarMod.Config and tonumber(TowBarMod.Config.vanillaTowbarModelScaleMax) + local minScale = configuredMin or VanillaScaleMin + local maxScale = configuredMax or VanillaScaleMax + return modelScale >= minScale and modelScale <= maxScale +end + +local function getTowbarIndexVanilla(script) + local z = script:getPhysicsChassisShape():z() / 2 - 0.1 + local index = math.floor((z * 2 / 3 - 1) * 10) + return math.max(0, math.min(TowbarMaxIndex, index)) +end + +local function getTowbarIndexSmallScale(script) + if not script then return nil end + + local maxAbsTowZ = nil + local trailer = script:getAttachmentById("trailer") + if trailer then + maxAbsTowZ = math.abs(trailer:getOffset():z()) + end + local trailerFront = script:getAttachmentById("trailerfront") + if trailerFront then + local frontAbsZ = math.abs(trailerFront:getOffset():z()) + if not maxAbsTowZ or frontAbsZ > maxAbsTowZ then + maxAbsTowZ = frontAbsZ + end + end + + if maxAbsTowZ ~= nil then + local index = math.floor((maxAbsTowZ + 0.1 - 1.0) * 10) + return math.max(0, math.min(TowbarMaxIndex, index)) + end + + return nil 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) + local isVanilla = isVanillaScale(script) + local index = getTowbarIndexVanilla(script) + if not isVanilla then + local attachmentIndex = getTowbarIndexSmallScale(script) + if attachmentIndex ~= nil then + index = attachmentIndex + else + local offset = TowBarMod and TowBarMod.Config and tonumber(TowBarMod.Config.smallScaleTowbarIndexOffset) or 2 + index = math.max(0, math.min(TowbarMaxIndex, index + offset)) + end end - index = math.max(0, math.min(TowbarMaxIndex, index)) - - local slotStart = shouldUseLargeTowbarModel(script) and TowbarLargeStart or TowbarNormalStart - return slotStart + index + return index, isVanilla end function BTtow.Create.towbar(vehicle, part) if part == nil then return end - for j=0, (TowbarVariantSize * 2) - 1 do + for j=0, TowbarVariantSize - 1 do part:setModelVisible("towbar" .. j, false) end end function BTtow.Init.towbar(vehicle, part) if part == nil then return end - for j=0, (TowbarVariantSize * 2) - 1 do + for j=0, TowbarVariantSize - 1 do part:setModelVisible("towbar" .. j, false) end if vehicle:getModData()["isTowingByTowBar"] and vehicle:getModData()["towed"] then local script = vehicle:getScript() if script then - local slot = getTowbarModelSlot(script) - part:setModelVisible("towbar" .. slot, true) + local index, isVanilla = getTowbarModelSlot(script) + local partId = part:getId() + local shouldShowOnThisPart = (isVanilla and partId == "towbar") or ((not isVanilla) and partId == "towbarLarge") + if shouldShowOnThisPart then + part:setModelVisible("towbar" .. index, true) + end end end end diff --git a/42.13/media/scripts/vehicles/template_battery.txt b/42.13/media/scripts/vehicles/template_battery.txt index f0acebf..d5a679a 100644 --- a/42.13/media/scripts/vehicles/template_battery.txt +++ b/42.13/media/scripts/vehicles/template_battery.txt @@ -1,138 +1,269 @@ module Base { - template vehicle Battery - { + template vehicle Battery + { part towbar - { - model towbar0 - { - file = towbarModel, + { + model towbar0 + { + file = towbarModel, offset = 0 -0.3 1.0, - } - model towbar1 - { - file = towbarModel, + } + model towbar1 + { + file = towbarModel, offset = 0 -0.3 1.1, - } - model towbar2 - { - file = towbarModel, + } + model towbar2 + { + file = towbarModel, offset = 0 -0.3 1.2, - } - model towbar3 - { - file = towbarModel, + } + model towbar3 + { + file = towbarModel, offset = 0 -0.3 1.3, - } - model towbar4 - { - file = towbarModel, + } + model towbar4 + { + file = towbarModel, offset = 0 -0.3 1.4, - } - model towbar5 - { - file = towbarModel, + } + model towbar5 + { + file = towbarModel, offset = 0 -0.3 1.5, - } - model towbar6 - { - file = towbarModel, + } + model towbar6 + { + file = towbarModel, offset = 0 -0.3 1.6, - } - model towbar7 - { - file = towbarModel, + } + model towbar7 + { + file = towbarModel, offset = 0 -0.3 1.7, - } - model towbar8 - { - file = towbarModel, + } + model towbar8 + { + file = towbarModel, offset = 0 -0.3 1.8, - } - model towbar9 - { - file = towbarModel, + } + model towbar9 + { + file = towbarModel, offset = 0 -0.3 1.9, - } - model towbar10 - { - file = towbarModel, + } + model towbar10 + { + file = towbarModel, offset = 0 -0.3 2.0, - } - model towbar11 - { - file = towbarModel, + } + model towbar11 + { + file = towbarModel, offset = 0 -0.3 2.1, - } - model towbar12 - { - file = towbarModel, + } + model towbar12 + { + file = towbarModel, offset = 0 -0.3 2.2, - } - model towbar13 - { - file = towbarModel, + } + model towbar13 + { + file = towbarModel, offset = 0 -0.3 2.3, - } - model towbar14 - { - file = towbarModel, + } + model towbar14 + { + file = towbarModel, offset = 0 -0.3 2.4, - } - model towbar15 - { - file = towbarModel, + } + model towbar15 + { + file = towbarModel, offset = 0 -0.3 2.5, - } - model towbar16 - { - file = towbarModel, + } + model towbar16 + { + file = towbarModel, offset = 0 -0.3 2.6, - } - model towbar17 - { - file = towbarModel, + } + model towbar17 + { + file = towbarModel, offset = 0 -0.3 2.7, - } - model towbar18 - { - file = towbarModel, + } + model towbar18 + { + file = towbarModel, offset = 0 -0.3 2.8, - } - model towbar19 - { - file = towbarModel, + } + model towbar19 + { + file = towbarModel, offset = 0 -0.3 2.9, - } - model towbar20 - { - file = towbarModel, + } + model towbar20 + { + file = towbarModel, offset = 0 -0.3 3.0, - } - model towbar21 - { - file = towbarModel, + } + model towbar21 + { + file = towbarModel, offset = 0 -0.3 3.1, - } - model towbar22 - { - file = towbarModel, + } + model towbar22 + { + file = towbarModel, offset = 0 -0.3 3.2, - } - model towbar23 - { - file = towbarModel, + } + model towbar23 + { + file = towbarModel, offset = 0 -0.3 3.3, - } + } - area = Engine, - mechanicRequireKey = false, - lua - { - create = BTtow.Create.towbar, - init = BTtow.Init.towbar, - } - } + area = Engine, + mechanicRequireKey = false, + lua + { + create = BTtow.Create.towbar, + init = BTtow.Init.towbar, + } + } + part towbarLarge + { + model towbar0 + { + file = towbarModelLarge, + offset = 0 -0.3 1.0, + } + model towbar1 + { + file = towbarModelLarge, + offset = 0 -0.3 1.1, + } + model towbar2 + { + file = towbarModelLarge, + offset = 0 -0.3 1.2, + } + model towbar3 + { + file = towbarModelLarge, + offset = 0 -0.3 1.3, + } + model towbar4 + { + file = towbarModelLarge, + offset = 0 -0.3 1.4, + } + model towbar5 + { + file = towbarModelLarge, + offset = 0 -0.3 1.5, + } + model towbar6 + { + file = towbarModelLarge, + offset = 0 -0.3 1.6, + } + model towbar7 + { + file = towbarModelLarge, + offset = 0 -0.3 1.7, + } + model towbar8 + { + file = towbarModelLarge, + offset = 0 -0.3 1.8, + } + model towbar9 + { + file = towbarModelLarge, + offset = 0 -0.3 1.9, + } + model towbar10 + { + file = towbarModelLarge, + offset = 0 -0.3 2.0, + } + model towbar11 + { + file = towbarModelLarge, + offset = 0 -0.3 2.1, + } + model towbar12 + { + file = towbarModelLarge, + offset = 0 -0.3 2.2, + } + model towbar13 + { + file = towbarModelLarge, + offset = 0 -0.3 2.3, + } + model towbar14 + { + file = towbarModelLarge, + offset = 0 -0.3 2.4, + } + model towbar15 + { + file = towbarModelLarge, + offset = 0 -0.3 2.5, + } + model towbar16 + { + file = towbarModelLarge, + offset = 0 -0.3 2.6, + } + model towbar17 + { + file = towbarModelLarge, + offset = 0 -0.3 2.7, + } + model towbar18 + { + file = towbarModelLarge, + offset = 0 -0.3 2.8, + } + model towbar19 + { + file = towbarModelLarge, + offset = 0 -0.3 2.9, + } + model towbar20 + { + file = towbarModelLarge, + offset = 0 -0.3 3.0, + } + model towbar21 + { + file = towbarModelLarge, + offset = 0 -0.3 3.1, + } + model towbar22 + { + file = towbarModelLarge, + offset = 0 -0.3 3.2, + } + model towbar23 + { + file = towbarModelLarge, + offset = 0 -0.3 3.3, + } + + area = Engine, + mechanicRequireKey = false, + lua + { + create = BTtow.Create.towbar, + init = BTtow.Init.towbar, + } + } part Battery { area = Engine, diff --git a/42.13/media/scripts/vehicles/template_towbar.txt b/42.13/media/scripts/vehicles/template_towbar.txt index 7368b72..68f1b24 100644 --- a/42.13/media/scripts/vehicles/template_towbar.txt +++ b/42.13/media/scripts/vehicles/template_towbar.txt @@ -11,7 +11,7 @@ module Base { mesh = vehicles/Towbar, texture = Vehicles/Towbar_Texture, - scale = 0.02, + scale = 0.02022, } template vehicle Towbar @@ -138,122 +138,134 @@ module Base file = towbarModel, offset = 0 -0.3 3.3, } - model towbar24 + + area = Engine, + mechanicRequireKey = false, + lua + { + create = BTtow.Create.towbar, + init = BTtow.Init.towbar, + } + } + + part towbarLarge + { + model towbar0 { file = towbarModelLarge, offset = 0 -0.3 1.0, } - model towbar25 + model towbar1 { file = towbarModelLarge, offset = 0 -0.3 1.1, } - model towbar26 + model towbar2 { file = towbarModelLarge, offset = 0 -0.3 1.2, } - model towbar27 + model towbar3 { file = towbarModelLarge, offset = 0 -0.3 1.3, } - model towbar28 + model towbar4 { file = towbarModelLarge, offset = 0 -0.3 1.4, } - model towbar29 + model towbar5 { file = towbarModelLarge, offset = 0 -0.3 1.5, } - model towbar30 + model towbar6 { file = towbarModelLarge, offset = 0 -0.3 1.6, } - model towbar31 + model towbar7 { file = towbarModelLarge, offset = 0 -0.3 1.7, } - model towbar32 + model towbar8 { file = towbarModelLarge, offset = 0 -0.3 1.8, } - model towbar33 + model towbar9 { file = towbarModelLarge, offset = 0 -0.3 1.9, } - model towbar34 + model towbar10 { file = towbarModelLarge, offset = 0 -0.3 2.0, } - model towbar35 + model towbar11 { file = towbarModelLarge, offset = 0 -0.3 2.1, } - model towbar36 + model towbar12 { file = towbarModelLarge, offset = 0 -0.3 2.2, } - model towbar37 + model towbar13 { file = towbarModelLarge, offset = 0 -0.3 2.3, } - model towbar38 + model towbar14 { file = towbarModelLarge, offset = 0 -0.3 2.4, } - model towbar39 + model towbar15 { file = towbarModelLarge, offset = 0 -0.3 2.5, } - model towbar40 + model towbar16 { file = towbarModelLarge, offset = 0 -0.3 2.6, } - model towbar41 + model towbar17 { file = towbarModelLarge, offset = 0 -0.3 2.7, } - model towbar42 + model towbar18 { file = towbarModelLarge, offset = 0 -0.3 2.8, } - model towbar43 + model towbar19 { file = towbarModelLarge, offset = 0 -0.3 2.9, } - model towbar44 + model towbar20 { file = towbarModelLarge, offset = 0 -0.3 3.0, } - model towbar45 + model towbar21 { file = towbarModelLarge, offset = 0 -0.3 3.1, } - model towbar46 + model towbar22 { file = towbarModelLarge, offset = 0 -0.3 3.2, } - model towbar47 + model towbar23 { file = towbarModelLarge, offset = 0 -0.3 3.3, @@ -267,5 +279,6 @@ module Base init = BTtow.Init.towbar, } } + } }