Intial Commit
5
42.13/media/lua/client/TowBar/Config.lua
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if not TowBarMod then TowBarMod = {} end
|
||||||
|
if not TowBarMod.Config then TowBarMod.Config = {} end
|
||||||
|
|
||||||
|
TowBarMod.Config.lowLevelAnimation = "RemoveGrass"
|
||||||
|
|
||||||
72
42.13/media/lua/client/TowBar/CustomPathFindAction.lua
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
require "TimedActions/ISBaseTimedAction"
|
||||||
|
|
||||||
|
TowBarCustomPathFind = ISBaseTimedAction:derive("TowBarCustomPathFind")
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:isValid()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:update()
|
||||||
|
if instanceof(self.character, "IsoPlayer") and
|
||||||
|
(self.character:pressedMovement(false) or self.character:pressedCancelAction()) then
|
||||||
|
self:forceStop()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = self.character:getPathFindBehavior2():update()
|
||||||
|
if result == BehaviorResult.Succeeded then
|
||||||
|
self:forceComplete()
|
||||||
|
end
|
||||||
|
|
||||||
|
local x = self.character:getX()
|
||||||
|
local y = self.character:getY()
|
||||||
|
|
||||||
|
if x == self.lastX and y == self.lastY then
|
||||||
|
self.currentTimeInOnePosition = self.currentTimeInOnePosition + 1
|
||||||
|
else
|
||||||
|
self.currentTimeInOnePosition = 0
|
||||||
|
self.lastX = x
|
||||||
|
self.lastY = y
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.currentTimeInOnePosition > self.maxTimeInOnePosition then
|
||||||
|
self:forceComplete()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:start()
|
||||||
|
self.character:facePosition(self.goal[2], self.goal[3])
|
||||||
|
self.character:getPathFindBehavior2():pathToLocationF(self.goal[2], self.goal[3], self.goal[4])
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:stop()
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
self.character:getPathFindBehavior2():cancel()
|
||||||
|
self.character:setPath2(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:perform()
|
||||||
|
self.character:getPathFindBehavior2():cancel()
|
||||||
|
self.character:setPath2(nil)
|
||||||
|
ISBaseTimedAction.perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarCustomPathFind:pathToLocationF(character, targetX, targetY, targetZ)
|
||||||
|
local o = {}
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
o.character = character
|
||||||
|
o.stopOnWalk = false
|
||||||
|
o.stopOnRun = false
|
||||||
|
o.maxTime = -1
|
||||||
|
|
||||||
|
o.maxTimeInOnePosition = 15
|
||||||
|
o.currentTimeInOnePosition = 0
|
||||||
|
o.lastX = -1
|
||||||
|
o.lastY = -1
|
||||||
|
|
||||||
|
o.goal = { 'LocationF', targetX, targetY, targetZ }
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
56
42.13/media/lua/client/TowBar/HookVehicleAction.lua
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
require('TimedActions/ISBaseTimedAction')
|
||||||
|
|
||||||
|
TowBarHookVehicle = ISBaseTimedAction:derive("TowBarHookVehicle")
|
||||||
|
|
||||||
|
|
||||||
|
-- The condition which tells the timed action if it is still valid
|
||||||
|
function TowBarHookVehicle:isValid()
|
||||||
|
return true;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Starts the Timed Action
|
||||||
|
function TowBarHookVehicle:start()
|
||||||
|
self:setActionAnim(self.animation)
|
||||||
|
self.sound = getSoundManager():PlayWorldSound("towbar_hookingSound", false, self.character:getSquare(), 0, 5, 1, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Is called when the time has passed
|
||||||
|
function TowBarHookVehicle:perform()
|
||||||
|
self.sound:stop();
|
||||||
|
|
||||||
|
if self.performFunc ~= nil then
|
||||||
|
self.performFunc(self.character, self.arg1, self.arg2, self.arg3, self.arg4)
|
||||||
|
end
|
||||||
|
|
||||||
|
ISBaseTimedAction.perform(self);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function TowBarHookVehicle:stop()
|
||||||
|
if self.sound then
|
||||||
|
self.sound:stop()
|
||||||
|
end
|
||||||
|
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarHookVehicle:new(character, time, animation, performFunc, arg1, arg2, arg3, arg4)
|
||||||
|
local o = {};
|
||||||
|
setmetatable(o, self)
|
||||||
|
self.__index = self
|
||||||
|
o.stopOnWalk = true
|
||||||
|
o.stopOnRun = true
|
||||||
|
o.maxTime = time
|
||||||
|
|
||||||
|
o.character = character;
|
||||||
|
o.animation = animation
|
||||||
|
|
||||||
|
o.performFunc = performFunc
|
||||||
|
o.arg1 = arg1
|
||||||
|
o.arg2 = arg2
|
||||||
|
o.arg3 = arg3
|
||||||
|
o.arg4 = arg4
|
||||||
|
|
||||||
|
return o;
|
||||||
|
end
|
||||||
|
|
||||||
42
42.13/media/lua/client/TowBar/ScheduleAction.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
require("TimedActions/ISBaseTimedAction")
|
||||||
|
|
||||||
|
TowBarScheduleAction = ISBaseTimedAction:derive("TowBarScheduleAction")
|
||||||
|
|
||||||
|
function TowBarScheduleAction:isValid()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarScheduleAction:start()
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarScheduleAction:perform()
|
||||||
|
if self.performFunc ~= nil then
|
||||||
|
self.performFunc(self.character, self.arg1, self.arg2, self.arg3, self.arg4)
|
||||||
|
end
|
||||||
|
|
||||||
|
ISBaseTimedAction.perform(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarScheduleAction:stop()
|
||||||
|
ISBaseTimedAction.stop(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarScheduleAction:new(character, time, performFunc, arg1, arg2, arg3, arg4)
|
||||||
|
local o = ISBaseTimedAction.new(self, character)
|
||||||
|
|
||||||
|
o.useProgressBar = false
|
||||||
|
o.stopOnWalk = false
|
||||||
|
o.stopOnRun = false
|
||||||
|
|
||||||
|
o.maxTime = time
|
||||||
|
o.character = character
|
||||||
|
|
||||||
|
o.performFunc = performFunc
|
||||||
|
o.arg1 = arg1
|
||||||
|
o.arg2 = arg2
|
||||||
|
o.arg3 = arg3
|
||||||
|
o.arg4 = arg4
|
||||||
|
|
||||||
|
return o
|
||||||
|
end
|
||||||
|
|
||||||
565
42.13/media/lua/client/TowBar/TowingHooking.lua
Normal file
@@ -0,0 +1,565 @@
|
|||||||
|
if not TowBarMod then TowBarMod = {} end
|
||||||
|
if not TowBarMod.Hook then TowBarMod.Hook = {} end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- Tow bar functions
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local TowBarTowMass = 200
|
||||||
|
local CannotDriveWhileTowedFallbackText = "Cannot drive while being towed"
|
||||||
|
local CannotDriveMessageCooldownHours = 1 / 1800 -- 2 seconds
|
||||||
|
local ForcedTowBarReapplyCooldownHours = 1 / 3600 -- 1 second
|
||||||
|
TowBarMod.Hook.reappliedVehicleIds = TowBarMod.Hook.reappliedVehicleIds or {}
|
||||||
|
TowBarMod.Hook.pendingReapplyVehicleIds = TowBarMod.Hook.pendingReapplyVehicleIds or {}
|
||||||
|
TowBarMod.Hook.reapplyTickCounter = TowBarMod.Hook.reapplyTickCounter or 0
|
||||||
|
TowBarMod.Hook.lastCannotDriveMessageAtByPlayer = TowBarMod.Hook.lastCannotDriveMessageAtByPlayer or {}
|
||||||
|
TowBarMod.Hook.lastForcedReapplyAtByVehicle = TowBarMod.Hook.lastForcedReapplyAtByVehicle or {}
|
||||||
|
TowBarMod.Hook.lastTowBarVehicleIdByPlayer = TowBarMod.Hook.lastTowBarVehicleIdByPlayer or {}
|
||||||
|
|
||||||
|
function TowBarMod.Hook.isTowedByTowBar(vehicle)
|
||||||
|
if not vehicle then return false end
|
||||||
|
|
||||||
|
local modData = vehicle:getModData()
|
||||||
|
if not modData or not modData["isTowingByTowBar"] or not modData["towed"] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local towingVehicle = vehicle:getVehicleTowedBy()
|
||||||
|
if not towingVehicle then return false end
|
||||||
|
|
||||||
|
local towingModData = towingVehicle:getModData()
|
||||||
|
return towingModData and towingModData["isTowingByTowBar"] == true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.getCannotDriveWhileTowedText()
|
||||||
|
local msg = getText("UI_Text_Towing_cannotDriveWhileTowed")
|
||||||
|
if not msg or msg == "UI_Text_Towing_cannotDriveWhileTowed" then
|
||||||
|
return CannotDriveWhileTowedFallbackText
|
||||||
|
end
|
||||||
|
return msg
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
if not playerObj then return end
|
||||||
|
local playerNum = playerObj:getPlayerNum()
|
||||||
|
local nowHours = getGameTime() and getGameTime():getWorldAgeHours() or nil
|
||||||
|
local lastHours = TowBarMod.Hook.lastCannotDriveMessageAtByPlayer[playerNum]
|
||||||
|
if nowHours and lastHours and (nowHours - lastHours) < CannotDriveMessageCooldownHours then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.lastCannotDriveMessageAtByPlayer[playerNum] = nowHours or 0
|
||||||
|
|
||||||
|
-- Match the overhead-style skill/feedback text.
|
||||||
|
HaloTextHelper.addBadText(playerObj, TowBarMod.Hook.getCannotDriveWhileTowedText())
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.installStartEngineBlock()
|
||||||
|
if not ISVehicleMenu or not ISVehicleMenu.onStartEngine then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if TowBarMod.Hook._startEngineBlockInstalled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook.defaultOnStartEngine = ISVehicleMenu.onStartEngine
|
||||||
|
ISVehicleMenu.onStartEngine = function(playerObj)
|
||||||
|
local vehicle = playerObj and playerObj:getVehicle() or nil
|
||||||
|
if TowBarMod.Hook.isTowedByTowBar(vehicle) then
|
||||||
|
TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook.defaultOnStartEngine(playerObj)
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook._startEngineBlockInstalled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.getVehicleByIdSafe(vehicleId)
|
||||||
|
if getVehicleById then
|
||||||
|
return getVehicleById(vehicleId)
|
||||||
|
end
|
||||||
|
|
||||||
|
local cell = getCell()
|
||||||
|
if not cell then return nil end
|
||||||
|
local vehicles = cell:getVehicles()
|
||||||
|
if not vehicles then return nil end
|
||||||
|
|
||||||
|
for i = 0, vehicles:size() - 1 do
|
||||||
|
local vehicle = vehicles:get(i)
|
||||||
|
if vehicle and vehicle:getId() == vehicleId then
|
||||||
|
return vehicle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.shouldBlockDriverSeatForTowBar(playerObj, vehicle, seat)
|
||||||
|
if not playerObj or not vehicle then return false end
|
||||||
|
if seat ~= 0 then return false end
|
||||||
|
return TowBarMod.Hook.isTowedByTowBar(vehicle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.hasPendingSeatSafetyAction(playerObj)
|
||||||
|
if not playerObj or not ISTimedActionQueue then return false end
|
||||||
|
|
||||||
|
return ISTimedActionQueue.hasActionType(playerObj, "ISSwitchVehicleSeat")
|
||||||
|
or ISTimedActionQueue.hasActionType(playerObj, "ISExitVehicle")
|
||||||
|
or ISTimedActionQueue.hasActionType(playerObj, "ISStopVehicle")
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.getBestSeatForDriverKick(playerObj, vehicle)
|
||||||
|
if not playerObj or not vehicle then return nil end
|
||||||
|
|
||||||
|
if ISVehicleMenu and ISVehicleMenu.getBestSwitchSeatExit then
|
||||||
|
local best = ISVehicleMenu.getBestSwitchSeatExit(playerObj, vehicle, 0)
|
||||||
|
if best and best > 0 and not vehicle:isSeatOccupied(best) and vehicle:canSwitchSeat(0, best) then
|
||||||
|
return best
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for seat = 1, vehicle:getMaxPassengers() - 1 do
|
||||||
|
if not vehicle:isSeatOccupied(seat) and vehicle:canSwitchSeat(0, seat) then
|
||||||
|
return seat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.tryMoveOrExitTowedDriver(playerObj, vehicle)
|
||||||
|
if not playerObj or not vehicle then return false end
|
||||||
|
if not TowBarMod.Hook.isTowedByTowBar(vehicle) then return false end
|
||||||
|
if not vehicle:isDriver(playerObj) and vehicle:getSeat(playerObj) ~= 0 then return false end
|
||||||
|
if TowBarMod.Hook.hasPendingSeatSafetyAction(playerObj) then return false end
|
||||||
|
|
||||||
|
local seatTo = TowBarMod.Hook.getBestSeatForDriverKick(playerObj, vehicle)
|
||||||
|
if seatTo then
|
||||||
|
if ISVehicleMenu and ISVehicleMenu.onSwitchSeat then
|
||||||
|
ISVehicleMenu.onSwitchSeat(playerObj, seatTo)
|
||||||
|
elseif ISSwitchVehicleSeat then
|
||||||
|
ISTimedActionQueue.add(ISSwitchVehicleSeat:new(playerObj, seatTo))
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not vehicle:isStopped() then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if ISVehicleMenu and ISVehicleMenu.onExit then
|
||||||
|
ISVehicleMenu.onExit(playerObj, 0)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if ISExitVehicle then
|
||||||
|
ISTimedActionQueue.add(ISExitVehicle:new(playerObj))
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
if not TowBarMod.Hook.hasTowBarTowData(vehicle) then return false end
|
||||||
|
|
||||||
|
local vehicleId = vehicle:getId()
|
||||||
|
local nowHours = getGameTime() and getGameTime():getWorldAgeHours() or nil
|
||||||
|
local lastHours = TowBarMod.Hook.lastForcedReapplyAtByVehicle[vehicleId]
|
||||||
|
if nowHours and lastHours and (nowHours - lastHours) < ForcedTowBarReapplyCooldownHours then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.lastForcedReapplyAtByVehicle[vehicleId] = nowHours or 0
|
||||||
|
|
||||||
|
TowBarMod.Hook.clearReapplied(vehicle)
|
||||||
|
TowBarMod.Hook.queueTowBarReapply(vehicle)
|
||||||
|
return TowBarMod.Hook.tryTowBarReapply(vehicle, playerObj)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.installSeatEntryBlock()
|
||||||
|
if not ISVehicleMenu or not ISVehicleMenu.onEnter or not ISVehicleMenu.onSwitchSeat then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if TowBarMod.Hook._seatEntryBlockInstalled then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook.defaultOnEnter = ISVehicleMenu.onEnter
|
||||||
|
TowBarMod.Hook.defaultOnEnter2 = ISVehicleMenu.onEnter2
|
||||||
|
TowBarMod.Hook.defaultOnSwitchSeat = ISVehicleMenu.onSwitchSeat
|
||||||
|
|
||||||
|
ISVehicleMenu.onEnter = function(playerObj, vehicle, seat)
|
||||||
|
if TowBarMod.Hook.shouldBlockDriverSeatForTowBar(playerObj, vehicle, seat) then
|
||||||
|
TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
TowBarMod.Hook.tryMoveOrExitTowedDriver(playerObj, vehicle)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.defaultOnEnter(playerObj, vehicle, seat)
|
||||||
|
end
|
||||||
|
|
||||||
|
if TowBarMod.Hook.defaultOnEnter2 then
|
||||||
|
ISVehicleMenu.onEnter2 = function(playerObj, vehicle, seat)
|
||||||
|
if TowBarMod.Hook.shouldBlockDriverSeatForTowBar(playerObj, vehicle, seat) then
|
||||||
|
TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
TowBarMod.Hook.tryMoveOrExitTowedDriver(playerObj, vehicle)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.defaultOnEnter2(playerObj, vehicle, seat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ISVehicleMenu.onSwitchSeat = function(playerObj, seatTo)
|
||||||
|
local vehicle = playerObj and playerObj:getVehicle() or nil
|
||||||
|
if TowBarMod.Hook.shouldBlockDriverSeatForTowBar(playerObj, vehicle, seatTo) then
|
||||||
|
TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
TowBarMod.Hook.tryMoveOrExitTowedDriver(playerObj, vehicle)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.defaultOnSwitchSeat(playerObj, seatTo)
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook._seatEntryBlockInstalled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.enforceTowedVehicleEngineOff(playerObj)
|
||||||
|
if not playerObj or not instanceof(playerObj, "IsoPlayer") or not playerObj:isLocalPlayer() then return end
|
||||||
|
|
||||||
|
local vehicle = playerObj:getVehicle()
|
||||||
|
if not TowBarMod.Hook.isTowedByTowBar(vehicle) then return end
|
||||||
|
|
||||||
|
if vehicle:isEngineRunning() or vehicle:isEngineStarted() or vehicle:isStarting() then
|
||||||
|
vehicle:shutOff()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.enforceTowedVehicleSeatSafety(playerObj)
|
||||||
|
if not playerObj or not instanceof(playerObj, "IsoPlayer") or not playerObj:isLocalPlayer() then return end
|
||||||
|
|
||||||
|
local vehicle = playerObj:getVehicle()
|
||||||
|
if not TowBarMod.Hook.isTowedByTowBar(vehicle) then return end
|
||||||
|
|
||||||
|
TowBarMod.Hook.lastTowBarVehicleIdByPlayer[playerObj:getPlayerNum()] = vehicle:getId()
|
||||||
|
|
||||||
|
if vehicle:isDriver(playerObj) or vehicle:getSeat(playerObj) == 0 then
|
||||||
|
TowBarMod.Hook.showCannotDriveWhileTowed(playerObj)
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
TowBarMod.Hook.tryMoveOrExitTowedDriver(playerObj, vehicle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.handleTowBarSeatEvent(character)
|
||||||
|
if not character or not instanceof(character, "IsoPlayer") or not character:isLocalPlayer() then return end
|
||||||
|
|
||||||
|
local playerObj = character
|
||||||
|
local vehicle = playerObj:getVehicle()
|
||||||
|
if not TowBarMod.Hook.isTowedByTowBar(vehicle) then return end
|
||||||
|
|
||||||
|
TowBarMod.Hook.lastTowBarVehicleIdByPlayer[playerObj:getPlayerNum()] = vehicle:getId()
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, playerObj)
|
||||||
|
TowBarMod.Hook.enforceTowedVehicleSeatSafety(playerObj)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.OnEnterVehicle(character)
|
||||||
|
TowBarMod.Hook.handleTowBarSeatEvent(character)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.OnSwitchVehicleSeat(character)
|
||||||
|
TowBarMod.Hook.handleTowBarSeatEvent(character)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.OnExitVehicle(character)
|
||||||
|
if not character or not instanceof(character, "IsoPlayer") or not character:isLocalPlayer() then return end
|
||||||
|
|
||||||
|
local playerNum = character:getPlayerNum()
|
||||||
|
local vehicleId = TowBarMod.Hook.lastTowBarVehicleIdByPlayer[playerNum]
|
||||||
|
if not vehicleId then return end
|
||||||
|
|
||||||
|
local vehicle = TowBarMod.Hook.getVehicleByIdSafe(vehicleId)
|
||||||
|
if vehicle and TowBarMod.Hook.hasTowBarTowData(vehicle) then
|
||||||
|
TowBarMod.Hook.forceTowBarReapply(vehicle, character)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.markReapplied(vehicle)
|
||||||
|
if not vehicle then return end
|
||||||
|
local vehicleId = vehicle:getId()
|
||||||
|
TowBarMod.Hook.reappliedVehicleIds[vehicleId] = true
|
||||||
|
TowBarMod.Hook.pendingReapplyVehicleIds[vehicleId] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.clearReapplied(vehicle)
|
||||||
|
if not vehicle then return end
|
||||||
|
local vehicleId = vehicle:getId()
|
||||||
|
TowBarMod.Hook.reappliedVehicleIds[vehicleId] = nil
|
||||||
|
TowBarMod.Hook.pendingReapplyVehicleIds[vehicleId] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.hasTowBarTowData(vehicle)
|
||||||
|
if not vehicle then return false end
|
||||||
|
local modData = vehicle:getModData()
|
||||||
|
return modData and modData["isTowingByTowBar"] and modData["towed"]
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.queueTowBarReapply(vehicle)
|
||||||
|
if not TowBarMod.Hook.hasTowBarTowData(vehicle) then return end
|
||||||
|
local vehicleId = vehicle:getId()
|
||||||
|
TowBarMod.Hook.pendingReapplyVehicleIds[vehicleId] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.tryTowBarReapply(vehicle, playerObj)
|
||||||
|
if not TowBarMod.Hook.hasTowBarTowData(vehicle) then return false end
|
||||||
|
local vehicleId = vehicle:getId()
|
||||||
|
if TowBarMod.Hook.reappliedVehicleIds[vehicleId] then return true end
|
||||||
|
|
||||||
|
local towingVehicle = vehicle:getVehicleTowedBy()
|
||||||
|
if not towingVehicle then return false end
|
||||||
|
local towingModData = towingVehicle:getModData()
|
||||||
|
if not towingModData or towingModData["isTowingByTowBar"] ~= true then return false end
|
||||||
|
|
||||||
|
playerObj = playerObj or getPlayer()
|
||||||
|
if not playerObj then return false end
|
||||||
|
|
||||||
|
local modData = vehicle:getModData()
|
||||||
|
if not modData.towBarOriginalScriptName then
|
||||||
|
modData.towBarOriginalScriptName = vehicle:getScriptName()
|
||||||
|
vehicle:transmitModData()
|
||||||
|
end
|
||||||
|
|
||||||
|
local attachmentA = towingVehicle:getTowAttachmentSelf() or "trailer"
|
||||||
|
local attachmentB = vehicle:getTowAttachmentSelf() or "trailerfront"
|
||||||
|
|
||||||
|
-- Re-run the same rigid tow offset + fake-trailer flow used during normal attach.
|
||||||
|
TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, vehicle, attachmentA, attachmentB)
|
||||||
|
vehicle:setScriptName("notTowingA_Trailer")
|
||||||
|
|
||||||
|
local args = { vehicleA = towingVehicle:getId(), vehicleB = vehicle:getId(), attachmentA = attachmentA, attachmentB = attachmentB }
|
||||||
|
sendClientCommand(playerObj, "vehicle", "attachTrailer", args)
|
||||||
|
ISTimedActionQueue.add(TowBarScheduleAction:new(playerObj, 10, TowBarMod.Hook.setVehiclePostAttach, vehicle))
|
||||||
|
|
||||||
|
TowBarMod.Hook.markReapplied(vehicle)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.reapplyTowBarPostLoad(vehicle)
|
||||||
|
TowBarMod.Hook.queueTowBarReapply(vehicle)
|
||||||
|
TowBarMod.Hook.tryTowBarReapply(vehicle, getPlayer())
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.processPendingReapplies()
|
||||||
|
TowBarMod.Hook.reapplyTickCounter = TowBarMod.Hook.reapplyTickCounter + 1
|
||||||
|
if TowBarMod.Hook.reapplyTickCounter < 15 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
TowBarMod.Hook.reapplyTickCounter = 0
|
||||||
|
|
||||||
|
local playerObj = getPlayer()
|
||||||
|
if not playerObj then return end
|
||||||
|
|
||||||
|
for vehicleId, _ in pairs(TowBarMod.Hook.pendingReapplyVehicleIds) do
|
||||||
|
local vehicle = TowBarMod.Hook.getVehicleByIdSafe(vehicleId)
|
||||||
|
if vehicle then
|
||||||
|
TowBarMod.Hook.tryTowBarReapply(vehicle, playerObj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.OnSpawnVehicle(vehicle)
|
||||||
|
TowBarMod.Hook.reapplyTowBarPostLoad(vehicle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.performAttachTowBar(playerObj, towingVehicle, towedVehicle, attachmentA, attachmentB)
|
||||||
|
if #(TowBarMod.Utils.getHookTypeVariants(towingVehicle, towedVehicle, true)) == 0 then return end
|
||||||
|
|
||||||
|
local towBarItem = playerObj:getInventory():getItemFromType("TowBar.TowBar")
|
||||||
|
if towBarItem ~= nil then
|
||||||
|
sendClientCommand(playerObj, "towbar", "consumeTowBar", { itemId = towBarItem:getID() })
|
||||||
|
end
|
||||||
|
playerObj:setPrimaryHandItem(nil)
|
||||||
|
|
||||||
|
TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicle, attachmentA, attachmentB)
|
||||||
|
|
||||||
|
local towingModData = towingVehicle:getModData()
|
||||||
|
local towedModData = towedVehicle:getModData()
|
||||||
|
towedModData.towBarOriginalScriptName = towedVehicle:getScriptName()
|
||||||
|
towedModData.towBarOriginalMass = towedVehicle:getMass()
|
||||||
|
towedModData.towBarOriginalBrakingForce = towedVehicle:getBrakingForce()
|
||||||
|
|
||||||
|
towingModData["isTowingByTowBar"] = true
|
||||||
|
towedModData["isTowingByTowBar"] = true
|
||||||
|
towedModData["towed"] = true
|
||||||
|
towingVehicle:transmitModData()
|
||||||
|
towedVehicle:transmitModData()
|
||||||
|
|
||||||
|
local part = towedVehicle:getPartById("towbar")
|
||||||
|
if part ~= nil then
|
||||||
|
if towedVehicle:getScript():getModelScale() >= 1.5 and towedVehicle:getScript():getModelScale() <= 2 then
|
||||||
|
local z = towedVehicle:getScript():getPhysicsChassisShape():z()/2 - 0.1
|
||||||
|
part:setModelVisible("towbar" .. math.floor((z*2/3-1)*10), true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
towedVehicle:doDamageOverlay()
|
||||||
|
|
||||||
|
-- Fake a trailer script so the base "attachTrailer" command creates rigid point-constraint towing.
|
||||||
|
towedVehicle:setScriptName("notTowingA_Trailer")
|
||||||
|
local args = { vehicleA = towingVehicle:getId(), vehicleB = towedVehicle:getId(), attachmentA = attachmentA, attachmentB = attachmentB }
|
||||||
|
sendClientCommand(playerObj, "vehicle", "attachTrailer", args)
|
||||||
|
ISTimedActionQueue.add(TowBarScheduleAction:new(playerObj, 10, TowBarMod.Hook.setVehiclePostAttach, towedVehicle))
|
||||||
|
TowBarMod.Hook.markReapplied(towedVehicle)
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.setVehiclePostAttach(playerObj, towedVehicle)
|
||||||
|
if not towedVehicle then return end
|
||||||
|
|
||||||
|
local towedModData = towedVehicle:getModData()
|
||||||
|
if towedModData.towBarOriginalScriptName then
|
||||||
|
towedVehicle:setScriptName(towedModData.towBarOriginalScriptName)
|
||||||
|
end
|
||||||
|
|
||||||
|
towedVehicle:setMass(TowBarTowMass)
|
||||||
|
towedVehicle:setBrakingForce(0)
|
||||||
|
towedVehicle:constraintChanged()
|
||||||
|
towedVehicle:updateTotalMass()
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.attachByTowBarAction(playerObj, towingVehicle, towedVehicle)
|
||||||
|
if playerObj == nil or towingVehicle == nil or towedVehicle == nil then return end
|
||||||
|
|
||||||
|
local item = playerObj:getInventory():getItemFromTypeRecurse("TowBar.TowBar")
|
||||||
|
if item == nil then return end
|
||||||
|
|
||||||
|
if #(TowBarMod.Utils.getHookTypeVariants(towingVehicle, towedVehicle, true)) == 0 then return end
|
||||||
|
|
||||||
|
local hookPoint = towedVehicle:getAttachmentWorldPos("trailerfront", TowBarMod.Utils.tempVector1)
|
||||||
|
if hookPoint == nil then return end
|
||||||
|
ISTimedActionQueue.add(TowBarCustomPathFind:pathToLocationF(playerObj, hookPoint:x(), hookPoint:y(), hookPoint:z()))
|
||||||
|
|
||||||
|
if not playerObj:getInventory():contains("TowBar.TowBar") then
|
||||||
|
ISTimedActionQueue.add(ISInventoryTransferAction:new(playerObj, item, item:getContainer(), playerObj:getInventory(), nil))
|
||||||
|
end
|
||||||
|
|
||||||
|
local storePrim = playerObj:getPrimaryHandItem()
|
||||||
|
if storePrim == nil or storePrim ~= item then
|
||||||
|
ISTimedActionQueue.add(ISEquipWeaponAction:new(playerObj, item, 12, true))
|
||||||
|
end
|
||||||
|
|
||||||
|
ISTimedActionQueue.add(TowBarHookVehicle:new(playerObj, 300, TowBarMod.Config.lowLevelAnimation))
|
||||||
|
|
||||||
|
hookPoint = towingVehicle:getAttachmentWorldPos("trailer", TowBarMod.Utils.tempVector1)
|
||||||
|
if hookPoint == nil then return end
|
||||||
|
ISTimedActionQueue.add(TowBarCustomPathFind:pathToLocationF(playerObj, hookPoint:x(), hookPoint:y(), hookPoint:z()))
|
||||||
|
|
||||||
|
ISTimedActionQueue.add(TowBarHookVehicle:new(
|
||||||
|
playerObj,
|
||||||
|
100,
|
||||||
|
TowBarMod.Config.lowLevelAnimation,
|
||||||
|
TowBarMod.Hook.performAttachTowBar,
|
||||||
|
towingVehicle,
|
||||||
|
towedVehicle,
|
||||||
|
"trailer",
|
||||||
|
"trailerfront"
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.performDeattachTowBar(playerObj, towingVehicle, towedVehicle)
|
||||||
|
TowBarMod.Utils.updateAttachmentsOnDefaultValues(towingVehicle, towedVehicle)
|
||||||
|
|
||||||
|
local args = { vehicle = towedVehicle:getId() }
|
||||||
|
sendClientCommand(playerObj, "towbar", "detachConstraint", args)
|
||||||
|
|
||||||
|
local towedModData = towedVehicle:getModData()
|
||||||
|
if towedModData.towBarOriginalScriptName then
|
||||||
|
towedVehicle:setScriptName(towedModData.towBarOriginalScriptName)
|
||||||
|
end
|
||||||
|
if towedModData.towBarOriginalMass ~= nil then
|
||||||
|
towedVehicle:setMass(towedModData.towBarOriginalMass)
|
||||||
|
end
|
||||||
|
if towedModData.towBarOriginalBrakingForce ~= nil then
|
||||||
|
towedVehicle:setBrakingForce(towedModData.towBarOriginalBrakingForce)
|
||||||
|
end
|
||||||
|
towedVehicle:constraintChanged()
|
||||||
|
towedVehicle:updateTotalMass()
|
||||||
|
|
||||||
|
sendClientCommand(playerObj, "towbar", "giveTowBar", { equipPrimary = true })
|
||||||
|
|
||||||
|
towingVehicle:getModData()["isTowingByTowBar"] = false
|
||||||
|
towedModData["isTowingByTowBar"] = false
|
||||||
|
towedModData["towed"] = false
|
||||||
|
towedModData.towBarOriginalScriptName = nil
|
||||||
|
towedModData.towBarOriginalMass = nil
|
||||||
|
towedModData.towBarOriginalBrakingForce = nil
|
||||||
|
towingVehicle:transmitModData()
|
||||||
|
towedVehicle:transmitModData()
|
||||||
|
TowBarMod.Hook.clearReapplied(towedVehicle)
|
||||||
|
TowBarMod.Hook.lastForcedReapplyAtByVehicle[towedVehicle:getId()] = nil
|
||||||
|
|
||||||
|
local part = towedVehicle:getPartById("towbar")
|
||||||
|
if part ~= nil then
|
||||||
|
for j=0, 23 do
|
||||||
|
part:setModelVisible("towbar" .. j, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
towedVehicle:doDamageOverlay()
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Hook.deattachTowBarAction(playerObj, vehicle)
|
||||||
|
local towingVehicle = vehicle
|
||||||
|
local towedVehicle = vehicle:getVehicleTowing()
|
||||||
|
if vehicle:getVehicleTowedBy() then
|
||||||
|
towingVehicle = vehicle:getVehicleTowedBy()
|
||||||
|
towedVehicle = vehicle
|
||||||
|
end
|
||||||
|
if towingVehicle == nil or towedVehicle == nil then return end
|
||||||
|
|
||||||
|
local localPoint = towingVehicle:getAttachmentLocalPos(towingVehicle:getTowAttachmentSelf(), TowBarMod.Utils.tempVector1)
|
||||||
|
local shift = 0
|
||||||
|
if towingVehicle:getModData()["isChangedTowedAttachment"] then
|
||||||
|
shift = localPoint:z() > 0 and -1 or 1
|
||||||
|
end
|
||||||
|
local hookPoint = towingVehicle:getWorldPos(localPoint:x(), localPoint:y(), localPoint:z() + shift, TowBarMod.Utils.tempVector2)
|
||||||
|
if hookPoint == nil then return end
|
||||||
|
ISTimedActionQueue.add(TowBarCustomPathFind:pathToLocationF(playerObj, hookPoint:x(), hookPoint:y(), hookPoint:z()))
|
||||||
|
|
||||||
|
local storePrim = playerObj:getPrimaryHandItem()
|
||||||
|
if storePrim ~= nil then
|
||||||
|
ISTimedActionQueue.add(ISUnequipAction:new(playerObj, storePrim, 12))
|
||||||
|
end
|
||||||
|
|
||||||
|
ISTimedActionQueue.add(TowBarHookVehicle:new(playerObj, 100, TowBarMod.Config.lowLevelAnimation))
|
||||||
|
|
||||||
|
localPoint = towedVehicle:getAttachmentLocalPos(towedVehicle:getTowAttachmentSelf(), TowBarMod.Utils.tempVector1)
|
||||||
|
shift = 0
|
||||||
|
if towedVehicle:getModData()["isChangedTowedAttachment"] then
|
||||||
|
shift = localPoint:z() > 0 and -1 or 1
|
||||||
|
end
|
||||||
|
hookPoint = towedVehicle:getWorldPos(localPoint:x(), localPoint:y(), localPoint:z() + shift, TowBarMod.Utils.tempVector2)
|
||||||
|
if hookPoint == nil then return end
|
||||||
|
ISTimedActionQueue.add(TowBarCustomPathFind:pathToLocationF(playerObj, hookPoint:x(), hookPoint:y(), hookPoint:z()))
|
||||||
|
|
||||||
|
ISTimedActionQueue.add(TowBarHookVehicle:new(
|
||||||
|
playerObj,
|
||||||
|
300,
|
||||||
|
TowBarMod.Config.lowLevelAnimation,
|
||||||
|
TowBarMod.Hook.performDeattachTowBar,
|
||||||
|
towingVehicle,
|
||||||
|
towedVehicle
|
||||||
|
))
|
||||||
|
end
|
||||||
|
|
||||||
|
TowBarMod.Hook.installStartEngineBlock()
|
||||||
|
TowBarMod.Hook.installSeatEntryBlock()
|
||||||
|
Events.OnGameStart.Add(TowBarMod.Hook.installStartEngineBlock)
|
||||||
|
Events.OnGameStart.Add(TowBarMod.Hook.installSeatEntryBlock)
|
||||||
|
Events.OnPlayerUpdate.Add(TowBarMod.Hook.enforceTowedVehicleEngineOff)
|
||||||
|
Events.OnPlayerUpdate.Add(TowBarMod.Hook.enforceTowedVehicleSeatSafety)
|
||||||
|
Events.OnSpawnVehicleEnd.Add(TowBarMod.Hook.OnSpawnVehicle)
|
||||||
|
Events.OnEnterVehicle.Add(TowBarMod.Hook.OnEnterVehicle)
|
||||||
|
Events.OnSwitchVehicleSeat.Add(TowBarMod.Hook.OnSwitchVehicleSeat)
|
||||||
|
Events.OnExitVehicle.Add(TowBarMod.Hook.OnExitVehicle)
|
||||||
|
Events.OnTick.Add(TowBarMod.Hook.processPendingReapplies)
|
||||||
|
|
||||||
|
|
||||||
161
42.13/media/lua/client/TowBar/TowingUI.lua
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
if not TowBarMod then TowBarMod = {} end
|
||||||
|
if not TowBarMod.UI then TowBarMod.UI = {} end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- UI functions
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function TowBarMod.UI.removeDefaultDetachOption(playerObj)
|
||||||
|
local menu = getPlayerRadialMenu(playerObj:getPlayerNum())
|
||||||
|
if menu == nil then return end
|
||||||
|
|
||||||
|
local tmpSlices = menu.slices
|
||||||
|
menu:clear()
|
||||||
|
for _, slice in ipairs(tmpSlices) do
|
||||||
|
local command = slice.command and slice.command[1]
|
||||||
|
local args = slice.command or {}
|
||||||
|
if command ~= ISVehicleMenu.onDetachTrailer then
|
||||||
|
menu:addSlice(
|
||||||
|
slice.text,
|
||||||
|
slice.texture,
|
||||||
|
args[1],
|
||||||
|
args[2],
|
||||||
|
args[3],
|
||||||
|
args[4],
|
||||||
|
args[5],
|
||||||
|
args[6],
|
||||||
|
args[7]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Show menu with available vehicles for tow bar hook.
|
||||||
|
function TowBarMod.UI.showChooseVehicleMenu(playerObj, vehicle, vehicles, hasTowBar)
|
||||||
|
local playerIndex = playerObj:getPlayerNum()
|
||||||
|
local menu = getPlayerRadialMenu(playerIndex)
|
||||||
|
menu:clear()
|
||||||
|
|
||||||
|
local added = 0
|
||||||
|
for _, veh in ipairs(vehicles) do
|
||||||
|
local hookTypeVariants = TowBarMod.Utils.getHookTypeVariants(vehicle, veh, hasTowBar)
|
||||||
|
if #hookTypeVariants > 0 then
|
||||||
|
local hookType = hookTypeVariants[1]
|
||||||
|
menu:addSlice(
|
||||||
|
hookType.name,
|
||||||
|
getTexture("media/textures/tow_bar_attach.png"),
|
||||||
|
hookType.func,
|
||||||
|
playerObj,
|
||||||
|
hookType.towingVehicle,
|
||||||
|
hookType.towedVehicle,
|
||||||
|
hookType.towingPoint,
|
||||||
|
hookType.towedPoint
|
||||||
|
)
|
||||||
|
added = added + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if added == 0 then return 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.addHookOptionToMenu(playerObj, vehicle)
|
||||||
|
local menu = getPlayerRadialMenu(playerObj:getPlayerNum())
|
||||||
|
if menu == nil then return end
|
||||||
|
|
||||||
|
local hasTowBar = playerObj:getInventory():getItemFromTypeRecurse("TowBar.TowBar") ~= nil
|
||||||
|
if not hasTowBar then return end
|
||||||
|
|
||||||
|
local vehicles = TowBarMod.Utils.getAviableVehicles(vehicle, hasTowBar)
|
||||||
|
|
||||||
|
if #vehicles == 0 then
|
||||||
|
return
|
||||||
|
elseif #vehicles == 1 then
|
||||||
|
local hookTypeVariants = TowBarMod.Utils.getHookTypeVariants(vehicle, vehicles[1], hasTowBar)
|
||||||
|
if #hookTypeVariants > 0 then
|
||||||
|
local hookType = hookTypeVariants[1]
|
||||||
|
menu:addSlice(
|
||||||
|
hookType.name,
|
||||||
|
getTexture("media/textures/tow_bar_attach.png"),
|
||||||
|
hookType.func,
|
||||||
|
playerObj,
|
||||||
|
hookType.towingVehicle,
|
||||||
|
hookType.towedVehicle,
|
||||||
|
hookType.towingPoint,
|
||||||
|
hookType.towedPoint
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
menu:addSlice(
|
||||||
|
getText("UI_Text_Towing_attach") .. "...",
|
||||||
|
getTexture("media/textures/tow_bar_attach.png"),
|
||||||
|
TowBarMod.UI.showChooseVehicleMenu,
|
||||||
|
playerObj,
|
||||||
|
vehicle,
|
||||||
|
vehicles,
|
||||||
|
hasTowBar
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.UI.addUnhookOptionToMenu(playerObj, vehicle)
|
||||||
|
local menu = getPlayerRadialMenu(playerObj:getPlayerNum())
|
||||||
|
if menu == nil then return end
|
||||||
|
if not vehicle:getModData()["isTowingByTowBar"] then return end
|
||||||
|
if not vehicle:getVehicleTowing() and not vehicle:getVehicleTowedBy() then return end
|
||||||
|
|
||||||
|
local towedVehicle = vehicle
|
||||||
|
if vehicle:getVehicleTowing() then
|
||||||
|
towedVehicle = vehicle:getVehicleTowing()
|
||||||
|
end
|
||||||
|
|
||||||
|
menu:addSlice(
|
||||||
|
getText("ContextMenu_Vehicle_DetachTrailer", ISVehicleMenu.getVehicleDisplayName(towedVehicle)),
|
||||||
|
getTexture("media/textures/tow_bar_detach.png"),
|
||||||
|
TowBarMod.Hook.deattachTowBarAction,
|
||||||
|
playerObj,
|
||||||
|
towedVehicle
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- Mod compability
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if getActivatedMods():contains("vehicle_additions") then
|
||||||
|
require("Vehicles/ISUI/Oven_Mattress_RadialMenu")
|
||||||
|
require("Vehicles/ISUI/FuelTruckTank_ISVehicleMenu_FillPartMenu")
|
||||||
|
end
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- Attach to default menu method
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if TowBarMod.UI.defaultShowRadialMenu == nil then
|
||||||
|
TowBarMod.UI.defaultShowRadialMenu = ISVehicleMenu.showRadialMenu
|
||||||
|
end
|
||||||
|
|
||||||
|
function ISVehicleMenu.showRadialMenu(playerObj)
|
||||||
|
TowBarMod.UI.defaultShowRadialMenu(playerObj)
|
||||||
|
|
||||||
|
if playerObj:getVehicle() then return end
|
||||||
|
|
||||||
|
local vehicle = ISVehicleMenu.getVehicleToInteractWith(playerObj)
|
||||||
|
if vehicle == nil then return end
|
||||||
|
|
||||||
|
if vehicle:getModData()["isTowingByTowBar"] then
|
||||||
|
TowBarMod.UI.removeDefaultDetachOption(playerObj)
|
||||||
|
TowBarMod.UI.addUnhookOptionToMenu(playerObj, vehicle)
|
||||||
|
elseif not vehicle:getVehicleTowing() and not vehicle:getVehicleTowedBy() then
|
||||||
|
TowBarMod.UI.addHookOptionToMenu(playerObj, vehicle)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
173
42.13/media/lua/client/TowBar/TowingUtils.lua
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
if not TowBarMod then TowBarMod = {} end
|
||||||
|
if not TowBarMod.Utils then TowBarMod.Utils = {} end
|
||||||
|
|
||||||
|
TowBarMod.Utils.tempVector1 = Vector3f.new()
|
||||||
|
TowBarMod.Utils.tempVector2 = Vector3f.new()
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
--- Util functions
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function TowBarMod.Utils.isTrailer(vehicle)
|
||||||
|
return string.match(string.lower(vehicle:getScript():getName()), "trailer")
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return vehicles from sector that player can tow by tow bar.
|
||||||
|
function TowBarMod.Utils.getAviableVehicles(mainVehicle, hasTowBar)
|
||||||
|
local vehicles = {}
|
||||||
|
if not hasTowBar then return vehicles end
|
||||||
|
|
||||||
|
local square = mainVehicle:getSquare()
|
||||||
|
if square == nil then return vehicles end
|
||||||
|
|
||||||
|
-- Match vanilla towing search radius.
|
||||||
|
for y=square:getY() - 6, square:getY() + 6 do
|
||||||
|
for x=square:getX() - 6, square:getX() + 6 do
|
||||||
|
local square2 = getCell():getGridSquare(x, y, square:getZ())
|
||||||
|
if square2 then
|
||||||
|
for i=1, square2:getMovingObjects():size() do
|
||||||
|
local obj = square2:getMovingObjects():get(i-1)
|
||||||
|
if obj ~= nil
|
||||||
|
and instanceof(obj, "BaseVehicle")
|
||||||
|
and obj ~= mainVehicle
|
||||||
|
and #(TowBarMod.Utils.getHookTypeVariants(mainVehicle, obj, hasTowBar)) ~= 0 then
|
||||||
|
table.insert(vehicles, obj)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return vehicles
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Return a table with towbar-only hook options for vehicles.
|
||||||
|
function TowBarMod.Utils.getHookTypeVariants(vehicleA, vehicleB, hasTowBar)
|
||||||
|
local hookTypeVariants = {}
|
||||||
|
if not hasTowBar then return hookTypeVariants end
|
||||||
|
|
||||||
|
if vehicleA:getVehicleTowing() or vehicleA:getVehicleTowedBy()
|
||||||
|
or vehicleB:getVehicleTowing() or vehicleB:getVehicleTowedBy() then
|
||||||
|
return hookTypeVariants
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Keep tow bars for vehicle-to-vehicle towing only.
|
||||||
|
if TowBarMod.Utils.isTrailer(vehicleA) or TowBarMod.Utils.isTrailer(vehicleB) then
|
||||||
|
return hookTypeVariants
|
||||||
|
end
|
||||||
|
|
||||||
|
if vehicleA:canAttachTrailer(vehicleB, "trailerfront", "trailer") then
|
||||||
|
local hookType = {}
|
||||||
|
hookType.name = getText("UI_Text_Towing_attach") .. "\n" .. ISVehicleMenu.getVehicleDisplayName(vehicleB) .. "\n" .. getText("UI_Text_Towing_byTowBar")
|
||||||
|
hookType.func = TowBarMod.Hook.attachByTowBarAction
|
||||||
|
hookType.towingVehicle = vehicleB
|
||||||
|
hookType.towedVehicle = vehicleA
|
||||||
|
hookType.textureName = "tow_bar_icon"
|
||||||
|
table.insert(hookTypeVariants, hookType)
|
||||||
|
elseif vehicleA:canAttachTrailer(vehicleB, "trailer", "trailerfront") then
|
||||||
|
local hookType = {}
|
||||||
|
hookType.name = getText("UI_Text_Towing_attach") .. "\n" .. ISVehicleMenu.getVehicleDisplayName(vehicleB) .. "\n" .. getText("UI_Text_Towing_byTowBar")
|
||||||
|
hookType.func = TowBarMod.Hook.attachByTowBarAction
|
||||||
|
hookType.towingVehicle = vehicleA
|
||||||
|
hookType.towedVehicle = vehicleB
|
||||||
|
hookType.textureName = "tow_bar_icon"
|
||||||
|
table.insert(hookTypeVariants, hookType)
|
||||||
|
end
|
||||||
|
|
||||||
|
return hookTypeVariants
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Utils.updateAttachmentsForRigidTow(towingVehicle, towedVehicle, attachmentA, attachmentB)
|
||||||
|
local towingAttachment = towingVehicle:getScript():getAttachmentById(attachmentA)
|
||||||
|
local towedAttachment = towedVehicle:getScript():getAttachmentById(attachmentB)
|
||||||
|
if towingAttachment == nil or towedAttachment == nil then return end
|
||||||
|
|
||||||
|
towingAttachment:setUpdateConstraint(false)
|
||||||
|
towingAttachment:setZOffset(0)
|
||||||
|
|
||||||
|
towedAttachment:setUpdateConstraint(false)
|
||||||
|
towedAttachment:setZOffset(0)
|
||||||
|
|
||||||
|
local offset = towedAttachment:getOffset()
|
||||||
|
local zShift = offset:z() > 0 and 1 or -1
|
||||||
|
towedAttachment:getOffset():set(offset:x(), offset:y(), offset:z() + zShift)
|
||||||
|
local towedModData = towedVehicle:getModData()
|
||||||
|
towedModData["isChangedTowedAttachment"] = true
|
||||||
|
towedModData["towBarChangedAttachmentId"] = attachmentB
|
||||||
|
towedModData["towBarChangedOffsetZShift"] = zShift
|
||||||
|
towedVehicle:transmitModData()
|
||||||
|
end
|
||||||
|
|
||||||
|
function TowBarMod.Utils.updateAttachmentsOnDefaultValues(towingVehicle, towedVehicle)
|
||||||
|
local towingAttachmentId = towingVehicle:getTowAttachmentSelf()
|
||||||
|
local towingAttachment = towingVehicle:getScript():getAttachmentById(towingAttachmentId)
|
||||||
|
if towingAttachment ~= nil then
|
||||||
|
towingAttachment:setUpdateConstraint(true)
|
||||||
|
local zOffset = (towingAttachmentId == "trailer") and -1 or 1
|
||||||
|
towingAttachment:setZOffset(zOffset)
|
||||||
|
end
|
||||||
|
|
||||||
|
local towedModData = towedVehicle:getModData()
|
||||||
|
local changedAttachmentId = towedModData["towBarChangedAttachmentId"] or towedVehicle:getTowAttachmentSelf()
|
||||||
|
local towedAttachment = towedVehicle:getScript():getAttachmentById(changedAttachmentId)
|
||||||
|
if towedAttachment ~= nil then
|
||||||
|
towedAttachment:setUpdateConstraint(true)
|
||||||
|
local zOffset = (changedAttachmentId == "trailer") and -1 or 1
|
||||||
|
towedAttachment:setZOffset(zOffset)
|
||||||
|
|
||||||
|
if towedModData["isChangedTowedAttachment"] then
|
||||||
|
local offset = towedAttachment:getOffset()
|
||||||
|
local storedShift = tonumber(towedModData["towBarChangedOffsetZShift"])
|
||||||
|
if storedShift ~= nil then
|
||||||
|
towedAttachment:getOffset():set(offset:x(), offset:y(), offset:z() - storedShift)
|
||||||
|
else
|
||||||
|
local zShift = offset:z() > 0 and -1 or 1
|
||||||
|
towedAttachment:getOffset():set(offset:x(), offset:y(), offset:z() + zShift)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
towedModData["isChangedTowedAttachment"] = false
|
||||||
|
towedModData["towBarChangedAttachmentId"] = nil
|
||||||
|
towedModData["towBarChangedOffsetZShift"] = nil
|
||||||
|
towedVehicle:transmitModData()
|
||||||
|
end
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
--- Fix mods that add vehicles without tow attachments
|
||||||
|
local function fixTowAttachmentsForOtherVehicleMods()
|
||||||
|
local scriptManager = getScriptManager()
|
||||||
|
local vehicleScripts = scriptManager:getAllVehicleScripts()
|
||||||
|
|
||||||
|
for i = 0, vehicleScripts:size()-1 do
|
||||||
|
local script = vehicleScripts:get(i)
|
||||||
|
local wheelCount = script:getWheelCount()
|
||||||
|
|
||||||
|
local attachHeigtOffset = -0.5
|
||||||
|
if wheelCount > 0 then
|
||||||
|
attachHeigtOffset = script:getWheel(0):getOffset():y() + 0.1
|
||||||
|
end
|
||||||
|
|
||||||
|
if not string.match(string.lower(script:getName()), "trailer") then
|
||||||
|
local trailerAttachment = script:getAttachmentById("trailer")
|
||||||
|
if trailerAttachment == nil then
|
||||||
|
local attach = ModelAttachment.new("trailer")
|
||||||
|
attach:getOffset():set(0, attachHeigtOffset, -script:getPhysicsChassisShape():z()/2 - 0.1)
|
||||||
|
attach:setZOffset(-1)
|
||||||
|
script:addAttachment(attach)
|
||||||
|
end
|
||||||
|
|
||||||
|
local trailerFrontAttachment = script:getAttachmentById("trailerfront")
|
||||||
|
if trailerFrontAttachment == nil then
|
||||||
|
local attach = ModelAttachment.new("trailerfront")
|
||||||
|
attach:getOffset():set(0, attachHeigtOffset, script:getPhysicsChassisShape():z()/2 + 0.1)
|
||||||
|
attach:setZOffset(1)
|
||||||
|
script:addAttachment(attach)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnGameBoot.Add(fixTowAttachmentsForOtherVehicleMods)
|
||||||
|
|
||||||
22
42.13/media/lua/server/BTTow.lua
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
BTtow = {}
|
||||||
|
BTtow.Create = {}
|
||||||
|
BTtow.Init = {}
|
||||||
|
|
||||||
|
function BTtow.Create.towbar(vehicle, part)
|
||||||
|
if part == nil then return end
|
||||||
|
for j=0, 23 do
|
||||||
|
part:setModelVisible("towbar" .. j, false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BTtow.Init.towbar(vehicle, part)
|
||||||
|
if part == nil then return end
|
||||||
|
for j=0, 23 do
|
||||||
|
part:setModelVisible("towbar" .. j, false)
|
||||||
|
end
|
||||||
|
if vehicle:getScript():getModelScale() > 2 or vehicle:getScript():getModelScale() < 1.5 then return end
|
||||||
|
if vehicle:getModData()["isTowingByTowBar"] and vehicle:getModData()["towed"] then
|
||||||
|
local z = vehicle:getScript():getPhysicsChassisShape():z()/2 - 0.1
|
||||||
|
part:setModelVisible("towbar" .. math.floor((z*2/3-1)*10), true)
|
||||||
|
end
|
||||||
|
end
|
||||||
71
42.13/media/lua/server/Items/TowBarItem_Distributions.lua
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
require 'Items/ProceduralDistributions'
|
||||||
|
require 'Items/SuburbsDistributions'
|
||||||
|
require 'Items/Distributions'
|
||||||
|
require 'Items/Distribution_BinJunk'
|
||||||
|
require 'Items/Distribution_ClosetJunk'
|
||||||
|
require 'Items/Distribution_DeskJunk'
|
||||||
|
require 'Items/Distribution_ShelfJunk'
|
||||||
|
require 'Items/Distribution_CounterJunk'
|
||||||
|
require 'Items/Distribution_SideTableJunk'
|
||||||
|
require 'Vehicles/VehicleDistributions'
|
||||||
|
require 'Vehicles/VehicleDistribution_GloveBoxJunk'
|
||||||
|
require 'Vehicles/VehicleDistribution_SeatJunk'
|
||||||
|
require 'Vehicles/VehicleDistribution_TrunkJunk'
|
||||||
|
|
||||||
|
----------------- TOW BAR -----------------------
|
||||||
|
-- Mirror Jack spawn chance into TowBar in container distributions (world + vehicle containers).
|
||||||
|
-- Intentionally excludes story-clutter floor placement tables (RandomizedWorldContent/StoryClutter).
|
||||||
|
|
||||||
|
local TOWBAR_ITEM_TYPE = "TowBar.TowBar"
|
||||||
|
local JACK_ITEM_TYPES = {
|
||||||
|
["Jack"] = true,
|
||||||
|
["Base.Jack"] = true,
|
||||||
|
}
|
||||||
|
|
||||||
|
local function addMissingTowBarsForJack(items)
|
||||||
|
if type(items) ~= "table" then return end
|
||||||
|
|
||||||
|
local jackCountByChance = {}
|
||||||
|
local towBarCountByChance = {}
|
||||||
|
|
||||||
|
for i = 1, #items, 2 do
|
||||||
|
local itemType = items[i]
|
||||||
|
local chance = tonumber(items[i + 1])
|
||||||
|
if type(itemType) == "string" and chance ~= nil then
|
||||||
|
if JACK_ITEM_TYPES[itemType] then
|
||||||
|
jackCountByChance[chance] = (jackCountByChance[chance] or 0) + 1
|
||||||
|
elseif itemType == TOWBAR_ITEM_TYPE then
|
||||||
|
towBarCountByChance[chance] = (towBarCountByChance[chance] or 0) + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for chance, jackCount in pairs(jackCountByChance) do
|
||||||
|
local missing = jackCount - (towBarCountByChance[chance] or 0)
|
||||||
|
for _ = 1, missing do
|
||||||
|
table.insert(items, TOWBAR_ITEM_TYPE)
|
||||||
|
table.insert(items, chance)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function walkContainerDistributions(root, seen)
|
||||||
|
if type(root) ~= "table" or seen[root] then return end
|
||||||
|
seen[root] = true
|
||||||
|
|
||||||
|
for key, value in pairs(root) do
|
||||||
|
if key == "items" and type(value) == "table" then
|
||||||
|
addMissingTowBarsForJack(value)
|
||||||
|
elseif type(value) == "table" then
|
||||||
|
walkContainerDistributions(value, seen)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local seen = {}
|
||||||
|
walkContainerDistributions(ProceduralDistributions, seen)
|
||||||
|
walkContainerDistributions(SuburbsDistributions, seen)
|
||||||
|
walkContainerDistributions(Distributions, seen)
|
||||||
|
walkContainerDistributions(VehicleDistributions, seen)
|
||||||
|
walkContainerDistributions(ClutterTables, seen)
|
||||||
|
|
||||||
73
42.13/media/lua/server/TowingCommands.lua
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
if isClient() then return end
|
||||||
|
|
||||||
|
local Commands = {}
|
||||||
|
local TowBarItemType = "TowBar.TowBar"
|
||||||
|
|
||||||
|
function Commands.attachConstraint(player, args)
|
||||||
|
local vehicleA = args and getVehicleById(args.vehicleA)
|
||||||
|
local vehicleB = args and getVehicleById(args.vehicleB)
|
||||||
|
local attachmentA = args and args.attachmentA
|
||||||
|
local attachmentB = args and args.attachmentB
|
||||||
|
if not vehicleA or not vehicleB or not attachmentA or not attachmentB then return end
|
||||||
|
|
||||||
|
vehicleA:addPointConstraint(player, vehicleB, attachmentA, attachmentB)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Commands.detachConstraint(player, args)
|
||||||
|
local vehicle = args and getVehicleById(args.vehicle)
|
||||||
|
if not vehicle then return end
|
||||||
|
|
||||||
|
vehicle:breakConstraint(true, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Commands.consumeTowBar(player, args)
|
||||||
|
if not player then return end
|
||||||
|
local inventory = player:getInventory()
|
||||||
|
if not inventory then return end
|
||||||
|
|
||||||
|
local towBarItem = nil
|
||||||
|
local itemId = args and args.itemId
|
||||||
|
if itemId then
|
||||||
|
towBarItem = inventory:getItemWithID(itemId)
|
||||||
|
end
|
||||||
|
if not towBarItem then
|
||||||
|
towBarItem = inventory:getFirstTypeRecurse(TowBarItemType)
|
||||||
|
end
|
||||||
|
if not towBarItem then return end
|
||||||
|
|
||||||
|
local wasPrimary = player:isPrimaryHandItem(towBarItem)
|
||||||
|
local wasSecondary = player:isSecondaryHandItem(towBarItem)
|
||||||
|
player:removeFromHands(towBarItem)
|
||||||
|
inventory:Remove(towBarItem)
|
||||||
|
sendRemoveItemFromContainer(inventory, towBarItem)
|
||||||
|
|
||||||
|
if wasPrimary or wasSecondary then
|
||||||
|
sendEquip(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Commands.giveTowBar(player, args)
|
||||||
|
if not player then return end
|
||||||
|
local inventory = player:getInventory()
|
||||||
|
if not inventory then return end
|
||||||
|
|
||||||
|
local towBarItem = inventory:AddItem(TowBarItemType)
|
||||||
|
if not towBarItem then return end
|
||||||
|
sendAddItemToContainer(inventory, towBarItem)
|
||||||
|
|
||||||
|
if args and args.equipPrimary then
|
||||||
|
player:setPrimaryHandItem(towBarItem)
|
||||||
|
sendEquip(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onClientCommand(module, command, player, args)
|
||||||
|
if module ~= "towbar" then return end
|
||||||
|
|
||||||
|
local fn = Commands[command]
|
||||||
|
if fn then
|
||||||
|
fn(player, args or {})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Events.OnClientCommand.Add(onClientCommand)
|
||||||
3
42.13/media/registries.lua
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-- Build 42 registry file.
|
||||||
|
-- This mod currently uses only base registries (for example ItemType = base:normal),
|
||||||
|
-- so no custom identifier registrations are required here.
|
||||||
15
42.13/media/scripts/TowBar_items.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
module TowBar
|
||||||
|
{
|
||||||
|
/*******************Towing Car*******************/
|
||||||
|
item TowBar
|
||||||
|
{
|
||||||
|
DisplayCategory = Tool,
|
||||||
|
Weight = 8.0,
|
||||||
|
ItemType = base:normal,
|
||||||
|
Icon = TowBar,
|
||||||
|
Tooltip = Tooltip_TowBar,
|
||||||
|
StaticModel = towbarModel,
|
||||||
|
WorldStaticModel = towbarModel,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
3265
42.13/media/scripts/vehicles/burntvehicles.txt
Normal file
184
42.13/media/scripts/vehicles/template_battery.txt
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
module Base
|
||||||
|
{
|
||||||
|
template vehicle Battery
|
||||||
|
{
|
||||||
|
part towbar
|
||||||
|
{
|
||||||
|
model towbar0
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.0,
|
||||||
|
}
|
||||||
|
model towbar1
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.1,
|
||||||
|
}
|
||||||
|
model towbar2
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.2,
|
||||||
|
}
|
||||||
|
model towbar3
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.3,
|
||||||
|
}
|
||||||
|
model towbar4
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.4,
|
||||||
|
}
|
||||||
|
model towbar5
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.5,
|
||||||
|
}
|
||||||
|
model towbar6
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.6,
|
||||||
|
}
|
||||||
|
model towbar7
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.7,
|
||||||
|
}
|
||||||
|
model towbar8
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.8,
|
||||||
|
}
|
||||||
|
model towbar9
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.9,
|
||||||
|
}
|
||||||
|
model towbar10
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.0,
|
||||||
|
}
|
||||||
|
model towbar11
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.1,
|
||||||
|
}
|
||||||
|
model towbar12
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.2,
|
||||||
|
}
|
||||||
|
model towbar13
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.3,
|
||||||
|
}
|
||||||
|
model towbar14
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.4,
|
||||||
|
}
|
||||||
|
model towbar15
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.5,
|
||||||
|
}
|
||||||
|
model towbar16
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.6,
|
||||||
|
}
|
||||||
|
model towbar17
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.7,
|
||||||
|
}
|
||||||
|
model towbar18
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.8,
|
||||||
|
}
|
||||||
|
model towbar19
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.9,
|
||||||
|
}
|
||||||
|
model towbar20
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.0,
|
||||||
|
}
|
||||||
|
model towbar21
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.1,
|
||||||
|
}
|
||||||
|
model towbar22
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.2,
|
||||||
|
}
|
||||||
|
model towbar23
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.3,
|
||||||
|
}
|
||||||
|
|
||||||
|
area = Engine,
|
||||||
|
mechanicRequireKey = false,
|
||||||
|
lua
|
||||||
|
{
|
||||||
|
create = BTtow.Create.towbar,
|
||||||
|
init = BTtow.Init.towbar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
part Battery
|
||||||
|
{
|
||||||
|
area = Engine,
|
||||||
|
itemType = Base.CarBattery,
|
||||||
|
mechanicRequireKey = true,
|
||||||
|
category = engine,
|
||||||
|
table install
|
||||||
|
{
|
||||||
|
items
|
||||||
|
{
|
||||||
|
1
|
||||||
|
{
|
||||||
|
type = Base.Screwdriver,
|
||||||
|
count = 1,
|
||||||
|
keep = true,
|
||||||
|
equip = primary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time = 100,
|
||||||
|
professions = ,
|
||||||
|
skills = ,
|
||||||
|
traits = ,
|
||||||
|
recipes = ,
|
||||||
|
test = Vehicles.InstallTest.Default,
|
||||||
|
door = EngineDoor,
|
||||||
|
}
|
||||||
|
table uninstall
|
||||||
|
{
|
||||||
|
items
|
||||||
|
{
|
||||||
|
1
|
||||||
|
{
|
||||||
|
type = Base.Screwdriver,
|
||||||
|
count = 1,
|
||||||
|
keep = true,
|
||||||
|
equip = primary,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time = 100,
|
||||||
|
test = Vehicles.UninstallTest.Battery,
|
||||||
|
}
|
||||||
|
lua
|
||||||
|
{
|
||||||
|
create = Vehicles.Create.Battery,
|
||||||
|
update = Vehicles.Update.Battery,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
144
42.13/media/scripts/vehicles/template_towbar.txt
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
module Base
|
||||||
|
{
|
||||||
|
model towbarModel
|
||||||
|
{
|
||||||
|
mesh = vehicles/Towbar,
|
||||||
|
texture = Vehicles/Towbar_Texture,
|
||||||
|
scale = 0.01,
|
||||||
|
}
|
||||||
|
|
||||||
|
template vehicle Towbar
|
||||||
|
{
|
||||||
|
part towbar
|
||||||
|
{
|
||||||
|
model towbar0
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.0,
|
||||||
|
}
|
||||||
|
model towbar1
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.1,
|
||||||
|
}
|
||||||
|
model towbar2
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.2,
|
||||||
|
}
|
||||||
|
model towbar3
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.3,
|
||||||
|
}
|
||||||
|
model towbar4
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.4,
|
||||||
|
}
|
||||||
|
model towbar5
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.5,
|
||||||
|
}
|
||||||
|
model towbar6
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.6,
|
||||||
|
}
|
||||||
|
model towbar7
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.7,
|
||||||
|
}
|
||||||
|
model towbar8
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.8,
|
||||||
|
}
|
||||||
|
model towbar9
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 1.9,
|
||||||
|
}
|
||||||
|
model towbar10
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.0,
|
||||||
|
}
|
||||||
|
model towbar11
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.1,
|
||||||
|
}
|
||||||
|
model towbar12
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.2,
|
||||||
|
}
|
||||||
|
model towbar13
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.3,
|
||||||
|
}
|
||||||
|
model towbar14
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.4,
|
||||||
|
}
|
||||||
|
model towbar15
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.5,
|
||||||
|
}
|
||||||
|
model towbar16
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.6,
|
||||||
|
}
|
||||||
|
model towbar17
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.7,
|
||||||
|
}
|
||||||
|
model towbar18
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.8,
|
||||||
|
}
|
||||||
|
model towbar19
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 2.9,
|
||||||
|
}
|
||||||
|
model towbar20
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.0,
|
||||||
|
}
|
||||||
|
model towbar21
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.1,
|
||||||
|
}
|
||||||
|
model towbar22
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.2,
|
||||||
|
}
|
||||||
|
model towbar23
|
||||||
|
{
|
||||||
|
file = towbarModel,
|
||||||
|
offset = 0 -0.3 3.3,
|
||||||
|
}
|
||||||
|
|
||||||
|
area = Engine,
|
||||||
|
mechanicRequireKey = false,
|
||||||
|
lua
|
||||||
|
{
|
||||||
|
create = BTtow.Create.towbar,
|
||||||
|
init = BTtow.Init.towbar,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
42.13/mod.info
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
name=Towbars
|
||||||
|
id=hrsys_towbars
|
||||||
|
poster=../common/media/textures/preview.png
|
||||||
|
description=Towbar Towing Towed Towing Towbars. The thrid
|
||||||
|
author=Riggs0
|
||||||
|
category=vehicle
|
||||||
|
icon=../common/media/textures/tow_bar_icon.png
|
||||||
|
url=https://hudsonriggs.systems
|
||||||
|
modversion=1.0.0
|
||||||
|
versionMin=42.13.0
|
||||||
BIN
art/banner.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
art/banner.psd
Normal file
BIN
art/preview.psd
Normal file
BIN
art/thumbnail.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
art/tow_bar_icon.psd
Normal file
3
common/media/lua/shared/Translate/CN/ItemName_CN.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_CN = {
|
||||||
|
ItemName_TowBar.TowBar = "拖车牵引杆"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/CN/Items_CN.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_CN = {
|
||||||
|
DisplayName_TowBar ="拖车牵引杆"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/CN/Tooltip_CN.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_CN = {
|
||||||
|
Tooltip_TowBar = "使用拖车牵引杆可以让你的汽车像拖车一样牵引车辆"
|
||||||
|
}
|
||||||
16
common/media/lua/shared/Translate/CN/UI_CN.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
UI_CN = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "关闭 停车制动器",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "打开 停车制动器",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "没有可供牵引的车辆<br>(或无法牵引)",
|
||||||
|
UI_Text_Towing_attach = "附加",
|
||||||
|
UI_Text_Towing_deattach = "解除连接",
|
||||||
|
UI_Text_Towing_byRope = "通过绳索连接",
|
||||||
|
UI_Text_Towing_byTowBar = "通过拖车牵引杆连接",
|
||||||
|
UI_Text_Towing_byHook = "通过挂钩连接",
|
||||||
|
UI_Text_Towing_flipUpright = "垂直翻转",
|
||||||
|
UI_Text_PushByHands = "用手推车",
|
||||||
|
UI_Text_PushByHands_Left = "从左向右推",
|
||||||
|
UI_Text_PushByHands_Right = "从右向左推",
|
||||||
|
UI_Text_PushByHands_Front = "从前向后推",
|
||||||
|
UI_Text_PushByHands_Behind = "从后向前推",
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/DE/ItemName_DE.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ItemName_DE = {
|
||||||
|
ItemName_TowBar.TowBar = "Abschleppstange"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/DE/Items_DE.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_DE = {
|
||||||
|
DisplayName_TowBar = "Abschleppstange"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/DE/Tooltip_DE.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_DE = {
|
||||||
|
Tooltip_TowBar = "Eine Abschleppstange wird benutzt um ein Fahrzeug wie einen Anh<6E>nger abzuschleppen"
|
||||||
|
}
|
||||||
11
common/media/lua/shared/Translate/DE/UI_DE.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UI_DE = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Feststellbremse lösen",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Feststellbremse einlegen",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "Keine Fahrzeuge zum verbinden oder nicht möglich",
|
||||||
|
UI_Text_Towing_attach = "Verbinde",
|
||||||
|
UI_Text_Towing_deattach = "Trenne",
|
||||||
|
UI_Text_Towing_byRope = "mit einem Abschleppseil",
|
||||||
|
UI_Text_Towing_byTowBar = "mit einer Abschleppstange",
|
||||||
|
UI_Text_Towing_byHook = "mit dem Abschlepphaken",
|
||||||
|
UI_Text_Towing_flipUpright = "Gerade drehen"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/EN/IG_UI_EN.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
IGUI_EN = {
|
||||||
|
IGUI_VehicleParttowbar = "Towbar Attachment"
|
||||||
|
}
|
||||||
4
common/media/lua/shared/Translate/EN/ItemName_EN.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ItemName_EN = {
|
||||||
|
ItemName_TowBar.TowBar = "Tow Bar"
|
||||||
|
}
|
||||||
|
|
||||||
3
common/media/lua/shared/Translate/EN/Tooltip_EN.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_EN = {
|
||||||
|
Tooltip_TowBar = "A tow bar can be used<br>to tow vehicles like a trailer"
|
||||||
|
}
|
||||||
19
common/media/lua/shared/Translate/EN/UI_EN.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
UI_EN = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Turn off parking brake",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Turn on parking brake",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "No vehicles for attach<br>or can't attach",
|
||||||
|
UI_Text_Towing_attach = "Attach",
|
||||||
|
UI_Text_Towing_deattach = "Deattach",
|
||||||
|
UI_Text_Towing_byRope = "by rope",
|
||||||
|
UI_Text_Towing_byTowBar = "by tow bar",
|
||||||
|
UI_Text_Towing_byHook = "by hook",
|
||||||
|
UI_Text_Towing_flipUpright = "Flip upright",
|
||||||
|
UI_Text_Towing_cannotDriveWhileTowed = "Cannot drive while being towed",
|
||||||
|
|
||||||
|
UI_Text_PushByHands = "Push vehicle",
|
||||||
|
UI_Text_PushByHands_Left = "Left",
|
||||||
|
UI_Text_PushByHands_Right = "Right",
|
||||||
|
UI_Text_PushByHands_Front = "Front",
|
||||||
|
UI_Text_PushByHands_Behind = "Behind",
|
||||||
|
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/ES/ItemName_ES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ItemName_ES = {
|
||||||
|
ItemName_TowBar.TowBar = "Enganche de remolque"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/ES/Items_ES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_ES = {
|
||||||
|
DisplayName_TowBar = "Enganche de remolque"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/ES/Tooltip_ES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_ES = {
|
||||||
|
Tooltip_TowBar = "Un enganche de remolque se puede utilizar<br>para enganchar un veh<65>culo como un remolque"
|
||||||
|
}
|
||||||
11
common/media/lua/shared/Translate/ES/UI_ES.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UI_ES = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Apagar freno de mano",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Encender freno de mano",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "No hay vehículos para unir<br>o no se puede unir",
|
||||||
|
UI_Text_Towing_attach = "Unir",
|
||||||
|
UI_Text_Towing_deattach = "Soltar",
|
||||||
|
UI_Text_Towing_byRope = "con una cuerda",
|
||||||
|
UI_Text_Towing_byTowBar = "con el enganche de remolque",
|
||||||
|
UI_Text_Towing_byHook = "con un gancho",
|
||||||
|
UI_Text_Towing_flipUpright = "Voltear hacia arriba"
|
||||||
|
}
|
||||||
4
common/media/lua/shared/Translate/FR/ItemName_FR.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ItemName_FR = {
|
||||||
|
ItemName_TowBar.TowBar = "Barre de remorquage"
|
||||||
|
}
|
||||||
|
|
||||||
3
common/media/lua/shared/Translate/FR/Items_FR.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_FR = {
|
||||||
|
DisplayName_TowBar = "Barre de remorquage"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/FR/Tooltip_FR.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_FR = {
|
||||||
|
Tooltip_TowBar = "Une barre de remorquage<br>pour remorquer des vehicules."
|
||||||
|
}
|
||||||
11
common/media/lua/shared/Translate/FR/UI_FR.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UI_FR = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Desactiver le frein de stationnement",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Activer le frein de stationnement",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "Aucun vehicule pour attacher<br>ou ne peut pas attacher",
|
||||||
|
UI_Text_Towing_attach = "Attacher",
|
||||||
|
UI_Text_Towing_deattach = "Detacher",
|
||||||
|
UI_Text_Towing_byRope = "par corde",
|
||||||
|
UI_Text_Towing_byTowBar = "par barre de remorquage",
|
||||||
|
UI_Text_Towing_byHook = "par crochet",
|
||||||
|
UI_Text_Towing_flipUpright = "Retourner à la verticale"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/IT/ItemName_IT.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
ItemName_IT = {
|
||||||
|
ItemName_TowBar.TowBar = "Barra di traino"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/IT/Items_IT.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_IT = {
|
||||||
|
DisplayName_TowBar = "Barra di traino"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/IT/Tooltip_IT.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_IT = {
|
||||||
|
Tooltip_TowBar = "Una barra di traino pu<70> essere<br>utilizzata per rimorchiare veicoli"
|
||||||
|
}
|
||||||
11
common/media/lua/shared/Translate/IT/UI_IT.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UI_IT = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Sblocca il freno di stazionamento",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Aziona il freno di stazionamento",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "Nessun veicolo rimorchiabile<br>oppure non è possibile agganciare",
|
||||||
|
UI_Text_Towing_attach = "Agganciare",
|
||||||
|
UI_Text_Towing_deattach = "Sganciare",
|
||||||
|
UI_Text_Towing_byRope = "con la corda",
|
||||||
|
UI_Text_Towing_byTowBar = "con la barra di traino",
|
||||||
|
UI_Text_Towing_byHook = "con il gancio",
|
||||||
|
UI_Text_Towing_flipUpright = "Raddrizzare"
|
||||||
|
}
|
||||||
4
common/media/lua/shared/Translate/PL/ItemName_PL.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ItemName_PL = {
|
||||||
|
ItemName_TowBar.TowBar = "Hak holowniczy"
|
||||||
|
}
|
||||||
|
|
||||||
3
common/media/lua/shared/Translate/PL/Items_PL.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_PL = {
|
||||||
|
DisplayName_TowBar = "Hak holowniczy"
|
||||||
|
}
|
||||||
3
common/media/lua/shared/Translate/PL/Tooltip_PL.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Tooltip_PL = {
|
||||||
|
Tooltip_TowBar = "Za pomoc<6F> haka mo<6D>na holowa<77><br>samochody niczym przyczepy"
|
||||||
|
}
|
||||||
11
common/media/lua/shared/Translate/PL/UI_PL.txt
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
UI_PL = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Zwolnij hamulec ręczny",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Zacišgnij hamuler ręczny",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "Brak pojazdów do podłšczenia<br>lub nie można podłšczyć.",
|
||||||
|
UI_Text_Towing_attach = "Podłšcz",
|
||||||
|
UI_Text_Towing_deattach = "Odłšcz",
|
||||||
|
UI_Text_Towing_byRope = "za pomocš liny",
|
||||||
|
UI_Text_Towing_byTowBar = "za pomocš haka holowniczego",
|
||||||
|
UI_Text_Towing_byHook = "za pomocš haka na wysięgniku",
|
||||||
|
UI_Text_Towing_flipUpright = "Przewróć na koła"
|
||||||
|
}
|
||||||
4
common/media/lua/shared/Translate/RU/ItemName_RU.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
ItemName_RU = {
|
||||||
|
ItemName_TowBar.TowBar = "<22><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"
|
||||||
|
}
|
||||||
|
|
||||||
3
common/media/lua/shared/Translate/RU/Items_RU.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Items_RU = {
|
||||||
|
DisplayName_TowBar = "Ćĺńňęŕ˙ ńöĺďęŕ"
|
||||||
|
}
|
||||||
4
common/media/lua/shared/Translate/RU/Tooltip_RU.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
Tooltip_RU = {
|
||||||
|
Tooltip_TowBar = "<22><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><br><3E><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (<28><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)"
|
||||||
|
}
|
||||||
|
|
||||||
17
common/media/lua/shared/Translate/RU/UI_RU.txt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
UI_RU = {
|
||||||
|
UI_Text_Towing_turnOffParkingBrake = "Ñíÿòü ñ ðó÷íîãî òîðìîçà",
|
||||||
|
UI_Text_Towing_turnOnParkingBrake = "Ïîñòàâèòü íà ðó÷íîé òîðìîç",
|
||||||
|
UI_Text_Towing_noAviableVehicles = "Íåò àâòî äëÿ áóêñèðîâêè<br>èëè íå ìîæåò ïðèöåïèòü",
|
||||||
|
UI_Text_Towing_attach = "Ïðèöåïèòü",
|
||||||
|
UI_Text_Towing_deattach = "Îòöåïèòü",
|
||||||
|
UI_Text_Towing_byRope = "áóêñèðîâî÷íûì òðîñîì",
|
||||||
|
UI_Text_Towing_byTowBar = "æåñòêîé ñöåïêîé",
|
||||||
|
UI_Text_Towing_byHook = "êðþêîì",
|
||||||
|
UI_Text_Towing_flipUpright = "Ïåðåâåðíóòü àâòî",
|
||||||
|
|
||||||
|
UI_Text_PushByHands = "Òîëêíóòü àâòî",
|
||||||
|
UI_Text_PushByHands_Left = "Ñëåâà",
|
||||||
|
UI_Text_PushByHands_Right = "Ñïðàâà",
|
||||||
|
UI_Text_PushByHands_Front = "Ñïåðåäè",
|
||||||
|
UI_Text_PushByHands_Behind = "Ñçàäè",
|
||||||
|
}
|
||||||
BIN
common/media/models_X/Towbar.fbx
Normal file
BIN
common/media/sound/towbar_hookingSound.ogg
Normal file
BIN
common/media/textures/Item_TowBar.png
Normal file
|
After Width: | Height: | Size: 714 B |
BIN
common/media/textures/Vehicles/Towbar_Texture.png
Normal file
|
After Width: | Height: | Size: 467 KiB |
BIN
common/media/textures/preview.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
BIN
common/media/textures/tow_bar_attach.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
common/media/textures/tow_bar_detach.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
common/media/textures/tow_bar_icon.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
10
mod.info
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
name=Towbars
|
||||||
|
id=hrsys_towbars
|
||||||
|
poster=common/media/textures/preview.png
|
||||||
|
description=Towbar Towing Towed Towing Towbars. The thrid
|
||||||
|
author=Riggs0
|
||||||
|
category=vehicle
|
||||||
|
versionMin=42.13.0
|
||||||
|
url=https://hudsonriggs.systems
|
||||||
|
modversion=1.0.0
|
||||||
|
icon=common/media/textures/tow_bar_icon.png
|
||||||