local U = require "scriptbank\\utillib" local rad = math.rad local sin = math.sin local cos = math.cos local atan = math.atan2 local grappleHooks = {} local epressed = false local throw_speed = 10 local move_speed = 700 local hold_height = -5 local hold_dist = 50 local max_throw_dist = 5 --maximum time (in seconds) the hook will travel if it doesnt hit anything local max_charge_time = 1 --seconds til max throw length reached local show_timer = false local ghtimer = 0 local perc = 0 local n_max_time = 0 local angle_Y = 0 function grapplinghook_init_name( e, name ) Include( "utillib.lua" ) grappleHooks[ e ] = { name = name, state = "wait pick up" } max_charge_time = max_charge_time * 1000 max_throw_dist = max_throw_dist * 1000 end local function round( num, idp ) local mult = 10^( idp or 0 ) return math.floor( num * mult + 0.5 ) / mult end function RotatePlayerToEntity( e ) if g_Entity[e] ~= nil then local x = g_Entity[e]['x'] - g_PlayerPosX local z = g_Entity[e]['z'] - g_PlayerPosZ local angle = atan( x, z ) angle = angle * ( 180.0 / math.pi ) if angle < 0 then angle = 360 + angle elseif angle > 360 then angle = angle - 360 end SetFreezeAngle(g_PlayerAngX,angle,g_PlayerAngZ) SetFreezePosition(g_PlayerPosX,g_PlayerPosY,g_PlayerPosZ) TransportToFreezePosition() return angle end return 0 end function grapplinghook_main( e ) local gh = grappleHooks[ e ] local Ent = g_Entity[ e ] if gh == nil then return end -- Prompt( gh.state ) if gh.state == "wait pick up" then if U.PlayerLookingNear( e, 150, 20 ) then PromptLocal( e, "Collect the " .. gh.name .. "? (E)" ) if g_KeyPressE == 1 and not epressed then epressed = true gh.state = "picking" end end elseif gh.state == "picking" then if g_KeyPressE == 0 then epressed = false StartTimer( e ) gh.state = "holding" end elseif gh.state == "holding" then local ppx, ppy, ppz = g_PlayerPosX, g_PlayerPosY, g_PlayerPosZ local pax, pay, paz = rad( g_PlayerAngX ), rad( g_PlayerAngY ), rad( g_PlayerAngZ ) -- correct player y pos for crouching if GetGamePlayerStatePlayerDucking() == 0 then ppy = ppy + 31 + hold_height else ppy = ppy + 10 + hold_height end -- calculate carry position based on player angles local xo, yo, zo = U.Rotate3D( 0, 0, hold_dist, pax, pay, paz ) -- position entity wrt player CollisionOff( e ) SetRotation( e, g_PlayerAngX, g_PlayerAngY, g_PlayerAngZ ) SetPosition( e, ppx + xo, ppy + yo, ppz + zo ) CollisionOn( e ) angle_Y = pay if g_KeyPressE == 1 then ghtimer = GetTimer( e ) Panel( 40, 80, 64, 86 ) if ghtimer > max_charge_time then ghtimer = max_charge_time end perc = ( ( ghtimer / max_charge_time ) * 10 ) * 2 for a = 1, perc do Panel( 40 + a, 81, 41 + a, 82 ) end perc = ghtimer / max_charge_time n_max_time = max_throw_dist * perc perc = perc * 100 perc = round( perc, 0 ) TextCenterOnX( 50, 76, 3, perc .. " % " ) else if perc > 0 then perc = 0 gh.state = "firing" end -- store a vector describing the direction of the throw local vx, vy, vz = U.Rotate3D( 0, 0, 1, pax, pay, paz ) gh.vec = { vx = vx, vy = vy, vz = vz } ghtimer = 0 StartTimer( e ) end elseif gh.state == "firing" then local x, y, z = GetEntityPosAng( e ) local v = gh.vec local nx, ny, nz = x + v.vx * throw_speed, y + v.vy * throw_speed, z + v.vz * throw_speed local obstructionhit = IntersectAll( x, y, z, nx, ny, nz, Ent.obj ) if obstructionhit == nil then obstructionhit = 0 end if obstructionhit ~= 0 then --Prompt ("obstructed") gh.state = "hit" gh.hit = { x = x, y = y, z = z } else local thit = RayTerrain( x, y, z, nx, ny, nz ) if thit ~= 1 then else gh.state = "hit" --prompt ("obstructed") gh.hit = { x = x, y = x, z = z } end end if gh.state ~= "hit" then if GetTimer( e ) > n_max_time then gh.state = "return" else CollisionOff( e ) -- SetRotation( e, g_PlayerAngX, g_PlayerAngY, g_PlayerAngZ ) SetPosition( e, nx, ny, nz ) CollisionOn( e ) end end elseif gh.state == "hit" then StartTimer( e ) angle_Y = g_PlayerAngY local x1 = g_PlayerPosX local y1 = g_PlayerPosY + 10 local z1 = g_PlayerPosZ local y2 = y1 local x2 = x1 + ( sin( angle_Y ) * 80 ) local z2 = z1 + ( cos( angle_Y ) * 80 ) local obstructionhit = IntersectAll( x1, y1, z1, x2, y2, z2, 0 ) if obstructionhit == nil then obstructionhit = 0 end if obstructionhit ~= 0 then angle_Y = RotatePlayerToEntity( e ) angle_Y = rad( angle_Y ) local pos_X = g_PlayerPosX + ( sin( angle_Y ) * -move_speed / 10 ) local pos_Z = g_PlayerPosZ + ( cos( angle_Y ) * -move_speed / 10 ) SetFreezePosition( pos_X, g_PlayerPosY, pos_Z ) SetFreezeAngle( 0, g_PlayerAngY, 0 ) TransportToFreezePosition() gh.state = "return" return end if U.PlayerCloserThan( e, 200 ) then gh.state = "holding" return end angle_Y = RotatePlayerToEntity( e ) angle_Y = rad( angle_Y ) local pos_X = g_PlayerPosX + ( sin( angle_Y ) * move_speed / 10 ) local pos_Z = g_PlayerPosZ + ( cos( angle_Y ) * move_speed / 10 ) SetFreezePosition( pos_X, g_PlayerPosY, pos_Z ) SetFreezeAngle( 0, g_PlayerAngY, 0 ) TransportToFreezePosition() elseif gh.state == "return" then StartTimer( e ) if U.PlayerCloserThan( e, 150 ) then CollisionOff( e ) RotateToPlayer( e ) MoveForward( e, throw_speed ) CollisionOn( e ) else gh.state = "holding" end end end function grapplinghook_preexit(e) end function grapplinghook_exit(e) end