Skip to content

Commit 2e86749

Browse files
authored
glue: resource for attaching players (and/or) vehicles to a vehicle (#657)
1 parent a011c8c commit 2e86749

File tree

11 files changed

+2918
-0
lines changed

11 files changed

+2918
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
-- #######################################
2+
-- ## Project: Glue ##
3+
-- ## Author: MTA contributors ##
4+
-- ## Version: 1.3.1 ##
5+
-- #######################################
6+
7+
IS_SERVER = (not triggerServerEvent) -- do not touch — constant; helper bool which checks whether it's a server or client environment
8+
9+
GLUE_WEAPON_SLOTS = {} -- do not touch — constant; used to verify whether passed weapon slot is in valid range (0-12), this is used to restore currently held weapon, because MTA resets weapon slot on attach
10+
GLUE_CLIENT_ATTACH_DATA_SIZE = 6 -- do not touch, unless you modify data sent from client via triggerServerEvent (onServerVehicleAttachElement)
11+
GLUE_ELEMENT_TYPES_AND_EVENTS = { -- do not touch — constant; controls which events would be added for glue logic based on allowed element type
12+
["player"] = "onPlayerWasted",
13+
["vehicle"] = "onVehicleExplode",
14+
}
15+
16+
GLUE_ALLOWED_ELEMENTS = {"player", "vehicle"} -- elements which could be attached to vehicle (supported: "player", "vehicle")
17+
GLUE_VEHICLE_TYPES = { -- only relevant if GLUE_ALLOWED_ELEMENTS contains "vehicle", specifies which vehicle types are allowed to glue
18+
"Automobile",
19+
--"Plane",
20+
"Bike",
21+
"Helicopter",
22+
--"Boat",
23+
"Train",
24+
"Trailer",
25+
"BMX",
26+
"Monster Truck",
27+
"Quad",
28+
}
29+
30+
GLUE_VEHICLE_WHITELIST = { -- only relevant if GLUE_ALLOWED_ELEMENTS contains "vehicle", ignores GLUE_VEHICLE_TYPES; specifies which vehicle models are allowed to glue
31+
500, -- mesa
32+
411, -- infernus
33+
443, -- packer
34+
487, -- maverick
35+
}
36+
37+
GLUE_ATTACH_OVER_VEHICLE = false -- if true, vehicles will attach over the top of target vehicle. if false, vehicles will attach but will maintain original position (seamless, precise glue'ing)
38+
GLUE_DETACH_ON_VEHICLE_EXPLOSION = true -- specifies whether attached elements would be automatically detached, when attachedTo vehicle explodes
39+
GLUE_ATTACH_ON_TOP_OFFSETS = {0, 0, 1.5, 0, 0, 0} -- only relevant if GLUE_ATTACH_OVER_VEHICLE is set to true; offsets (attachX, attachY, attachZ, attachRX, attachRY, attachRZ) used when vehicle is being attached to vehicle on top
40+
GLUE_ATTACH_HELICOPTER_OFFSETS = {0, 0, -1.5, 0, 0, 0} -- offsets (attachX, attachY, attachZ, attachRX, attachRY, attachRZ) used when vehicle is being attached to helicopter
41+
GLUE_ATTACH_VEHICLE_MAX_DISTANCE = 5 -- specifies maximum distance for nearby vehicle to be glued (also serves anti-cheat purpose, so only nearby vehicle could be attached)
42+
GLUE_ATTACH_PLAYER_MAX_DISTANCE = 10 -- ditto
43+
44+
GLUE_PREVENT_CONTROLS = false -- prevent players from shooting their guns while attached to vehicle
45+
GLUE_PREVENT_CONTROLS_LIST = {"fire", "action"} -- only relevant GLUE_PREVENT_CONTROLS is set to true, specifies which controls will be toggled on/off
46+
47+
GLUE_SYNC_CORRECTION = true -- whether attached player positions should be sanity corrected by server, this exists to prevents positional desyncs (e.g: during vehicle teleporting on long distances), which causes player to behave like a ghost (roam freely around SA, while still appearing glued to vehicle for other players)
48+
GLUE_SYNC_CORRECTION_INTERVAL = 3500 -- only relevant if GLUE_SYNC_CORRECTION is set to true, how often glued player position should be corrected, do not set it too low, otherwise you will face weapon aiming interruption (this was constant issue when this variable was set to 1000 before)
49+
50+
GLUE_MESSAGE_PREFIX = "[Glue]:" -- shown in all glue messages
51+
GLUE_MESSAGE_PREFIX_COLOR = "#c68ff8" -- color used by prefix
52+
GLUE_MESSAGE_HIGHLIGHT_COLOR = "#c68ff8" -- color used in message highlights
53+
GLUE_SHOW_ONE_TIME_HINT = true -- whether player should receive one-time (till resource restart) hint, regarding glue keybindings and settings, upon entering a vehicle
54+
55+
GLUE_ALLOW_ATTACH_TOGGLING = true -- should players be able to control attach lock on their vehicle (as a driver)
56+
GLUE_ALLOW_DETACHING_ELEMENTS = true -- should players be able to detach already attached elements (as a driver)
57+
GLUE_ALLOW_DETACHING_VEHICLES_AS_A_DRIVER = true -- should vehicle driver be able to detach vehicle which is attached to his own (this is default behavior for helicopters)
58+
59+
GLUE_ATTACH_DETACH_KEY = "X" -- used to attach/detach yourself/vehicle/nearby vehicle (for helicopters)
60+
GLUE_ATTACH_TOGGLE_KEY = "C" -- only relevant if GLUE_ALLOW_ATTACH_TOGGLING is set to true; key used for toggling attach lock
61+
GLUE_DETACH_ELEMENTS_KEY = "B" -- only relevant if GLUE_ALLOW_DETACHING_ELEMENTS is set to true; key used for detaching all elements attached to vehicle
62+
63+
GLUE_ATTACH_DETACH_DELAY = 300 -- how often player can attach/detach yourself/vehicle
64+
GLUE_ATTACH_TOGGLE_DELAY = 300 -- only relevant if GLUE_ALLOW_ATTACH_TOGGLING is set to true; how often player can toggle vehicle attach lock
65+
GLUE_DETACH_ELEMENTS_DELAY = 1000 -- only relevant if GLUE_ALLOW_DETACHING_ELEMENTS is set to true; how often player can detach all currently attached elements
66+
67+
do
68+
local vehicleModelsWhitelist = {}
69+
local vehicleTypesWhitelist = {}
70+
71+
for vehicleModelID = 1, #GLUE_VEHICLE_WHITELIST do
72+
local vehicleModel = GLUE_VEHICLE_WHITELIST[vehicleModelID]
73+
74+
vehicleModelsWhitelist[vehicleModel] = true
75+
end
76+
77+
for vehicleTypeID = 1, #GLUE_VEHICLE_TYPES do
78+
local vehicleType = GLUE_VEHICLE_TYPES[vehicleTypeID]
79+
80+
vehicleTypesWhitelist[vehicleType] = true
81+
end
82+
83+
GLUE_VEHICLE_WHITELIST = vehicleModelsWhitelist
84+
GLUE_VEHICLE_TYPES = vehicleTypesWhitelist
85+
86+
local weaponSlotMin = 0
87+
local weaponSlotMax = 12
88+
89+
for weaponSlotID = weaponSlotMin, weaponSlotMax do
90+
GLUE_WEAPON_SLOTS[weaponSlotID] = true
91+
end
92+
end
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
-- #######################################
2+
-- ## Project: Glue ##
3+
-- ## Author: MTA contributors ##
4+
-- ## Version: 1.3.1 ##
5+
-- #######################################
6+
7+
local glueHintsDisplayed = false
8+
9+
local function handleGlueAttachAndDetach()
10+
local playerVehicle = getPedOccupiedVehicle(localPlayer)
11+
12+
if (playerVehicle) then
13+
local playerVehicleToDetach = playerVehicle
14+
local playerVehicleHelicopter = isVehicleHelicopter(playerVehicle)
15+
local playerVehicleAttachedVehicle = getAttachedVehicle(playerVehicle)
16+
17+
if (playerVehicleAttachedVehicle) then
18+
playerVehicleToDetach = playerVehicleAttachedVehicle
19+
end
20+
21+
if (playerVehicleToDetach) then
22+
local playerVehicleCanDetach = canPlayerDetachElementFromVehicle(localPlayer, playerVehicleToDetach)
23+
24+
if (playerVehicleCanDetach) then
25+
triggerServerEvent("onServerVehicleDetachElement", localPlayer, playerVehicleToDetach)
26+
27+
return true
28+
end
29+
end
30+
31+
local vehicleNearby = getNearestVehicleFromVehicle(playerVehicle)
32+
33+
if (not vehicleNearby) then
34+
return false
35+
end
36+
37+
local playerVehicleAttach = (playerVehicleHelicopter and vehicleNearby or playerVehicle)
38+
local playerVehicleAttachTo = (playerVehicleHelicopter and playerVehicle or vehicleNearby)
39+
local playerCanAttachVehicleToVehicle = canPlayerAttachElementToVehicle(localPlayer, playerVehicleAttach, playerVehicleAttachTo)
40+
41+
if (not playerCanAttachVehicleToVehicle) then
42+
return false
43+
end
44+
45+
local vehicleAttachX, vehicleAttachY, vehicleAttachZ, vehicleAttachRX, vehicleAttachRY, vehicleAttachRZ = getVehicleAttachData(playerVehicleAttach, playerVehicleAttachTo)
46+
47+
if (playerVehicleHelicopter) then
48+
local helicopterAttachX = GLUE_ATTACH_HELICOPTER_OFFSETS[1]
49+
local helicopterAttachY = GLUE_ATTACH_HELICOPTER_OFFSETS[2]
50+
local helicopterAttachZ = GLUE_ATTACH_HELICOPTER_OFFSETS[3]
51+
local helicopterAttachRX = GLUE_ATTACH_HELICOPTER_OFFSETS[4]
52+
local helicopterAttachRY = GLUE_ATTACH_HELICOPTER_OFFSETS[5]
53+
local helicopterAttachRZ = GLUE_ATTACH_HELICOPTER_OFFSETS[6]
54+
55+
vehicleAttachX, vehicleAttachY, vehicleAttachZ = helicopterAttachX, helicopterAttachY, helicopterAttachZ
56+
vehicleAttachRX, vehicleAttachRY, vehicleAttachRZ = helicopterAttachRX, helicopterAttachRY, helicopterAttachRZ
57+
end
58+
59+
local vehicleAttachData = {vehicleAttachX, vehicleAttachY, vehicleAttachZ, vehicleAttachRX, vehicleAttachRY, vehicleAttachRZ}
60+
61+
triggerServerEvent("onServerVehicleAttachElement", localPlayer, playerVehicleAttach, playerVehicleAttachTo, vehicleAttachData)
62+
63+
return false
64+
end
65+
66+
if (not playerVehicle) then
67+
local playerAttachedTo = getElementAttachedTo(localPlayer)
68+
69+
if (playerAttachedTo) then
70+
local playerCanDetach = canPlayerDetachElementFromVehicle(localPlayer, localPlayer)
71+
72+
if (not playerCanDetach) then
73+
return false
74+
end
75+
76+
triggerServerEvent("onServerVehicleDetachElement", localPlayer, localPlayer)
77+
78+
return true
79+
end
80+
81+
local playerContactElement = getPedContactElement(localPlayer)
82+
local playerContactVehicle = isElementType(playerContactElement, "vehicle")
83+
84+
if (not playerContactVehicle) then
85+
return false
86+
end
87+
88+
local playerCanAttach = canPlayerAttachElementToVehicle(localPlayer, localPlayer, playerContactElement)
89+
90+
if (not playerCanAttach) then
91+
return false
92+
end
93+
94+
local playerX, playerY, playerZ = getElementPosition(localPlayer)
95+
local playerVehicleMatrix = getElementMatrix(playerContactElement)
96+
local playerPosition = {playerX, playerY, playerZ}
97+
local playerAttachX, playerAttachY, playerAttachZ = getOffsetFromXYZ(playerVehicleMatrix, playerPosition)
98+
local playerAttachRX, playerAttachRY, playerAttachRZ = 0, 0, 0
99+
local playerAttachData = {playerAttachX, playerAttachY, playerAttachZ, playerAttachRX, playerAttachRY, playerAttachRZ}
100+
local playerWeaponSlot = getPedWeaponSlot(localPlayer)
101+
102+
triggerServerEvent("onServerVehicleAttachElement", localPlayer, localPlayer, playerContactElement, playerAttachData, playerWeaponSlot)
103+
end
104+
end
105+
bindKey(GLUE_ATTACH_DETACH_KEY, "down", handleGlueAttachAndDetach)
106+
107+
local function handleGlueAttachLock()
108+
local canToggleVehicleAttachLock = canPlayerToggleVehicleAttachLock(localPlayer)
109+
110+
if (canToggleVehicleAttachLock) then
111+
triggerServerEvent("onServerVehicleToggleAttachLock", localPlayer)
112+
end
113+
end
114+
if (GLUE_ALLOW_ATTACH_TOGGLING) then
115+
bindKey(GLUE_ATTACH_TOGGLE_KEY, "down", handleGlueAttachLock)
116+
end
117+
118+
local function handleGlueDetachElements()
119+
local canDetachVehicleElements = canPlayerDetachElementsFromVehicle(localPlayer)
120+
121+
if (canDetachVehicleElements) then
122+
triggerServerEvent("onServerVehicleDetachElements", localPlayer)
123+
end
124+
end
125+
if (GLUE_ALLOW_DETACHING_ELEMENTS) then
126+
bindKey(GLUE_DETACH_ELEMENTS_KEY, "down", handleGlueDetachElements)
127+
end
128+
129+
local function toggleCombatControls(forcedState)
130+
for controlID = 1, #GLUE_PREVENT_CONTROLS_LIST do
131+
local controlName = GLUE_PREVENT_CONTROLS_LIST[controlID]
132+
local controlState = isControlEnabled(controlName)
133+
local controlStateNeedsUpdate = (controlState ~= forcedState)
134+
135+
if (controlStateNeedsUpdate) then
136+
toggleControl(controlName, forcedState)
137+
end
138+
end
139+
140+
return true
141+
end
142+
143+
local function restoreCombatControlsOnEvent(vehicleElement)
144+
local playerAttachedTo = getElementAttachedTo(localPlayer)
145+
146+
if (not playerAttachedTo) then
147+
return false
148+
end
149+
150+
if (vehicleElement) then
151+
local playerAttachedElementMatching = (playerAttachedTo == vehicleElement)
152+
153+
if (not playerAttachedElementMatching) then
154+
return false
155+
end
156+
end
157+
158+
toggleCombatControls(true)
159+
160+
return true
161+
end
162+
163+
local function restoreCombatControlsOnVehicleDestroy()
164+
restoreCombatControlsOnEvent(source)
165+
end
166+
if (GLUE_PREVENT_CONTROLS) then
167+
addEventHandler("onClientElementDestroy", root, restoreCombatControlsOnVehicleDestroy)
168+
end
169+
170+
local function restoreCombatControlsOnResourceStop()
171+
restoreCombatControlsOnEvent()
172+
end
173+
if (GLUE_PREVENT_CONTROLS) then
174+
addEventHandler("onClientResourceStop", root, restoreCombatControlsOnResourceStop)
175+
end
176+
177+
local function displayGlueHintsOnVehicleEnter()
178+
if (glueHintsDisplayed) then
179+
return false
180+
end
181+
182+
local glueHintCanAttachVehicle = findInTable(GLUE_ALLOWED_ELEMENTS, "vehicle")
183+
local glueHintCanAttachPlayer = findInTable(GLUE_ALLOWED_ELEMENTS, "player")
184+
185+
if (not glueHintCanAttachVehicle and not glueHintCanAttachPlayer) then
186+
return false
187+
end
188+
189+
local glueHintAttachVehicles = glueHintCanAttachVehicle and GLUE_MESSAGE_HIGHLIGHT_COLOR.."current/nearby vehicle#ffffff" or ""
190+
local glueHintAttachYourself = glueHintCanAttachPlayer and GLUE_MESSAGE_HIGHLIGHT_COLOR.."yourself#ffffff"..(glueHintCanAttachVehicle and " or " or "") or ""
191+
local glueHintAttachLock = (GLUE_ALLOW_ATTACH_TOGGLING and "#ffffff'"..GLUE_MESSAGE_HIGHLIGHT_COLOR..GLUE_ATTACH_TOGGLE_KEY.."#ffffff' is used to disable/enable attaching to your vehicle. " or "")
192+
local glueHintDetachElements = (GLUE_ALLOW_DETACHING_ELEMENTS and "#ffffff'"..GLUE_MESSAGE_HIGHLIGHT_COLOR..GLUE_DETACH_ELEMENTS_KEY.."#ffffff' to detach all currently attached elements." or "")
193+
194+
local glueHintA = "Press '"..GLUE_MESSAGE_HIGHLIGHT_COLOR..GLUE_ATTACH_DETACH_KEY.."#ffffff' to attach "..glueHintAttachYourself..glueHintAttachVehicles.." to (nearby/current) vehicle."
195+
local glueHintB = glueHintAttachLock
196+
local glueHintC = glueHintDetachElements
197+
198+
sendGlueMessage(glueHintA)
199+
sendGlueMessage(glueHintB, nil, "*")
200+
sendGlueMessage(glueHintC, nil, "*")
201+
202+
glueHintsDisplayed = true
203+
end
204+
if (GLUE_SHOW_ONE_TIME_HINT) then
205+
addEventHandler("onClientPlayerVehicleEnter", localPlayer, displayGlueHintsOnVehicleEnter)
206+
end
207+
208+
function onClientAttachStateChanged(playerAttached)
209+
if (not GLUE_PREVENT_CONTROLS) then
210+
return false
211+
end
212+
213+
local toggleControlState = (not playerAttached)
214+
215+
toggleCombatControls(toggleControlState)
216+
end
217+
addEvent("onClientAttachStateChanged", true)
218+
addEventHandler("onClientAttachStateChanged", localPlayer, onClientAttachStateChanged)

0 commit comments

Comments
 (0)