hi I'm unsing the pickupabble.lua script provided by the community and want to add a sound or a bunch of random sounds based on the material of the object when the object collide with the terrain after been pushed or pulled
-- LUA Script - precede every function and global member with lowercase name of script + '_main'
--
-- pickuppable script
-- ==================
--
-- Assign script to all items to be manipulated by the player
--
--------------------------
-- user editable values --
--------------------------
local maxWeight = 800 -- default maximum weight of pickuppable
-- or stack of pickuppables
local maxSize = 400 -- default maximum size of pickuppable
local minSpeed = 0.05 -- speed of movement at max weight
local carryOfst = 0 -- x offset of carrying position \
local carryHght = 27 -- y offset of carrying position | relative to player
local carryDist = 60 -- z offset of carrying position /
local levelAng = 20 -- number of degrees off horizontal still considered
-- as 'level' for stacking purposes
local handSize = 15 -- size of hand icon (screen %)
local throwEnabled = true -- Picked up items can be thrown
local pushEnabled = true -- Also Pull
--------------------------
local U = require "scriptbank\\utillib"
local Q = require "scriptbank\\quatlib"
local P = require "scriptbank\\physlib"
local modf = math.modf
local deg = math.deg
local rad = math.rad
local max = math.max
local min = math.min
local abs = math.abs
local sin = math.sin
local cos = math.cos
local atan = math.atan2
local sqrt = math.sqrt
local log = math.log
local rnd = math.random
-- return a copy of a table/list (move to utils when tested)
local function deepcopy( orig )
local orig_type = type( orig )
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[ deepcopy( orig_key ) ] = deepcopy( orig_value )
end
setmetatable( copy, deepcopy( getmetatable( orig ) ) )
else -- number, string, boolean, etc
copy = orig
end
return copy
end
-- ============================== --
-- global variables for save/load --
-- ============================== --
g_pickuppables_list = g_pickuppables_list or {}
-- fill g_pickuppables_list with saved version for situation
-- where saving at a checkpoint
if g_pickuppables_list == {} and
g_pickuppables_snapshot ~= nil then
g_pickuppables_list = deepcopy( g_pickuppables_snapshot )
end
-- ============================== --
-- control lists
local dimensions = {}
local names = {}
local pEnt = {}
local carryingEnt = nil -- 'pickuppable' actually in hand (i.e. bottom of any 'Stack'
local droppedEnt = nil -- 'pickuppable' last to be in hand (i.e. last to be dropped)
local promptsOn = true -- whether to show Prompts to player or not
local thrownObj = nil -- details of thrown objects for collision purposes
-- ================================= --
-- start of global functions section --
-- ================================= --
function PU_EnableThrowing()
throwEnabled = true
g_pickuppables_list.throwEnabled = throwEnabled
end
function PU_CanThrow() return throwEnabled end
function PU_DisableThrowing()
throwEnabled = false
g_pickuppables_list.throwEnabled = throwEnabled
end
function PU_EnablePushPull()
pushEnabled = true
g_pickuppables_list.pushEnabled = pushEnabled
end
function PU_CanPush() return pushEnabled end
function PU_DisablePushPull()
pushEnabled = false
g_pickuppables_list.pushEnabled = pushEnabled
end
-- global functions to read/set max weight we can lift
function PU_GetMaxCarryWeight()
return maxWeight
end
function PU_SetMaxCarryWeight( value )
maxWeight = value
g_pickuppables_list.maxWeight = maxWeight
end
-- global functions to read/set max size of item we can lift
function PU_GetMaxCarrySize()
return maxSize
end
function PU_SetMaxCarrySize( value )
maxSize = value
g_pickuppables_list.maxSize = maxSize
end
function PU_DisablePrompts()
promptsOn = false
end
-- stops entity specified from being 'pickuppable'
function PU_RemoveEntity( e )
local remList = g_pickuppables_list.removed
if remList == nil then
g_pickuppables_list.removed = {}
remList = g_pickuppables_list.removed
end
remList[ e ] = true
dimensions[ e ] = nil
pEnt[ e ] = nil
end
-- returns nil or entity id of item being carried
function PU_GetEntityCarried()
return carryingEnt
end
-- returns nil or entity id of last dropped item
function PU_LastDropped()
return droppedEnt
end
-- returns empty list or list of all carried items
function PU_GetCarriedList()
local tempList = {}
if carryingEnt == nil then return tempList end
templist[ #templist + 1 ] = carryingEnt
local function getStackItems( p )
if p.stackList == nil then return end
for k, v in pairs( p.stackItems ) do
templist[ #templist + 1 ] = k
getStackItems( pEnt[ k ] )
end
end
getStackItems( pEnt[ carryingEnt ] )
return tempList
end
-- returns a list of carried items by name
function PU_CarriedNames()
local tempList = {}
for _, v in pairs( PU_GetCarriedList() ) do
templist[ #templist + 1 ] = names[ v ]
end
return templist
end
-- creates a copy of the current state for save/load purposes
function PU_SnapshotGlobalList()
g_pickuppables_snapshot = deepcopy( g_pickuppables_list )
end
-- End of global functions --
-- ======================= --
local mouse1Clicked = false
local mouse2Clicked = false
local mouseTimer = math.huge
-- sprite 'pointers'
local Sprites = {}
local handShowing = 'none'
local function HideHand( hand )
SetSpritePosition( Sprites[ hand ], 200, 200)
handShowing = 'none'
end
local function ShowHand( hand )
SetSpritePosition( Sprites[ hand ], 50, 50)
handShowing = hand
end
local function stackWeight( p )
local totWeight = 0
if p.stackList ~= nil then
for k, p in pairs( p.stackList ) do
totWeight = totWeight + ( dimensions[ p.obj ].m or 0 ) + stackWeight( pEnt[ k ] )
end
end
return totWeight
end
local function ObjectPickuppable( obj )
if obj == nil or obj == 0 then return false end
for _,v in pairs( pEnt ) do
if v.obj == obj then return true end
end
return false
end
local function getDims( obj )
dimensions[ obj ] = P.GetObjectDimensions( obj )
end
-------------------------------------------
-- Init routine - called once per entity --
-- at spawn time --
-------------------------------------------
function pickuppable_init_name( e, name )
-- These includes ensure that the 'make standalone' process
-- copies the libararies to the standalone folder
Include( "utillib.lua" )
Include( "quatlib.lua" )
Include( "physlib.lua" )
-- save name to local list
names[ e ] = name
-- null the list entries for this entity so that when
-- main routine called for the first time they will be
-- correctly initialised
dimensions[ g_Entity[e].obj ] = nil
pEnt[ e ] = nil
-- load sprites if not already loaded
if Sprites[ 'hand1' ] == nil then
Sprites[ 'hand1' ] = CreateSprite(LoadImage ( "scriptbank\\pickuppable\\hand1.png" ) )
Sprites[ 'hand2' ] = CreateSprite(LoadImage ( "scriptbank\\pickuppable\\hand2.png" ) )
local s = Sprites[ 'hand1' ]
SetSpriteOffset( s, -1 , handSize / 2 )
SetSpriteSize ( s, -1 , handSize )
SetSpriteDepth ( s, 0 )
HideHand( 'hand1' )
s = Sprites[ 'hand2' ]
SetSpriteOffset( s, -1 , handSize / 2 )
SetSpriteSize ( s, -1 , handSize )
SetSpriteDepth ( s, 0 )
HideHand( 'hand2' )
end
-- if there is global maximum weight/size use it to initialise the
-- local copy
if g_pickuppables_list.maxWeight ~= nil then
maxWeight = g_pickuppables_list.maxWeight
end
if g_pickuppables_list.maxSize ~= nil then
maxSize = g_pickuppables_list.maxSize
end
if g_pickuppables_list.pushEnabled ~= nil then
pushEnabled = g_pickuppables_list.pushEnabled
end
if g_pickuppables_list.throwEnabled ~= nil then
throwEnabled = g_pickuppables_list.throwEnabled
end
end
local function getRealWorldYangle( xa, ya, za ) -- Euler in degrees, returns radians
-- Tricky to explain but basically g_PlayerAngY is the real-world
-- angle, i.e. 0-359 degrees, whereas the Euler angle for an entity
-- returned by GetObjectPosAng is not.
-- In order to get the 'real-world' equivalent we need to do some math.
-- first rotate a unit 'facing forward' vector by the Euler angles
local xv, _, zv = U.Rotate3D( 0, 0, 1, rad( xa ), rad( ya ), rad ( za ) )
-- now work out the angle from the x and z components of the result
return atan( xv, zv )
end
local function isLevelIsh( xa, ya, za ) -- Euler in degrees, returns true/false
local maxAng = 180 - levelAng
local minAng = -180 + levelAng
return ( xa < minAng or xa > maxAng or
( xa < levelAng and xa > -levelAng ) ) and
( za < minAng or za > maxAng or
( za < levelAng and za > -levelAng ) )
end
local RayCast = IntersectAll
-- given angles and origin position return centre position
local function getCentre( p, x, y, z, xa, ya, za )
-- first rotate offsets
local dims = dimensions[ p.obj ]
local xo, yo, zo = U.Rotate3D( dims.cx, dims.cy, dims.cz, xa, ya, za )
-- now calculate centre of object
return x + xo, y + yo, z + zo
end
local function checkIfSatOn( pb, bpx, bpy, bpz, bax, bay, baz,
pt, tpx, tpy, tpz, tax, tay, taz )
-- can't be stacked if its origin is lower than the base
-- objects origin no matter what the relative orientations are
if tpy < bpy then return false end
-- send a ray trace straight down from the centre of the top object
-- first calculate centre of object
local tcx, tcy, tcz = getCentre( pt, tpx, tpy, tpz, tax, tay, taz )
local lowestY = tcy - ( dimensions[ pt.obj ].h / 2 + 5 )
-- now cast rays from around centre point to try and find the base object
local bObj = RayCast( tcx, tcy, tcz, tcx, lowestY , tcz, pt.obj )
if bObj ~= pb.obj then
bObj = RayCast( tcx + 1, tcy, tcz + 1, tcx + 1, lowestY, tcz + 1, pt.obj )
end
if bObj ~= pb.obj then
bObj = RayCast( tcx + 1, tcy, tcz - 1, tcx + 1, lowestY, tcz - 1, pt.obj )
end
if bObj ~= pb.obj then
bObj = RayCast( tcx - 1, tcy, tcz + 1, tcx + 1, lowestY, tcz + 1, pt.obj )
end
if bObj ~= pb.obj then
bObj = RayCast( tcx - 1, tcy, tcz - 1, tcx + 1, lowestY, tcz - 1, pt.obj )
end
if bObj ~= pb.obj then return false end
local q1 = Q.Conjugate( Q.FromEuler( bax, bay, baz ) )
local xo, yo, zo = U.Rotate3D( tpx - bpx, tpy - bpy, tpz - bpz, Q.ToEuler( q1 ) )
return true, xo, yo, zo, Q.Mul( q1 , Q.FromEuler( tax, tay, taz ) )
end
local function buildStackList( p, base_obj )
-- basically we have to find all pickuppable objects
-- that are sitting on this one and bung them in a
-- separate list, storing their positions relative to
-- the base entity and rotations relative to it
-- we have to do this before we first move the object
-- so we can also move all the others at the same time
local stacked = "No"
-- first check if object is roughly level
local pbx, pby, pbz, abx, aby, abz = GetObjectPosAng( p.obj )
-- for now only allow stacking on 'level(ish)' object
if p.obj == base_obj and not isLevelIsh( abx, aby, abz ) then
p.stackList = nil
return
end
-- roughly level so lets find out who is sat on us;
-- start by creating an empty list, we can delete
-- it if we don't find any 'stackable' items
p.stackList = {}
for k, v in pairs( pEnt ) do
-- don't process ourselves!
if v ~= p then
-- only process entities within range
local tpx, tpy, tpz, tax, tay, taz = GetObjectPosAng( v.obj )
if U.CloserThan( tpx, tpy, tpz, pbx, pby, pbz, maxSize * 2 ) then
local isOn, ox, oy, oz, q = checkIfSatOn( p, pbx, pby, pbz, rad(abx), rad(aby), rad(abz),
v, tpx, tpy, tpz, rad(tax), rad(tay), rad(taz),
dimensions[ k ] );
if isOn then
-- offset values are from the centres not origin!
p.stackList[ k ] = { obj = v.obj, x = ox, y = oy, z = oz, q = q }
stacked = "Yes"
end
end
end
end
if stacked == "Yes" then
for k, v in pairs( p.stackList ) do
-- now recurse
buildStackList( pEnt[ k ] )
end
else -- didn't find any so delete the stack
p.stackList = nil
end
end
local function processRotation( e, p, plQ )
local yaw = -( g_MouseX - 50 ) / 1000
local pitch = -( g_MouseY - 50 ) / 1000
if abs( yaw ) < 0.01 then yaw = 0 end
if p.stackList ~= nil or abs( pitch ) < 0.01 then pitch = 0 end
if promptsOn then Prompt( "Use mouse to rotate " .. names[ e ] ) end
if roty ~= 0 or rotx ~= 0 then
local quat = Q.FromEuler( pitch, yaw, 0 )
p.quat = Q.Mul( quat, p.quat )
end
end
local function clearStacks( p )
if p.stackList ~= nil then
for k, _ in pairs( p.stackList ) do
clearStacks( pEnt[ k ] )
pEnt[ k ].stackList = nil
end
end
end
local topSpeed = 0
local dropTimer = math.huge
local function dropObject( p, e )
droppedEnt = e
mouse1Clicked = true
carryingEnt = nil
mouseTimer = g_Time + 200
--PlaySound(e,0)--JCLEON
-- reset quat ready for next time we pick this entity up
-- stacking will use its own calculations
p.quat = nil
-- clear stackList(s)
clearStacks( p )
p.stackList = nil
SetGamePlayerControlTopspeed( topSpeed )
dropTimer = g_Time + 1000
end
local corners = {}
local function adjustForTerrainCollision( nx, ny, nz, dims, ax, ay, az )
-- We need to work out the coordinates of each 'corner' and check if
-- any of them would be under the terrain, if so we need to raise y
-- by the difference plus a little bit
-- ( could be expanded to add a raycast from corner to corner to check
-- for a terrain collision, but that's difficult ;-) )
-- TODO - replace this with the new terrain collision detection commands
-- at some point
local hw, hh, hl = dims.w / 2, dims.h / 2, dims.l / 2
-- rotate offsets
local ofx, ofy, ofz = U.Rotate3D( dims.cxs, dims.cys,dims.czs, ax, ay, az );
-- create our own collision box
corners = { { xo = hw, yo = hh, zo = hl },
{ xo = hw, yo = hh, zo = -hl },
{ xo = hw, yo = -hh, zo = hl },
{ xo = hw, yo = -hh, zo = -hl },
{ xo = -hw, yo = hh, zo = hl },
{ xo = -hw, yo = hh, zo = -hl },
{ xo = -hw, yo = -hh, zo = hl },
{ xo = -hw, yo = -hh, zo = -hl }
};
local heightDiff = 0
-- now check all the corners to see if any are below
-- the terrain
for k, v in pairs( corners ) do
-- rotate offsets to entity angle
local ox, oy, oz = U.Rotate3D( v.xo, v.yo, v.zo, ax, ay, az );
local th = GetTerrainHeight( nx + ox + ofx , nz + oz + ofz )
local yh = ny + oy + ofy
if th > yh and th - yh > heightDiff then
heightDiff = th - yh
end
end
return ny + heightDiff
end
local function rePositionEnt( e, obj, x, y, z, ax, ay, az )
CollisionOff( e )
PositionObject( obj , x, y, z )
RotateObject( obj, deg( ax ), deg( ay ), deg( az ) )
CollisionOn( e )
end
local function playerIsOn( p, ppx, ppy, ppz )
return p.obj == RayCast( ppx, ppy, ppz, ppx, ppy - 200, ppz, 0 )
end
local function repositionStack( p, nquat, nx, ny, nz, ppx, ppy, ppz )
if p.stackList ~= nil then
if ppy > nx + 20 or playerIsOn( p, ppx, ppy, ppz ) then
dropObject( pEnt[ carryingEnt ], carryingEnt )
return
end
-- quaternion of base item
local xa, ya, za = Q.ToEuler( nquat )
for k, v in pairs( p.stackList ) do
-- calculate relative rotation
local pquat = Q.Mul( nquat, v.q )
-- rotate centre offsets to match new angle
local xo, yo, zo = U.Rotate3D( v.x, v.y, v.z, xa, ya, za )
local px, py, pz = nx + xo, ny + yo, nz + zo
local nxa, nya, nza = Q.ToEuler( pquat )
rePositionEnt( k, v.obj, px, py, pz, nxa, nya, nza )
repositionStack( pEnt[ k ], pquat, px, py, pz, ppx, ppy, ppz )
if carryingEnt == nil then return end
end
end
end
local SEPTT_timer = 0
local function stopEntsPunchingThroughTerrain()
-- or more accurately rescue them when they have been punched through
if g_Time > SEPTT_timer then
-- check 5 times a second
SEPTT_timer = g_Time + 200
for k, v in pairs( pEnt ) do
if k ~= carryingEnt then
local x, y, z, xa, ya, za = GetObjectPosAng( v.obj )
-- check if the centre of the object is below terrain height
local cx, cy, za = getCentre( v, x, y, z, xa, ya, za )
local th = GetTerrainHeight( x, z )
if cy < th - 30 then
ya = getRealWorldYangle( xa, ya, za )
rePositionEnt( k, v.obj, x, th + 1, z, 0, ya, 0 )
end
end
end
end
end
local numFrames = 7
local function positionHandler( e, p, rq, ppx, ppy, ppz )
-- So we need this to run every frame and do the following:
if playerIsOn( p, ppx, ppy, ppz ) then
dropObject( p, e )
return
end
-- calculate current object position and rotation : cp, cq
local cpx, cpy, cpz, cax, cay, caz = GetObjectPosAng( p.obj )
local cq = Q.FromEuler( rad( cax ), rad( cay ), rad( caz ) )
-- calculate difference between cp and required position : rp
local xtg, ytg, ztg = p.rx - cpx, p.ry - cpy, p.rz - cpz
-- if difference greater that some amount work out how far we need
-- to move and calculate a per frame vector to apply which will depend
-- on maximum movement allowable
local dtg = xtg*xtg + ytg*ytg + ztg*ztg
if dtg < 1 then
rePositionEnt( e, p.obj, p.rx, p.ry, p.rz, Q.ToEuler( rq ) )
repositionStack( p, rq, p.rx, p.ry, p.rz, ppx, ppy, ppz )
else
xtg, ytg, ztg = xtg / numFrames, ytg / numFrames, ztg / numFrames
-- calculate per frame rotation (SLERP) : sq (same rules as for position)
local sq = Q.NLerp( cq, rq, 1 / numFrames )
local nx, ny, nz = cpx + xtg, cpy + ytg, cpz + ztg
rePositionEnt( e, p.obj, nx, ny, nz, Q.ToEuler( sq ) )
-- now position stacked ents
repositionStack( p, sq, nx, ny, nz, ppx, ppy, ppz )
end
end
local RayCast = IntersectAll
local throwTimer = 0
local hitObject = {}
local function CheckThrowCollision()
if throwTimer == 0 then throwTimer = g_Time + 1000 end
local colList = P.GetObjectCollisionDetails( thrownObj )
if colList ~= nil then
for i, v in ipairs( colList ) do
if v.obj ~= 0 then
local force = v.f * 1000
local e = P.ObjectToEntity( v.obj )
local Ent = g_Entity[ e ]
if Ent ~= nil then
SetEntityHealth( e, g_Entity[ e ].health - force )
end
if PU_ShowDecal ~= nil then
PU_ShowDecal( "PU Decal", v.x, v.y, v.z, force * 5 )
end
end
end
-- remove health from thrown object causing it to
-- explode ( if explodable )
SetEntityHealth( P.ObjectToEntity( thrownObj ), 0)
elseif g_Time < throwTimer then
-- didn't hit anything yet so give it more time
return
end
-- done with this object so remove from checking list
RemoveObjectCollisionCheck( thrownObj )
thrownObj = nil
throwTimer = 0
end
local function HandleTerrainCollisions()
local colList = P.GetTerrainCollisionDetails( thrownObj )
if colList == nil then return end
for _, v in ipairs( colList ) do
if v.x ~= 0 then
if PU_ShowDecal ~= nil then
PU_ShowDecal( "PU Decal2", v.x, v.y, v.z )
end
end
end
end
local currSpeed = 0
local colCheckTimer = 0
-----------------------------------------------------
-- Start of main entry routine - called very frame --
-----------------------------------------------------
function pickuppable_main(e)
if throwEnabled and P.ObjectToEntity( thrownObj ) == e then
if g_Time > colCheckTimer then
HandleTerrainCollisions()
CheckThrowCollision()
colCheckTimer = g_Time + 100 -- 1/10 second-
end
end
if g_pickuppables_list.removed ~= nil and
g_pickuppables_list.removed[ e ] then
return
end
local Ent = g_Entity[ e ]
if Ent == nil then return end
-- first time though calculate dimensions of entity
local dims = dimensions[ Ent.obj ]
if dims == nil then
getDims( Ent.obj )
return
end
local p = pEnt[ e ]
if p == nil then
-- store the object id for future use
pEnt[ e ] = { obj = Ent.obj }
return
end
if carryingEnt == e or droppedEnt == e then
stopEntsPunchingThroughTerrain()
-- delayed re-enabling of jump mode
if g_Time > dropTimer then
SetGamePlayerControlJumpMode( 0 )
dropTimer = math.huge
end
end
local pObj, objX, objY, objZ = 0, 0, 0, 0
if carryingEnt == nil then
if not U.PlayerCloserThan( e, 200 ) then return end
pObj, objX, objY, objZ = P.ObjectPlayerLookingAt( 100 )
if pObj == p.obj then
if handShowing == 'none' then ShowHand( 'hand1' ) end
elseif not ObjectPickuppable( pObj ) then
if handShowing ~= 'none' then
HideHand( handShowing )
end
return
else
return
end
elseif carryingEnt == e then
if g_PlrKeySPACE == 1 then
SetGamePlayerControlTopspeed( minSpeed )
else
SetGamePlayerControlTopspeed( currSpeed )
end
-- get player position and angles
local ppX, ppY, ppZ = g_PlayerPosX, g_PlayerPosY, g_PlayerPosZ
local paX, paY, paZ = rad( g_PlayerAngX ),
rad( g_PlayerAngY ),
rad( g_PlayerAngZ );
-- player quaternion
local plQ = Q.FromEuler( 0, paY, paZ )
-- we are carrying this entity
if handShowing ~= 'none' then
HideHand( handShowing )
end
if promptsOn then
if not throwEnabled then
Prompt( "LMB to drop " .. names[ e ] .. ", Hold RMB to rotate")
else
Prompt( "LMB(+E) to drop(throw) " .. names[ e ] .. ", Hold RMB to rotate")
end
end
if g_MouseClick == 1 or GetPlayerWeaponID() ~= 0 then
if not mouse1Clicked then
dropObject( p, e )
if not throwEnabled then return end
-- handle throwing
if g_KeyPressE == 1 and g_MouseClick == 1 then
local force = min( maxWeight / 6, dims.m )
vx, vy, vz = U.Rotate3D ( 0, 0, 1, paX, paY, paZ )
if names[ e ] == 'saw blade' then
force = force * 20
PushObject( p.obj, vx * force, vy * force, vz * force,
rnd()/10 , 0, rnd()/10 )
else
PushObject( p.obj, vx * force, vy * force, vz * force,
rnd()/100, rnd()/100, rnd()/100 )
end
-- test new collision testing command
thrownObj = p.obj
AddObjectCollisionCheck( p.obj )
-- do initial check in case enemy really close!
CheckThrowCollision()
end
return
end
elseif g_MouseClick == 2 then
if not mouse2Clicked then
mouse2Clicked = true
ActivateMouse()
end
processRotation( e, p, plQ )
elseif mouse2Clicked or (mouse1Clicked and g_Time > mouseTimer) then
DeactivateMouse()
mouse1Clicked = false
mouse2Clicked = false
mouseTimer = math.huge
end
-- move entity with player
-- (may need to handle collision as entity will probably be
-- outside player capsule)
if p.quat == nil then
-- we've just picked it up so initialise:
-- work out offset position of entity when held by player
local size = max( dims.w, dims.h, dims.l )
-- need to ensure entity is offset far enough to rotate
p.xo, p.yo, p.zo = carryOfst, carryHght, carryDist + size / 2
-- get entity angles
local _,_,_, eaX, eaY, eaZ = GetObjectPosAng( p.obj )
-- need to work out real world angle of entity
rwY = getRealWorldYangle( eaX, eaY, eaZ )
-- store angle as quaternion
p.quat = Q.FromEuler( 0, rwY - paY, 0 )
end
-- work out offset position of entity when held by player
-- first taking account of player angles
local xo, yo, zo = U.Rotate3D( p.xo, p.yo, p.zo, paX, paY, paZ )
-- work out rotation quaternion of entity
local enQ = Q.Mul( plQ, p.quat )
-- then object offsets, i.e to centre it properly
local oAx, oAy, oAz = Q.ToEuler( enQ )
local oxo, oyo, ozo = U.Rotate3D( dims.cx, dims.cy, dims.cz, oAx, oAy, oAz )
-- calculate new position for entity
p.rx, p.ry, p.rz = ppX + xo - oxo, ppY + yo - oyo, ppZ + zo - ozo
-- make sure we don't sink the entity into the terrain
p.ry = adjustForTerrainCollision( p.rx, p.ry, p.rz, dims, oAx, oAy, oAz )
positionHandler( e, p, enQ, ppX, ppY, ppZ )
return
else
-- something being carried and it isn't us so leave
return
end
if GetPlayerWeaponID() ~= 0 then
if promptsOn then Prompt( "Can't manipulate " .. names[ e ] .. " without your hands free!" ) end
if handShowing == 'hand1' then
HideHand( handShowing )
ShowHand( 'hand2' )
end
mouseTimer = g_Time + 200
return
end
-- if we've got here we can potentially pick up the item
-- check how heavy it is
if max( dims.w, dims.h, dims.l ) > maxSize then
if promptsOn then Prompt( names[ e ] .. " is too large to carry!" ) end
if handShowing == 'hand1' then
HideHand( handShowing )
ShowHand( 'hand2' )
end
elseif dims.m > maxWeight then
if promptsOn then Prompt( names[ e ] .. " is too heavy to lift!" ) end
if handShowing == 'hand1' then
HideHand( handShowing )
ShowHand( 'hand2' )
end
else
if handShowing == 'hand2' and
g_Time > mouseTimer then
HideHand( handShowing )
ShowHand( 'hand1' )
end
if mouse1Clicked then
if g_Time > mouseTimer then
mouse1Clicked = false
mouseTimer = math.huge
end
return
end
if promptsOn then
if pushEnabled then
Prompt( "LMB to pick up " .. names[ e ] .. ", E/R + LMB to Push/Pull." )
else
Prompt( "LMB to pick up " .. names[ e ] )
end
end
local pushX, pushY, pushZ = P.GetViewVector()
-- PromptLocal( e, pushX .. "," .. pushY .. "," .. pushZ .. " : " ..
-- objX .. "," .. objY .. "," .. objZ )
if g_MouseClick == 1 then
if pushEnabled then
-- handle pushing
if g_KeyPressE == 1 or g_KeyPressR == 1 then
-- local pushX, pushY, pushZ = P.GetViewVector()
-- get object position and angle
local ex, ey, ez, xa, ya, za = GetObjectPosAng( p.obj )
-- work out centre of object
local ox, oy, oz = U.Rotate3D( dims.cx, dims.cy, dims.cz, xa, ya, za );
local cx, cy, cz = ex + ox, ey + oy, ez + oz
-- finally work out contact point offsets from centre
ox, oy, oz = objX - cx, objY - cy, objZ - cz
-- push force less than throw force
local force
if g_KeyPressE == 1 then
force = min( maxWeight / 20, dims.m / 4 )
-- and push!
PushObject( p.obj, pushX*force, pushY*force, pushZ*force, ox, oy, oz )
else
-- pull force less than push force
local force = min( maxWeight / 60, dims.m / 6 )
-- and pull!
PushObject( p.obj, -pushX*force, -pushY*force, -pushZ*force, ox, oy, oz )
end
return
end
end
mouse1Clicked = true
-- build stack list
buildStackList( p, p.obj )
-- check how heavy the stack is
local currWeight = stackWeight( p ) + dims.m
if currWeight > maxWeight then
if promptsOn then
PromptDuration( "Stack is too heavy, remove some items or get stronger!", 2000 )
end
if handShowing == 'hand1' then
HideHand( handShowing )
ShowHand( 'hand2' )
end
mouseTimer = g_Time + 2000
else
carryingEnt = e
mouseTimer = g_Time + 200
topSpeed = GetGamePlayerControlTopspeed()
currSpeed = minSpeed + ( ( maxWeight - currWeight ) /
----------------------
maxWeight ) * ( topSpeed - minSpeed )
SetGamePlayerControlTopspeed( currSpeed )
SetGamePlayerControlJumpMode( 3 )
end
end
end
end
i added this
else
colList = P.GetTerrainCollisionDetails( Ent.obj )
if colList ~= nil then
PlaySound(e,0)
--we hit the ground
RemoveObjectCollisionCheck( Ent.obj )
break
end
end
in the HandleTerrainCollisions function to have this
local function HandleTerrainCollisions()
local colList = P.GetTerrainCollisionDetails( thrownObj )
if colList == nil then return end
for _, v in ipairs( colList ) do
if v.x ~= 0 then
if PU_ShowDecal ~= nil then
PU_ShowDecal( "PU Decal2", v.x, v.y, v.z )
end
end
end
else
colList = P.GetTerrainCollisionDetails( Ent.obj )
if colList ~= nil then
PlaySound(e,0)
--we hit the ground
RemoveObjectCollisionCheck( Ent.obj )
break
end
end
end
but i got ean error ..I'm new to lua and still learning and sincerely i cannot figured too well all the "end" lua needs LOL
any hint?
PC Specs:
AMD QUADCORE 880K @4.5GHZ, 32GB RAM DDR3 1600, M/B ASUS A88XM-PLUS
SVGA NVDIA 1660GTX 6GB , SSD KINGSTON A400 1TB, 2X HHD SEAGATE BARRACUDA 4TB