From 76eb9c6b0f2d6924c3dfd5985305abbbe120805a Mon Sep 17 00:00:00 2001 From: ChemicalCreations <73047231+ChemicalCreations@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:43:02 -0500 Subject: [PATCH] added resource: Chemical Ladder v2.0 (ladders) --- [gameplay]/ladders/README.md | 105 ++++ [gameplay]/ladders/client.lua | 968 ++++++++++++++++++++++++++++++++++ [gameplay]/ladders/data.lua | 693 ++++++++++++++++++++++++ [gameplay]/ladders/meta.xml | 21 + [gameplay]/ladders/server.lua | 427 +++++++++++++++ 5 files changed, 2214 insertions(+) create mode 100644 [gameplay]/ladders/README.md create mode 100644 [gameplay]/ladders/client.lua create mode 100644 [gameplay]/ladders/data.lua create mode 100644 [gameplay]/ladders/meta.xml create mode 100644 [gameplay]/ladders/server.lua diff --git a/[gameplay]/ladders/README.md b/[gameplay]/ladders/README.md new file mode 100644 index 000000000..5c15c726b --- /dev/null +++ b/[gameplay]/ladders/README.md @@ -0,0 +1,105 @@ +# Chemical_Ladders + Make working ladders in MTA + Allows ladders to be climbed in Multi-Theft Auto + Usage: + enter - enter or exit ladders + jump - jump of ladders (left/right changes directly) + crouch - slides down ladders + sprint - enter trough ladders with platforms + + Video v2 - https://youtu.be/K3JhbzGyQto + Video v1 - https://youtu.be/-XVog1RXpxI + + + For more cool free mods: + Visit https://ko-fi.com/chemicalcreations + Share your thoughts https://discord.com/invite/FxHCc7j or HMU + Help the code https://github.com/ChemicalCreations/Chemical_Ladders + + ---- Server Events ---- + "onLadderAdd" ++ root/surfaceElement (surface, ladder) -- when a new ladder is added (may be bypassed by onElementModelChange) + "onLadderRemove" ++ root/surfaceElement (surface[, ladder]) -- when a new ladder is removed (may be bypassed by onElementModelChange) + "onLadderClimbingStart" ++ root/surfaceElement (surface, ladder, ped, step) -- when a ladder is enterd by a ped + "onLadderClimbingStop" ++ root/surfaceElement (surface, ladder, ped) -- when a ladder is exited by a ped + "onPedLadderClimbingStart" ++ ped (surface, ladder, step) -- when a ped starts using a ladder + "onPedLadderClimbingStop" ++ ped (surface, ladder, position) -- when a ped stops using a ladder + "onPedLadderClimbingStep" ++ ped (surface, ladder) -- when a ped changes ladder step animation + NOTE: Ladders are built for player elements and peds may not work or give unexpected results + + ---- Server Functions ---- + setPedClimbingLadder(ped, surface, ladder, pos) - server + isPedClimbingLadder(ped) - shared + getPedsOnLadder(surface) - shared + setPedLadderClimbingEnabled(ped, enabled) - server + isPedLadderClimbingEnabled(ped) - shared + getLadderClosestToPosition(px, py, pz) - shared + getLadders(surface) - shared + setLadderEnabled(surface, ladder, active) - server + setLadderProperties(surface, ladder, properties) - server + getLadderProperties(surface, ladder) - shared + addLadder(surface, sx, sy, sz, tx, ty, tz, rx, ry, rz, d, jumping, inside, sliding, water, exitShift) - server + removeLadder(surface, ladder) - server + + ---- Client Events ---- + "onClientPedLadderClimbingStart" ++ ped (step) -- when a ped starts using a ladder + "onClientPedLadderClimbingStop" ++ ped () -- when a ped stops using a ladder + "onClientPedLadderClimbingStep" ++ ped (step) -- when a ped changes ladder step animation + + ---- Client Functions ---- + isPedClimbingLadder(ped) - shared + getPedsOnLadder(surface) - shared + isPedLadderClimbingEnabled(ped) - shared + getLadderClosestToPosition(px, py, pz) - shared + getLadders(surface) - shared + getLadderProperties(surface, ladder) - shared + + + + -- Table Layouts -- + + ---- Table: climbs ---- + ["SurfaceID"/ladderElement] = { -- Note: If surfaceID is an element, all positions are relative + [ladderIndex] = { -- individual ladders of a surface + sx=0 , sy=0, sz=0, -- ladder start position + tx=0, ty=0, tz=0, -- ladder end position + rx=0, ry=0, rz=0, -- ladder rotation + d=1, -- distance from ladder it can be grabbed (not players grab point has a 0.3 offset) + shift_exit = 0, -- distance to warp player upon ladder exit (Y axis relative to ladder) (doesn't affect all exits) + water = false, -- will fall on ladder exit (change exit anim) + sliding = true, -- allows sliding down ladders by hold "crouch" key + inside = false, -- allows entering ladders' the "sprint" key (for ladders with platforms) (also allows entering from rear of ladder) + jumping = true, -- allows jumping off ladders with the "jump" key + dynamic = false, -- detects ground level to exit ladder + } + } + + + ---- Table: ladderModels ---- + Note: This table will automatically assign a ladder surface to all vehicles/objects created as the index models + [ModelNumber/ModelName] -- { -- Note: Model Name is untested and would likely only support vehicle names atm + [ladderIndex] = {ladderData} -- (See ladder data under "Table Layouts > climbs") + } + + + ---- Table: anims ---- + ["ladderAnim"] = { + block = "dozer", -- animation block + anim = "DOZER_Align_LHS", -- animation name + anim_start = 350, -- anim start position + anim_hold = 530, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 120, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 150, -- ms to blend into anim (for when starting to use a ladder) + climb_up = "exit_l", -- next anim for going up (often to exit) + climb_next = "climb_r", -- next animation to move along lader + climb_down = "enter_l", -- next anim for going down (often to exit) + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, -- used to move ped up/down ladder per time + climb_angle = {{-90, 0}, {0, 170}}, -- used to apply rotation per time + climb_adjust = {{0.0, 000, 300}, {0.243, 400}, {0.700, 800}}, -- used to move ped in/out per time (Y pos axis) + climb_roll = {{0, 300}, {-22, 500}}, -- used to apply "X" rot axis tilt per time + velocity = {x=0.0, y=0.0, z=0.0}, -- used to apply velocity to ped over time (replaces "climb_move" value with velocity) + straight = true, -- used to disable some ped rotation adjustment (mainly in case of "X" axis leaning) + }, \ No newline at end of file diff --git a/[gameplay]/ladders/client.lua b/[gameplay]/ladders/client.lua new file mode 100644 index 000000000..a1cd22a21 --- /dev/null +++ b/[gameplay]/ladders/client.lua @@ -0,0 +1,968 @@ +-- ( xxxx |client) by: Markland aka DarkChemical + + +-- ** Data ** -- +local climbers = {} +local climbs = {} + +local anim = anims + + + + +addEvent("onClientPedLadderClimbingStart") +addEvent("onClientPedLadderClimbingStop") +addEvent("onClientPedLadderClimbingStep") + +addEvent("onClientRecieveLadderClimbingReady", true) +addEvent("onClientRecievePedLadderClimbingState", true) +addEvent("onClientRecieveLadderState", true) + + +function getLineUnitScale3D(sx, sy, sz, ex, ey, ez, m) + local m = m or 1 + local sx, sy, sz, ex, ey, ez = tonumber(sx) or 0, tonumber(sy) or 0, tonumber(sz) or 0, tonumber(ex) or 0, tonumber(ey) or 0, tonumber(ez) or 0 + local ax, ay, az = ex-sx, ey-sy, ez-sz + local d = getDistanceBetweenPoints3D(0, 0, 0, ax, ay, az) + if d == 0 or not d then return 0, 0, 0 end + local dx, dy, dz = ax/d, ay/d, az/d + return dx*m, dy*m, dz*m +end + +function getPointPositionOnLine3D(px, py, pz, sx, sy, sz, tx, ty, tz) + local st = getDistanceBetweenPoints3D(sx, sy, sz, tx, ty, tz) + local sp = getDistanceBetweenPoints3D(sx, sy, sz, px, py, pz) + local tp = getDistanceBetweenPoints3D(tx, ty, tz, px, py, pz) + local atp = math.acos((sp^2+st^2-tp^2)/(2*sp*st)) + local sd = sp*math.cos(atp) + if sd>st or sd<0 then + if tpst or sd<0 then + return tpst or sd<0 then + return tp= 0 and unit1-unit2 <= 180) + or (unit1-unit2 <= -180 and unit1-unit2 >= -360)) then + sign = -1 + end + if phi > 180 then + result = 360-phi + else + result = phi + end + + return result*sign + end +end + + + + + + +function isPedClimbingLadder(ped) + local data = climbers[ped] + return data and true or false +end + +function getPedClimbingLadder(ped) + local data = climbers[ped] + if not data then return false end + return data.surface, data.climb, data.state +end + +function getPedsOnLadder(surface) + local peds = {} + for ped, data in pairs(climbers) do + if surface==nil then + peds[ped] = data.surface + elseif surface==data.surface then + peds[ped] = data.climb + end + end + return peds +end + +function isPedLadderClimbingEnabled(ped) + local eType = ped and isElement(ped) and getElementType(ped) + assert(eType=="ped" or eType=="player") -- isPed + if climbers[ped]==false then return false end + return climbers[ped]==nil or (climbers[ped] and true) +end + +function getLadderPositionFromData(surface, ladder, l) + local l = l or climbs[surface] and climbs[climbs][ladder] + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = l.sx, l.sy, l.sz, l.tx, l.ty, l.tz, l.rx, l.ry, l.rz, l.d + if isElement(surface) then + local m = createMatrix(surface) + sx, sy, sz = getPositionFromMatrixOffset(m, sx, sy, sz) + tx, ty, tz = getPositionFromMatrixOffset(m, tx, ty, tz) + rx, ry, rz = getRotationFromMatrix(getMatrixFromOffset(m, 0, 0, 0, rx, ry, rz)) + end + return sx, sy, sz, tx, ty, tz, rx, ry, rz, d +end + +function getLadderClosestToPosition(px, py, pz) + for i, v in pairs{px, py, pz} do + assert(v==v and type(v)=="number") + end + local climbData, climbSurface, climbID, climbD, climbP, climbSize + for surface, surfaceData in pairs(climbs) do + for climb, l in pairs(surfaceData) do + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(surface, ladder, l) + local dist = ((tx-sx)^2+(ty-sy)^2+(tz-sz)^2)^.5+10 + if ((tx-px)^2+(ty-py)^2+(tz-pz)^2)^.50.5 and "climb_r" or "climb_l" + data.prog = anim[data.state].anim_start + elseif size-climbP*size<1 then + data.dir = -1 + data.position = (size+(0.1))/size + if rot>0 then + data.state = "align_l" + local t = anim[data.state].climb_angle[2][2] + local rot = math.abs(rot) + data.prog = t*(rot/180) + else + data.state = "align_r" + local t = anim[data.state].climb_angle[2][2] + local rot = math.abs(rot) + data.prog = t*(rot/180) + end + elseif l.inside and (rot>130 or rot<-130) then + local px, py, pz = getElementPosition(ped) + local p = data.position + local x, y, z, d = sx+dx*p, sy+dy*p, sz+dz*p + d = getDistanceBetweenPoints3D(px, py, pz, x, y, z) + if d<0.3 then return false end + local r = (( 360 - math.deg ( math.atan2 ( ( px - x ), ( py - y ) ) ) ) % 360)-180 + if math.abs(minus(rz, r))<120 then return end + data.state = "switch" + data.prog = anim[data.state].anim_start + elseif busyT=="move" then + data.state = math.random()>0.5 and "climb_r" or "climb_l" + data.prog = anim[data.state].anim_start + elseif rot>0 then + data.state = "enter_l" + local t = anim[data.state].climb_angle[2][2] + local rot = math.abs(rot) + if rot>90 then return end + rot = rot>90 and 90 or rot + data.prog = t*(1-rot/90) + else + data.state = "enter_r" + local t = anim[data.state].climb_angle[2][2] + local rot = math.abs(rot) + if rot>90 then return end + rot = rot>90 and 90 or rot + data.prog = t*(1-rot/90) + end + climbers[ped] = data + local state = anim[data.state] + if state.blend then + local f = ((data.dir or 0)>0 and state.anim_start or state.anim_end) + if f and state.reverse then f = state.anim_duration-f end + setPedAnimation(ped, state.block, state.anim, -1, false, true, false, false, state.blend, false) + setPedAnimationSpeed(ped, state.anim, 0) + setPedAnimationProgress(ped, state.anim, state.anim_frame or (f/state.anim_duration)) + end + triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + end +end) + +bindKey("jump", "down", function() + local tick = getTickCount() + if tick-cooldown<500 then return end + cooldown = tick + local ped = localPlayer + local data = climbers[ped] + if isControlEnabled("jump") and data then + if data.dir then return end + local surface = climbs[data.surface] + local l = surface[data.climb] + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + if l.jumping==false then return end + if getPedMoveState(ped)~="fall" then return false end + local x, y, z = getElementRotation(getCamera()) + local dir = 0 + local left, right + if isControlEnabled("left") then for key in pairs(getBoundKeys("left")) do if getKeyState(key) then left=true break end end end + if isControlEnabled("right") then for key in pairs(getBoundKeys("right")) do if getKeyState(key) then right=true break end end end + if left and right then + dir = 180 + elseif left or right then + local rot = minus(z, rz) + rot = rot+(left and 90 or -90) + if rot<0 then rot = 360+rot end + dir = rot<90 and 90 or rot>270 and 270 or rot + else + local rot = minus(z, rz) + if rot<0 then rot = 360+rot end + if rot<80 or rot>280 then + dir = 180 + else + dir = rot<90 and 90 or rot>270 and 270 or rot + end + end + data.final_angle = dir + local state = anim[data.state] + if state and not state.anim_hold then return end + local p = math.abs(data.prog-state.anim_hold) + if p>200 then return end + data.dir = -1 + data.next = "leap" + triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + return + end +end) + +bindKey("crouch", "both", function(key, state) + local tick = getTickCount() + if tick-cooldown<500 then return end + cooldown = tick + local ped = localPlayer + local data = climbers[ped] + if isControlEnabled("crouch") and data and state=="down" then + if data.dir then return end + local surface = climbs[data.surface] + local l = surface[data.climb] + if l.sliding==false then return end + if getPedMoveState(ped)~="fall" then return false end + local state = anim[data.state] + if state and not state.anim_hold then return end + local p = math.abs(data.prog-state.anim_hold) + if p>200 then return end + data.dir = -1 + data.state = data.state=="climb_l" and "slide_l" or "slide_r" + triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + return + elseif data and state=="up" then + if data.state~="slide" then return end + if data.next then return end + local surface = climbs[data.surface] + local l = surface[data.climb] + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + if data.position*getDistanceBetweenPoints3D(sx, sy, sz, tx, ty, tz)<1.5 then return end + data.dir = -1 + data.next = "climb_r" + data.dir_next = nil + triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + end +end) +addEventHandler("onClientPedLadderClimbingStep", localPlayer, function(state) + if state~="slide" then return end + local data = climbers[localPlayer] + if data then + if getPedControlState("crouch") then return end + if data.state~="slide" then return end + if data.next then return end + local surface = climbs[data.surface] + local l = surface[data.climb] + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + if data.position*getDistanceBetweenPoints3D(sx, sy, sz, tx, ty, tz)<1.5 then return end + data.dir = -1 + data.next = "climb_r" + data.dir_next = nil + triggerServerEvent("onPlayerReportLadderClimbingState", localPlayer, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + end +end, false) + +bindKey("sprint", "down", function() + local tick = getTickCount() + if tick-cooldown<500 then return end + cooldown = tick + local ped = localPlayer + local data = climbers[ped] + if isControlEnabled("sprint") and data then + if data.dir then return end + local surface = climbs[data.surface] + local l = surface[data.climb] + if l.inside~=true then return end + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + local dx, dy, dz = tx-sx, ty-sy, tz-sz + local p = data.position + do -- check clear + local x, y, z = sx+dx*p, sy+dy*p, sz+dz*p + local m = Matrix(Vector3(x, y, z), Vector3(rx, ry, rz)) + m.position = m.position+m.forward*1.2+m.up*0.0 + local sx, sy, sz = m.position.x, m.position.y, m.position.z + m.position = m.position+m.up*2 + local tx, ty, tz = m.position.x, m.position.y, m.position.z + local clear = isLineOfSightClear(sx, sy, sz, tx, ty, tz, true, true, false, true, true, true, false) + local color = clear and tocolor(0, 200, 0, 100) or tocolor(255, 0, 0, 100) + --dxDrawLine3D(sx, sy, sz, tx, ty, tz, color) + if not clear then return end + end + local state = anim[data.state] + if state and not state.anim_hold then return end + local p = math.abs(data.prog-state.anim_hold) + if p>200 then return end + data.dir = 1 + data.next = "kick" + triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, data.position, data.state, data.prog, data.dir, data.dir_next, data.final_angle) + return + end +end) + +function getValueAtTime(time, info) + local time_s, time_e, value_s, value_e = 0, 0, 0, 0 + local data = info[1] + if data then + if data[3] and time>=data[2] then + time_s, time_e, value_s, value_e = data[2], data[3], data[1], data[1] + else + time_s, time_e, value_s, value_e = 0, data[2], 0, data[1] + end + end + for i=2, #info do + data = info[i] + if time0 and value_e or value_s end + local p = (time-time_s)/(time_e-time_s) + p = p>1 and 1 or p + return value_s+(value_e-value_s)*p +end + +local progz = 0 +function processLadders(tick) + if testing then + local ped = localPlayer + local state = anim[testing] + if state then + local dir = 0+getPedAnalogControlState(ped, "forwards")+-getPedAnalogControlState(ped, "backwards") + progz = progz+dir + if progz>state.anim_duration then progz = state.anim_duration end + if progz<0 then progz = 0 end + local prog = progz/state.anim_duration + if not (setPedAnimationSpeed(ped, state.anim, 0) and setPedAnimationProgress(ped, state.anim, prog)) then + setPedAnimation(ped, state.block, state.anim, -1, false, false, false, false, 0, false) + setPedAnimationSpeed(ped, state.anim, 0) + setPedAnimationProgress(ped, state.anim, prog) + end + setPedRotation(ped, 0) + local px, py, pz = getElementPosition(ped) + local tx, ty, tz = getElementBonePosition(ped, 0) + local value = math.floor((tz-pz)*1000)/1000 + local value = math.floor((tx-px)*1000)/1000 + local value = math.floor((ty-py)*1000)/1000 + iprint("V:", progz, value) + return + end + for surface, surfaceData in pairs(climbs) do + for climb, l in pairs(surfaceData) do + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(surface, ladder, l) + dxDrawLine3D(sx, sy, sz, tx, ty, tz, tocolor(0, 200, 200, 100)) + end + end + end + local prog = tick*getGameSpeed() + if prog>50 then prog = 50 end + for ped, data in pairs(climbers) do + if data then + local isSyncer = ped==localPlayer or isElementSyncer(ped) + local first = isSyncer and not data.isSyncer + data.isSyncer = isSyncer + local prog = prog + local surface = climbs[data.surface] + local l = surface[data.climb] + local p = data.position + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + local dx, dy, dz = tx-sx, ty-sy, tz-sz + local dist_down, dist_up + do + data.position = p + local x, y, z = sx+dx*p, sy+dy*p, sz+dz*p + --dxDrawLine3D(x, y, z, sx, sy, sz, tocolor(255, 0, 0, 200), 1.2) + local hit, hx, hy, hz = processLineOfSight(x, y, z, sx-dx, sy-dy, sz-dz, true, true, false, true, true, true, false, true, isElement(data.surface) and data.surface or false) + dist_down = l.dynamic and hx and (getDistanceBetweenPoints3D(x, y, z, hx, hy, hz)-1.05) or getDistanceBetweenPoints3D(x, y, z, sx, sy, sz) + local hit, hx, hy, hz = processLineOfSight(x, y, z, tx, ty, tz, true, true, false, true, true, true, false, true, isElement(data.surface) and data.surface or false) + dist_up = l.dynamic and hx and getDistanceBetweenPoints3D(x, y, z, hx, hy, hz) or getDistanceBetweenPoints3D(x, y, z, tx, ty, tz) + end + local size = ((dx)^2+(dy)^2+(dz)^2)^.5 + local state = anim[data.state] + local move = 0 + local skip + if data.x==nil and isElement(data.surface) then setElementCollidableWith(ped, data.surface, false) end + if data.isSyncer or data.isLocal then + local px, py, pz = getElementPosition(ped) + if l.enabled==false or isPedDead(ped) or getElementHealth(ped)==0 or (data.x and getDistanceBetweenPoints3D(data.x, data.y, data.z, getElementPosition(ped))>2) then + remover[#remover+1] = ped + prog = 0 + skip = true + end + end + if not state then print(data.state) end + prog = prog*state.speed + while prog~=0 do + local move_s = getValueAtTime(data.prog, state.climb_move) + local dir = state.dir or data.dir or (state.anim_hold and data.prog>state.anim_hold and -1) or 1 + if data.dir or not state.anim_hold then + data.prog, prog = data.prog+prog*dir, 0 + if dir<0 and data.prog<=state.anim_start then + data.prog, prog, data.next = state.anim_start, state.anim_start-data.prog, data.next or state.climb_down + elseif dir>0 and data.prog>=state.anim_end then + data.prog, prog, data.next = state.anim_end, data.prog-state.anim_end, data.next or state.climb_up + else + data.next = data.next or (dir>0 and state.climb_up) or (dir<0 and state.climb_down) + end + elseif state.anim_hold then + local p = math.abs(data.prog-state.anim_hold) + if p<=prog then + if data.prog~=state.anim_hold then triggerEvent("onClientPedLadderClimbingStep", ped, data.state) end + data.prog, prog = state.anim_hold, prog-p + else + data.prog, prog = data.prog+prog*dir, 0 + end + if (isSyncer or data.isLocal) and data.dir==nil and data.dir_next==nil and p<100 then + local dir = state.dir or (0+getPedAnalogControlState(ped, "forwards")+-getPedAnalogControlState(ped, "backwards")) + if dir==0 then + prog = 0 + else + if data.isLocal then data.dir_next = dir<0 and -1 or 1 else prog = 0 end + if isSyncer then triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.dir_next) end + end + else + prog = 0 + end + end + local move_e = getValueAtTime(data.prog, state.climb_move) + move, move_s = move+(move_e-move_s), move_e + if state.anim_hold and data.prog==state.anim_hold then + if data.dir_next then + data.dir, data.dir_next = data.dir_next, nil + local d = (p*size) + if data.dir>0 then + if size-d<(state.up_turn or 3) then + data.next = state.climb_up + local anim = anim[data.next] + if anim.edge_dist then + p, move = (size-anim.edge_dist-(getValueAtTime(state.anim_end, state.climb_move)-move_s))/size, 0 + end + else + data.next = state.climb_next or false + end + elseif data.dir<0 then + if dist_down<(state.down_turn or 0.91) then + if l.water then + data.next = "fall2" + else + data.next = state.climb_down or false + local anim = anim[data.next] + if anim.edge_dist then + p, move = p+(anim.edge_dist-dist_down)/size, 0 + end + end + else + data.next = state.climb_next or false + end + end + end + end + p = p+move/size + + if (dir>0 and data.prog==state.anim_end) or (dir<0 and data.prog==state.anim_start) then + local anim = anim[data.next or state.climb_next] + if anim then + prog = prog*(anim.speed/state.speed) + data.state = data.next + state = anim + data.next = nil + data.prog = dir<0 and state.anim_end or state.anim_start + if state.anim_hold then data.dir = nil end + if isSyncer then triggerServerEvent("onPlayerReportLadderClimbingState", ped, data.surface, data.climb, p, data.state, data.prog, data.dir, data.dir_next, data.final_angle) end + else + remover[#remover+1] = ped + --if isSyncer then triggerServerEvent("onPlayerReportLadderClimbingState", ped, false) end + break + end + end + + local fade = ((dir>0 and state.anim_end-data.prog) or (dir<0 and data.prog-state.anim_start) or 0)/state.speed + if fade>0 and fade<=(state.anim_fade or 0) then + local anim = anim[data.next or state.climb_next] + local f = anim and (dir>0 and anim.anim_start or anim.anim_end) + if f and anim.reverse then f = anim.anim_duration-f end + if anim and not (setPedAnimationSpeed(ped, anim.anim, 0) and setPedAnimationProgress(ped, anim.anim, anim.anim_frame or (f/anim.anim_duration))) then + setPedAnimation(ped, anim.block, anim.anim, -1, false, true, false, false, fade, false) + setPedAnimationSpeed(ped, anim.anim, 0) + setPedAnimationProgress(ped, anim.anim, anim.anim_frame or (f/anim.anim_duration)) + end + end + end + + local stream = isElementStreamedIn(ped) + local rot = 0 + if stream then + local a = state.straight and 0 or math.deg(math.atan2((dx^2+dy^2)^.5, dz)) + setElementBoneRotation(ped, 0, 0, 90, a+(state.climb_roll and getValueAtTime(data.prog, state.climb_roll) or 0)) + updateElementRpHAnim(ped) + if state.climb_angle then + if data.final_angle then + local angle = {} + for i=1, #state.climb_angle do + angle[i] = state.climb_angle[i] + end + local a = angle[state.reverse and 1 or #angle] + angle[state.reverse and 1 or #angle] = {data.final_angle, a[2], a[3]} + rot = getValueAtTime(data.prog, angle) or rot + else + rot = getValueAtTime(data.prog, state.climb_angle) or rot + end + end + end + + --if move<0 then print(math.floor(size*p*10), state.anim, math.floor(move*100)/100) end + local steps = math.floor(size/.73) + local step = (p*steps) + if step>steps-2 then + if step>steps then step = steps end + step = 5+1-(steps-step)/2 + elseif step>1 then + step=2+(step-1)%2 + elseif step<1 then + step=step+1 + end + stepProg = step%1 + step = math.floor(step) + --local p = p>1 and 1 or p<0 and 0 or p + data.position = p + local x, y, z = sx+dx*p, sy+dy*p, sz+dz*p + if state.climb_adjust then + local r = math.rad(rz) + local d = getValueAtTime(data.prog, state.climb_adjust) + x, y, z = x-math.sin(r)*d, y+math.cos(r)*d, z + else + data.upper = nil + end + do -- anim + local prog = state.anim_frame or (data.prog/state.anim_duration) + if state.reverse then prog = 1-prog end + if not (setPedAnimationSpeed(ped, state.anim, 0) and setPedAnimationProgress(ped, state.anim, prog)) then + setPedAnimation(ped, state.block, state.anim, -1, false, true, false, false, 0, false) + setPedAnimationSpeed(ped, state.anim, 0) + setPedAnimationProgress(ped, state.anim, prog) + end + end + if stream then + local px, py, pz = getElementPosition(ped) + local tx, ty, tz = getElementBoneMatrix(ped, 0) + tx, ty, tz = tx[4][1], tx[4][2], tx[4][3] + x, y, z = x-(tx-px), y-(ty-py), z-(tz-pz) + end + if skip then + data.x, data.y, data.z = nil + elseif state.velocity then + if l.shift_exit and not (state and state.shift_exit==false) and data.shifted==nil then + local r = math.rad(rz) + local d = l.shift_exit + x, y, z = x-math.sin(r)*d, y+math.cos(r)*d, z + setElementPosition(ped, x, y, z, false) + data.shifted = true + elseif not (l.shift_exit or data.shifted) then + data.shifted = true + if isElement(data.surface) then setElementCollidableWith(ped, data.surface, true) end + end + local v = state.velocity + setElementRotation(ped, 0, 0, 360-(rz+rot), "ZXY") + setPedRotation(ped, (rz+rot), true) + local x, y, z = getElementVelocity(ped) + local r = math.rad(rz+(data.final_angle or rot)) + local d = -0.08 + local d = move*1 + local ox, oy, oz = v.x, v.y, v.z + local x, y, z = x-math.sin(r)*d*ox, y+math.cos(r)*d*oy, z+d*oz + setElementVelocity(ped, x, y, z) + data.x, data.y, data.z = nil + else + setElementPosition(ped, x, y, z, false) + data.x, data.y, data.z = getElementPosition(ped) + setElementVelocity(ped, 0, 0, 0) + setElementRotation(ped, 0, 0, 360-(rz+rot), "ZXY") + setPedRotation(ped, (rz+rot), true) + end + + --print("JJJJ", move, p, step, stepProg) + end + end + for i=1, #remover do + removeClimber(remover[i]) + remover[i] = nil + end +end + +function removeClimber(ped) + local data = climbers[ped] + if data then + local surface = climbs[data.surface] + local l = surface[data.climb] + local p = data.position + local state = anim[data.state] + local sx, sy, sz, tx, ty, tz, rx, ry, rz, d = getLadderPositionFromData(data.surface, data.climb, l) + if l.shift_exit and not (state and state.shift_exit==false) and data.shifted==nil then + local r = math.rad(rz) + local d = l.shift_exit + local x, y, z = getElementPosition(ped) + x, y, z = x-math.sin(r)*d, y+math.cos(r)*d, z + setElementPosition(ped, x, y, z, false) + end + climbers[ped] = nil + if isElement(data.surface) then setElementCollidableWith(ped, data.surface, true) end + local block, anim, time, loop, updatePosition, interuptable, fLF, blendTime = "BSKTBALL", "BBall_idle2_O", 0, false, false, false, true, 200 + setPedAnimation(ped, block, anim, time, loop, updatePosition, interuptable, fLF, blendTime, false) + --setElementVelocity(ped, 0, 0, 0) + if data.isSyncer then triggerServerEvent("onPlayerReportLadderClimbingState", ped, false) end + triggerEvent("onClientPedLadderClimbingStop", ped) + end +end + +addEventHandler("onClientResourceStop", resourceRoot, function() + local removes = {} + for ped in pairs(climbers) do + removes[#removes+1] = ped + end + for i=1, #removes do + removeClimber(removes[i]) + end +end) + +local ready +addEventHandler("onClientRecieveLadderClimbingReady", localPlayer, function(a, b) + if ready then print("What the actual F!!!???") return end + ready = true + climbs, climbers = a, b + if climbers[localPlayer] then climbers[localPlayer].isLocal = true end + addEventHandler("onClientPreRender", root, processLadders, false, "high") + addEventHandler("onClientRecievePedLadderClimbingState", root, function(info, forced) + local ped = source + if ped==localPlayer and not forced then return end + local data = climbers[ped] + + if info==1 or info==-1 then + if data then + data.dir_next = info + return + end + elseif info then + climbers[ped] = info + if ped==localPlayer then climbers[ped].isLocal = true end + if not data then + triggerEvent("onClientPedLadderClimbingStart", ped, info.state) + end + else + if data then + removeClimber(ped) + end + if info==false then climbers[ped] = false end + end + end) + addEventHandler("onClientRecieveLadderState", root, function(surface, climb, data) + if climb==nil then + local surfaceData = climbs[surface] + local l = surfaceData and surfaceData[climb] + if l then + for i, data in pairs(surfaceData) do + if data.enabled~=nil then l.enabled = data.enabled end + if data.water~=nil then l.water = data.water end + if data.jumping~=nil then l.jumping = data.jumping end + if data.inside~=nil then l.inside = data.inside end + if data.sliding~=nil then l.sliding = data.sliding end + if data.dynamic~=nil then l.dynamic = data.dynamic end + if data.shift_exit~=nil then l.shift_exit = data.shift_exit end + if data.d~=nil then l.d = data.d end + end + end + elseif climb==true then -- add/edit + climbs[surface] = data + elseif climb then -- change + surfaceData[climb] = data + end + end) + if testing then + for surface, surfaceData in pairs(climbs) do + for climb, l in pairs(surfaceData) do + local sx, sy, sz = l.sx, l.sy, l.sz + createBlip(sx, sy, sz, 0, 2, 255, 0, 0, 255, 0, 99999.0) + end + end + end + +end) + + + +addEventHandler("onClientPlayerQuit", root, function() + climbers[source] = nil +end) + +addEventHandler("onClientElementDestroy", root, function() + climbers[source] = nil +end) + +triggerServerEvent("onPlayerRequestLadderClimbingReady", localPlayer) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/[gameplay]/ladders/data.lua b/[gameplay]/ladders/data.lua new file mode 100644 index 000000000..bd5382d67 --- /dev/null +++ b/[gameplay]/ladders/data.lua @@ -0,0 +1,693 @@ +testing = false + + + +--[[ [Help] + -- Table Layouts -- + + ---- Table: climbs ---- + ["SurfaceID"/ladderElement] = { -- Note: If surfaceID is an element, all positions are relative + [ladderIndex] = { -- individual ladders of a surface + sx=0 , sy=0, sz=0, -- ladder start position + tx=0, ty=0, tz=0, -- ladder end position + rx=0, ry=0, rz=0, -- ladder rotation + d=1, -- distance from ladder it can be grabbed (not players grab point has a 0.3 offset) + shift_exit = 0, -- distance to warp player upon ladder exit (Y axis relative to ladder) (doesn't affect all exits) + water = false, -- will fall on ladder exit (change exit anim) + sliding = true, -- allows sliding down ladders by hold "crouch" key + inside = false, -- allows entering ladders' the "sprint" key (for ladders with platforms) (also allows entering from rear of ladder) + jumping = true, -- allows jumping off ladders with the "jump" key + dynamic = false, -- detects ground level to exit ladder + } + } + + + ---- Table: ladderModels ---- + Note: This table will automatically assign a ladder surface to all vehicles/objects created as the index models + [ModelNumber/ModelName] -- { -- Note: Model Name is untested and would likely only support vehicle names atm + [ladderIndex] = {ladderData} -- (See ladder data under "Table Layouts > climbs") + } + + + ---- Table: anims ---- + ["ladderAnim"] = { + block = "dozer", -- animation block + anim = "DOZER_Align_LHS", -- animation name + anim_start = 350, -- anim start position + anim_hold = 530, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 120, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 150, -- ms to blend into anim (for when starting to use a ladder) + climb_up = "exit_l", -- next anim for going up (often to exit) + climb_next = "climb_r", -- next animation to move along lader + climb_down = "enter_l", -- next anim for going down (often to exit) + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, -- used to move ped up/down ladder per time + climb_angle = {{-90, 0}, {0, 170}}, -- used to apply rotation per time + climb_adjust = {{0.0, 000, 300}, {0.243, 400}, {0.700, 800}}, -- used to move ped in/out per time (Y pos axis) + climb_roll = {{0, 300}, {-22, 500}}, -- used to apply "X" rot axis tilt per time + velocity = {x=0.0, y=0.0, z=0.0}, -- used to apply velocity to ped over time (replaces "climb_move" value with velocity) + straight = true, -- used to disable some ped rotation adjustment (mainly in case of "X" axis leaning) + }, +]] + +--[[ [Help] + + ---- Server Events ---- + "onLadderAdd" ++ root/surfaceElement (surface, ladder) -- when a new ladder is added (may be bypassed by onElementModelChange) + "onLadderRemove" ++ root/surfaceElement (surface[, ladder]) -- when a new ladder is removed (may be bypassed by onElementModelChange) + "onLadderClimbingStart" ++ root/surfaceElement (surface, ladder, ped, step) -- when a ladder is enterd by a ped + "onLadderClimbingStop" ++ root/surfaceElement (surface, ladder, ped) -- when a ladder is exited by a ped + "onPedLadderClimbingStart" ++ ped (surface, ladder, step) -- when a ped starts using a ladder + "onPedLadderClimbingStop" ++ ped (surface, ladder, position) -- when a ped stops using a ladder + "onPedLadderClimbingStep" ++ ped (surface, ladder) -- when a ped changes ladder step animation + NOTE: Ladders are built for player elements and peds may not work or give unexpected results + + ---- Server Functions ---- + setPedClimbingLadder(ped, surface, ladder, pos) - server + isPedClimbingLadder(ped) - shared + getPedsOnLadder(surface) - shared + setPedLadderClimbingEnabled(ped, enabled) - server + isPedLadderClimbingEnabled(ped) - shared + getLadderClosestToPosition(px, py, pz) - shared + getLadders(surface) - shared + setLadderEnabled(surface, ladder, active) - server + setLadderProperties(surface, ladder, properties) - server + getLadderProperties(surface, ladder) - shared + addLadder(surface, sx, sy, sz, tx, ty, tz, rx, ry, rz, d, jumping, inside, sliding, water, exitShift) - server + removeLadder(surface, ladder) - server + + ---- Client Events ---- + "onClientPedLadderClimbingStart" ++ ped (step) -- when a ped starts using a ladder + "onClientPedLadderClimbingStop" ++ ped () -- when a ped stops using a ladder + "onClientPedLadderClimbingStep" ++ ped (step) -- when a ped changes ladder step animation + + ---- Client Functions ---- + isPedClimbingLadder(ped) - shared + getPedsOnLadder(surface) - shared + isPedLadderClimbingEnabled(ped) - shared + getLadderClosestToPosition(px, py, pz) - shared + getLadders(surface) - shared + getLadderProperties(surface, ladder) - shared +]] + + +ladderProperties = {sx=0 , sy=0, sz=0, tx=0, ty=0, tz=0, rx=0, ry=0, rz=0, d=0, shift_exit=0, water=false, sliding=true, inside=false, jumping=true, dynamic=false} + +ladderModels = { + [590] = { + {sx=2.1 , sy=8.25, sz=-1.2, tx=2.1, ty=8.25, tz=3.2, rx=0, ry=0, rz=90, d=1, dynamic=true}, + {sx=-2.1 , sy=8.25, sz=-1.2, tx=-2.1, ty=8.25, tz=3.2, rx=0, ry=0, rz=-90, d=1, dynamic=true}, + {sx=2.1 , sy=-8.25, sz=-1.2, tx=2.1, ty=-8.25, tz=3.2, rx=0, ry=0, rz=90, d=1, dynamic=true}, + {sx=-2.1 , sy=-8.25, sz=-1.2, tx=-2.1, ty=-8.25, tz=3.2, rx=0, ry=0, rz=-90, d=1, dynamic=true}, + }, + [1428] = { + {sx=0 , sy=-0.7, sz=-0.55, tx=0, ty=0.2, tz=2.6, rx=0, ry=0, rz=0, d=1, dynamic=true}, + }, + [1437] = { -- BIG LADDER + {sx=0 , sy=-0.8, sz=-0.4, tx=0, ty=0.7, tz=5.9, rx=0, ry=0, rz=0, d=1, dynamic=true}, + }, +} + +climbs = { -- ladder ID (or vehicle/object element ) + ["airport_sf"] = { + {sx=-1736.60, sy=-445.96, sz=1.96, tx=-1736.60, ty=-445.96, tz=14.10, rx=0, ry=0, rz=-90, d=1}, + {sx=-1618.83, sy=-83.9, sz=1.96, tx=-1618.74, ty=-84.0, tz=14.10, rx=0, ry=0, rz=-135, d=1}, + {sx=-1444.528 , sy=90.304, sz=1.96, tx=-1444.528, ty=90.304, tz=14.10, rx=0, ry=0, rz=225, d=1}, + {sx=-1164.727 , sy=370.074, sz=1.96, tx=-1164.727, ty=370.074, tz=14.10, rx=0, ry=0, rz=225, d=1}, + {sx=-1115.7 , sy=335.3, sz=1.96, tx=-1115.7, ty=335.3, tz=14.10, rx=0, ry=0, rz=45, d=1}, + {sx=-1182.519 , sy=60.546, sz=1.96, tx=-1182.519, ty=60.546, tz=14.10, rx=0, ry=0, rz=135, d=1}, + {sx=-1081.827 , sy=-207.873, sz=1.96, tx=-1081.827, ty=-207.873, tz=14.10, rx=0, ry=0, rz=110, d=1}, + {sx=-1154.118 , sy=-476.786, sz=1.96, tx=-1154.118, ty=-476.786, tz=14.10, rx=0, ry=0, rz=60, d=1}, + {sx=-1361.046 , sy=-696.801, sz=1.96, tx=-1361.046, ty=-696.801, tz=14.10, rx=0, ry=0, rz=0, d=1}, + {sx=-1603.401 , sy=-696.76, sz=1.96, tx=-1603.401, ty=-696.76, tz=14.10, rx=0, ry=0, rz=0, d=1}, + }, + ["cargo_ship"] = {--ships + {sx=-2328.9, sy=1528.65, sz=-0.6, tx=-2328.9, ty=1528.65, tz=18.6, rx=0, ry=0, rz=12, d=1, water=true} + }, + ["factory_sf"] = {--Factory 1 + {sx=-1055.58, sy=-719.10, sz=32.00, tx=-1055.58, ty=-719.10, tz=55.50, rx=0, ry=0, rz=180, d=1, water=nil}, + {sx=-1013.51, sy=-719.10, sz=32.00, tx=-1013.51, ty=-719.10, tz=55.50, rx=0, ry=0, rz=180, d=1, water=nil}, + {sx=-1099.84, sy=-719.10, sz=32.00, tx=-1099.84, ty=-719.10, tz=55.50, rx=0, ry=0, rz=180, d=1, water=nil}, + {sx=-1073.27, sy=-645.60, sz=32.00, tx=-1073.27, ty=-645.60, tz=56.20, rx=0, ry=0, rz=180, d=1, water=nil}, + {sx=-1111.00, sy=-645.60, sz=32.00, tx=-1111.00, ty=-645.60, tz=56.20, rx=0, ry=0, rz=180, d=1, water=nil}, + {sx=-1060.10, sy=-617.627, sz=34.09, tx=-1060.10, ty=-617.627, tz=129.862, rx=0, ry=0, rz=270, d=1.1, inside=true}, + {sx=-1056.11 , sy=-627.688, sz=32.007, tx=-1056.11, ty=-627.688, tz=129.862, rx=0, ry=0, rz=180, d=1.1, inside=true}, + {sx=-1026.794 , sy=-700.45, sz=64.532, tx=-1026.794, ty=-700.45, tz=129.664, rx=0, ry=0, rz=180, d=1.1, inside=true}, + {sx=-1019.00 , sy=-703.90, sz=54.45, tx=-1019.00, ty=-703.90, tz=130.468, rx=0, ry=0, rz=270.00, d=1.1, inside=true}, + {sx=-1063.20, sy=-640.44, sz=34.09, tx=-1063.20, ty=-640.44, tz=44.20, rx=0, ry=0, rz=0, d=1.1}, + {sx=-1097.464 , sy=-640.731, sz=34.089, tx=-1097.464, ty=-640.731, tz=44.20, rx=0, ry=0, rz=0, d=1.1}, + {sx=-1062.69, sy=-671.95, sz=32.50, tx=-1062.69, ty=-671.95, tz=56.33, rx=0, ry=0, rz=180, d=1.5, shift_exit=-1.5, jumping=false}, + {sx=-1008.30 , sy=-704.145, sz=32.00, tx=-1008.30, ty=-704.145, tz=94.60, rx=0, ry=0, rz=270, d=1.1, shift_exit=-1.0, water=nil, sliding=nil, inside=true, jumping=false, dynamic=false}, -- shit col + {sx=-1059.062 , sy=-603.542, sz=34.09, tx=-1059.062, ty=-603.542, tz=92.92, rx=0, ry=0, rz=270, d=10, shift_exit=-1, water=nil, sliding=nil, inside=true, jumping=false, dynamic=false}, -- shit col + }, + ["factory_lv"] = {--Factory 2 + {sx=2688.041 , sy=2637.703, sz=10.82, tx=2688.041, ty=2637.703, tz=34.82, rx=0, ry=0, rz=0, d=1}, + {sx=2657.46 , sy=2643.843, sz=10.82, tx=2657.46, ty=2643.843, tz=34.5, rx=0, ry=0, rz=0, d=1}, + {sx=2613.297 , sy=2643.682, sz=10.82, tx=2613.297, ty=2643.682, tz=34.5, rx=0, ry=0, rz=0, d=1}, + {sx=2571.2 , sy=2643.759, sz=10.82, tx=2571.2, ty=2643.759, tz=34.5, rx=0, ry=0, rz=0, d=1}, + {sx=2588.6 , sy=2638.341, sz=10.82, tx=2588.6, ty=2638.341, tz=109.15, rx=0, ry=0, rz=270, d=1.2, inside=true}, + {sx=2632.54 , sy=2836.948, sz=24.124, tx=2632.54, ty=2836.948, tz=122.84, rx=0, ry=0, rz=180, d=1.2, water=true, inside=true}, + {sx=2501.651 , sy=2690.546, sz=10.812, tx=2501.651, ty=2690.546, tz=74.812, rx=0, ry=0, rz=270, d=1.2, inside=true}, + {sx=2713.684 , sy=2773.602, sz=10.82, tx=2713.684, ty=2773.602, tz=74.82, rx=0, ry=0, rz=270, d=1.2, inside=true}, + {sx=2562.597 , sy=2723.70, sz=12.824, tx=2562.597, ty=2723.70, tz=22.94, rx=0, ry=0, rz=180, d=1}, + {sx=2703.173 , sy=2676.83, sz=12.822, tx=2703.173, ty=2676.83, tz=22.92, rx=0, ry=0, rz=0, d=1}, + }, + ["area_51"] = testing and {--test ladder + {sx=268.8 , sy=1884.75, sz=-30.1, tx=268.8, ty=1884.75, tz=22.0, rx=0, ry=0, rz=0, d=1, water=nil, sliding=nil, inside=true, jumping=false, enabled=true, shift_exit=0}, + } or nil, +} + +anims = { + enter_r = { + block = "dozer", + anim = "DOZER_Align_LHS", + anim_start = 00, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 350, -- anim end position + anim_fade = 50, -- ms to blend into next anim + speed = 0.8, -- task speed multiplier + anim_duration = 970, -- ms lenght of anim + blend = 100, -- ms to blend into anim + edge_dist = 0.42, -- gta units from edge, anim starts + climb_up = "climb_r", + climb_down = nil, + climb_move = {{0, 0, 300}, {0.2, 430, 530}}, + climb_angle = {{90, 0}, {0, 170}}, -- ped rot alignment angle + straight = true, + }, + enter_l = { + block = "dozer", + anim = "DOZER_Align_RHS", + anim_start = 00, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 350, -- anim end position + anim_fade = 50, -- ms to blend into next anim + speed = 0.8, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + edge_dist = 0.42, -- gta units from edge, anim starts + climb_up = "climb_l", + climb_down = nil, + climb_move = {{0, 0, 300}, {0.2, 430, 530}}, + climb_angle = {{-90, 0}, {0, 170}}, + straight = true, + }, + climb_l = { + block = "dozer", + anim = "DOZER_Align_RHS", + anim_start = 350, -- anim start position + anim_hold = 530, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 120, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 150, -- ms to blend into anim + climb_up = "exit_l", + climb_next = "climb_r", + climb_down = "enter_l", + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, -- l + }, + climb_r = { + block = "dozer", + anim = "DOZER_Align_LHS", + anim_start = 350, -- anim start position + anim_hold = 530, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 120, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 970, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 150, -- ms to blend into anim + climb_up = "exit_r", + climb_next = "climb_l", + climb_down = "enter_r", + climb_move = {{0.011, 0, 250}, {0.037, 300}, {0.42, 430}, {0.496, 530}, {1.082, 720}}, -- r + }, + exit_l = { -- start exit blend at hold + block = "ped", + anim = "CLIMB_Pull", + anim_start = 220, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 870, -- anim end position + anim_fade = 50, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 870, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + edge_dist = 1.7, + climb_up = "exit", + climb_down = "climb_l", + climb_move = {{-0.015, 000}, {0.300, 200}, {1.02, 700}, {1.075, 870}}, + --climb_adjust = {{0.0000199, 000}, {-0.0000161, 400, 435}, {0.0000223, 870}}, + }, + exit_r = { + block = "ped", + anim = "CLIMB_Pull", + anim_start = 350, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 870, -- anim end position + anim_fade = 50, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 870, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + edge_dist = 1.6, -- gta units from edge, anim starts + climb_up = "exit", + climb_down = "climb_r", + climb_move = {{-0.015, 000}, {0.300, 200}, {1.02, 700}, {1.075, 870}}, + --climb_adjust = {{0.0000199, 000}, {-0.0000161, 400, 435}, {0.000223, 870}}, + }, + exit = { + block = "ped", + anim = "CLIMB_Stand", + anim_start = 0, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 800, -- anim end position + anim_fade = 120, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 800, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + climb_up = "exit_f", + climb_down = "exit_r", + climb_move = {{0.004, 0}, {0.017, 100}, {0.97, 720}, {0.99, 760}, {0.973, 800}}, + climb_adjust = {{0.0, 000, 300}, {0.243, 400}, {0.700, 800}}, + straight = true, + }, + exit_f = { + block = "ped", + anim = "CLIMB_Stand_finish", + anim_start = 0, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 200, -- anim end position + anim_fade = 50, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 200, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 50, -- ms to blend into anim + climb_up = nil, + climb_down = "exit", + climb_move = {{0.1, 200}}, + climb_adjust = {{0.700, 000}, {1, 200}}, + shift_exit = false, + straight = true, + }, + fall = { + block = "BSKTBALL", + anim = "BBall_idle2_O", + anim_start = 00, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 160, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 300, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = nil, + climb_move = {{0.1, 300}}, + }, + fall2 = { + block = "ped", + anim = "FALL_glide", + anim_start = 00, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 160, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 300, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = nil, + climb_move = {{0.3, 300}}, + }, + align_r = { + block = "ped", + anim = "turn_180", + anim_start = 000, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 630, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 630, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_down = "exit_f", + climb_move = {{0, 000}}, + climb_adjust = {{1, 000, 630}}, + climb_angle = {{0, 0}, {180, 630}}, -- ped rot alignment angle + straight = true, + }, + align_l = { + block = "ped", + anim = "turn_180", + anim_start = 000, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 630, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + reverse = true, -- task speed multiplier + anim_duration = 630, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_down = "exit_f", + climb_move = {{0, 000}}, + climb_adjust = {{1, 000, 630}}, + climb_angle = {{0, 0}, {-180, 630}}, -- ped rot alignment angle + straight = true, + }, + leap = { + block = "QUAD", + anim = "QUAD_getoff_B", + anim_start = 800, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 1200, -- anim end position + anim_fade = 150, -- ms to blend into next anim + speed = 0.8, -- task speed multiplier + reverse = true, -- task speed multiplier + anim_duration = 1630, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_down = "leap_fall", + climb_next = nil, + climb_move = {{0, 1100}, {-0.2, 1200}}, + climb_adjust = {{-0.3, 900}, {0, 1200}}, + climb_angle = {{180, 0, 900}, {90, 1110}, {0, 1200}}, -- ped rot alignment angle + velocity = {x=0.6, y=0.6, z=1}, + }, + leap_fall = { + block = "ped", + anim = "JUMP_glide", + anim_start = 400, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 400, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 500, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = nil, + climb_move = {{1.5, 0, 400}, {2, 500}}, + climb_adjust = {{-0.3, 0, 400}, {-0.4, 500}}, + climb_angle = {{180, 0, 500}}, -- ped rot alignment angle + velocity = {x=0.5, y=0.5, z=1}, + }, + kick = { + block = "dozer", + anim = "DOZER_Align_RHS", -- DOZER_pullout_LHS -- + anim_start = 720, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 930, -- anim end position + anim_fade = 150, -- ms to blend into next anim + speed = 0.9, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = "kick2", + climb_next = nil, + climb_down = nil, + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, + }, + kick2 = { + block = "BIKELEAP", + anim = "truck_getin", + anim_start = 1800, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 2350, -- anim end position + anim_fade = 150, -- ms to blend into next anim + speed = 0.7, -- task speed multiplier + anim_duration = 2500, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + climb_up = "kick3", + climb_next = nil, + climb_down = "kick", + climb_move = {{0, 1800}, {0.65, 2050, 2080}, {0.0, 2200}}, + climb_adjust = {{0, 1800}, {-0.08, 2000, 2080}, {0.5, 2200}, {1.3, 2350}}, + }, + kick3 = { + block = "ped", + anim = "JUMP_glide", + anim_start = 400, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 500, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 500, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = nil, + velocity = {x=1, y=1, z=0.6}, + climb_move = {{0, 400}, {0.08, 500}}, + climb_adjust = {{1.3, 400}, {1.5, 500}}, + shift_exit = false, + }, + switch = { + block = "dozer", + anim = "DOZER_Align_RHS", -- DOZER_pullout_LHS -- + anim_start = 730, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 930, -- anim end position + anim_fade = 150, -- ms to blend into next anim + speed = 0.9, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = "switch2", + climb_next = nil, + climb_down = nil, + climb_angle = {{180, 0, 1000}}, + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, + climb_adjust = {{1.3, 0, 930}}, + }, + switch2 = { + block = "BIKELEAP", + anim = "truck_getin", + anim_start = 1800, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 2350, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 0.7, -- task speed multiplier + anim_duration = 2500, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + climb_up = "switch3", + climb_next = nil, + climb_down = nil, + climb_angle = {{180, 0, 2180}, {250, 2350}}, + climb_move = {{0, 1800}, {0.65, 2050, 2080}, {-0.0, 2350}}, + climb_adjust = {{1.3, 1800}, {1.38, 2000, 2080}, {0.80, 2200}, {0.2, 2350}}, + --climb_adjust = {{0, 1800}, {-0.08, 2000, 2080}, {0.5, 2200}, {1.5, 2350}}, + }, + switch3 = { + block = "ped", + anim = "CLIMB_jump", + anim_start = 200, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 570, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 0.9, -- task speed multiplier + anim_duration = 570, -- ms lenght of anim + blend = 100, -- ms to blend into anim + climb_up = "climb_l", + climb_down = nil, + climb_next = nil, + climb_move = {{0, 200}, {-0.5, 400, 490}, {-0.0, 570}}, + climb_adjust = {{0.2, 200}, {0, 450}}, + climb_angle = {{240, 0, 200}, {360, 400}}, -- ped rot alignment angle + }, + + slide_l = { + block = "dozer", + anim = "DOZER_Align_RHS", + anim_start = 350, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 200, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 930, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = "slide", + climb_move = {{0, 250}, {0.04, 300}, {0.424, 430}, {0.494, 530}, {1.093, 720}}, -- l + climb_roll = {{-22, 350}, {0, 530}}, + climb_adjust = {{0.1, 350}, {0, 530}}, + }, + slide_r = { + block = "dozer", + anim = "DOZER_Align_LHS", + anim_start = 350, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 720, -- anim end position + anim_fade = 200, -- ms to blend into next anim + speed = 1, -- task speed multiplier + anim_duration = 970, -- ms lenght of anim + align = 130, -- max ms to align to ladder + blend = 100, -- ms to blend into anim + climb_up = nil, + climb_next = nil, + climb_down = "slide", + climb_move = {{0.011, 0, 250}, {0.037, 300}, {0.42, 430}, {0.496, 530}, {1.082, 720}}, -- r + climb_roll = {{-22, 350}, {0, 530}}, + climb_adjust = {{0.1, 350}, {0, 530}}, + }, + slide = { + block = "truck", + anim = "TRUCK_ALIGN_LHS", + dir = -1, + down_turn = 1.8, + anim_start = 0, -- anim start position + anim_hold = 200, -- anim wait for player input position + anim_end = 400, -- anim end position + anim_fade = 300, -- ms to blend into next anim + anim_frame = 400/570, + speed = 2, -- task speed multiplier + anim_duration = 400, -- ms lenght of anim + blend = 150, -- ms to blend into anim + climb_up = nil, + climb_down = "slide_ext", + climb_next = "slide", + climb_move = {{0, 0}, {1.6, 400}}, + climb_angle = {{-0, 0, 400}}, -- ped rot alignment angle + climb_roll = {{-22, 0, 400}}, + climb_adjust = {{0.1, 0, 400}}, + }, + slide_ext = { + block = "ped", + anim = "FALL_land", + anim_start = 300, -- anim start position + anim_hold = nil, -- anim wait for player input position + anim_end = 500, -- anim end position + anim_fade = 100, -- ms to blend into next anim + speed = 1.6, -- task speed multiplier + anim_duration = 500, -- ms lenght of anim + blend = 100, -- ms to blend into anim + edge_dist = 0.42, -- gta units from edge, anim starts + climb_up = nil, + climb_down = nil, + climb_move = {{0.3, 500}}, + climb_roll = {{0, 300}, {-22, 500}}, + climb_adjust = {{0.1, 0}, {0.1, 500}}, + velocity = {x=0.0, y=0.0, z=0.0}, + }, +} + +do -- Function Libary Extract + function table.load(table1, table2, overWrite) + local table1 = table1 + if overWrite ~= true then + table1 = table.load({}, table1, true) + end + for cellName, cell in pairs(table2) do + if type(cell) == "table" then + if type(table1[cellName]) ~= 'table' then table1[cellName] = {} end + table1[cellName] = table.load(table1[cellName], cell, true) + else + table1[cellName] = cell + end + end + return table1 + end + _G["table.load"] = table.load + do -- Matrix functions + function createMatrix(x, y, z, rx, ry, rz) + if x and type(x)~="number" and isElement(x) then + rx, ry, rz = getElementRotation(x, "ZXY") + x, y, z = getElementPosition(x) + end + rx, ry, rz = math.rad(rx or 0), math.rad(ry or 0), math.rad(rz or 0) + local matrix = {} + matrix[1] = {} + matrix[1][1] = math.cos(rz)*math.cos(ry) - math.sin(rz)*math.sin(rx)*math.sin(ry) + matrix[1][2] = math.cos(ry)*math.sin(rz) + math.cos(rz)*math.sin(rx)*math.sin(ry) + matrix[1][3] = -math.cos(rx)*math.sin(ry) + matrix[1][4] = 1 + + matrix[2] = {} + matrix[2][1] = -math.cos(rx)*math.sin(rz) + matrix[2][2] = math.cos(rz)*math.cos(rx) + matrix[2][3] = math.sin(rx) + matrix[2][4] = 1 + + matrix[3] = {} + matrix[3][1] = math.cos(rz)*math.sin(ry) + math.cos(ry)*math.sin(rz)*math.sin(rx) + matrix[3][2] = math.sin(rz)*math.sin(ry) - math.cos(rz)*math.cos(ry)*math.sin(rx) + matrix[3][3] = math.cos(rx)*math.cos(ry) + matrix[3][4] = 1 + + matrix[4] = {} + matrix[4][1], matrix[4][2], matrix[4][3] = x or 0, y or 0, z or 0 + matrix[4][4] = 1 + + return matrix + end + + function getRotationFromMatrix(fm) + local fx, fy, fz = 0, 0, 0 + + fx = math.asin(fm[2][3]) + fy = math.cos(fx) + if fy~=0 then + fy = fm[3][3]/fy + fy = fy>1 and 1 or fy<-1 and -1 or fy + fy = -math.acos(fy) + if fm[1][3]<0 then fy = -fy end + end + if fm[2][1]==0 and fm[2][2]==0 then + fz = -math.atan2(fm[3][1], fm[3][2]) + else + fz = -math.atan2(fm[2][1], fm[2][2]) + end + + local fx, fy, fz = math.deg(fx), math.deg(fy), math.deg(fz) + --dxDrawText(inspect({nx=nx, ny=ny, yRot=getDifferenceBetweenRotations(fy, y)}), 300, 20) + --local text = tostring((fx)).."\n"..tostring(fy).."\n"..tostring((fz)) + --dxDrawText(text, 500, 300) + return fx, fy, fz + end + + function getPositionFromMatrix(fm) + return fm[4][1], fm[4][2], fm[4][3] + end + + function getPositionFromMatrixOffset(matrix, offX, offY, offZ) + local m = matrix -- Get the matrix + local x = offX*m[1][1] + offY*m[2][1] + offZ*m[3][1] + m[4][1] + local y = offX*m[1][2] + offY*m[2][2] + offZ*m[3][2] + m[4][2] + local z = offX*m[1][3] + offY*m[2][3] + offZ*m[3][3] + m[4][3] + return x, y, z + end + + function getMatrixFromOffset(m, x, y, z, rx, ry, rz) + local o = createMatrix(0, 0, 0, rx, ry, rz) + local ox = {getPositionFromMatrixOffset(o, 1, 0, 0)} + local oy = {getPositionFromMatrixOffset(o, 0, 1, 0)} + local oz = {getPositionFromMatrixOffset(o, 0, 0, 1)} + local x, y, z = getPositionFromMatrixOffset(m, x, y, z) + local xx = ox[1]*m[1][1] + ox[2]*m[2][1] + ox[3]*m[3][1] + local xy = ox[1]*m[1][2] + ox[2]*m[2][2] + ox[3]*m[3][2] + local xz = ox[1]*m[1][3] + ox[2]*m[2][3] + ox[3]*m[3][3] + local yx = oy[1]*m[1][1] + oy[2]*m[2][1] + oy[3]*m[3][1] + local yy = oy[1]*m[1][2] + oy[2]*m[2][2] + oy[3]*m[3][2] + local yz = oy[1]*m[1][3] + oy[2]*m[2][3] + oy[3]*m[3][3] + local zx = oz[1]*m[1][1] + oz[2]*m[2][1] + oz[3]*m[3][1] + local zy = oz[1]*m[1][2] + oz[2]*m[2][2] + oz[3]*m[3][2] + local zz = oz[1]*m[1][3] + oz[2]*m[2][3] + oz[3]*m[3][3] + local fm = { + {xx, xy, xz, 1}, + {yx, yy, yz, 1}, + {zx, zy, zz, 1}, + {x, y, z, 1}, + } + return fm + end + end +end \ No newline at end of file diff --git a/[gameplay]/ladders/meta.xml b/[gameplay]/ladders/meta.xml new file mode 100644 index 000000000..d18584dad --- /dev/null +++ b/[gameplay]/ladders/meta.xml @@ -0,0 +1,21 @@ + + + + +