214 lines
5.2 KiB
Lua
214 lines
5.2 KiB
Lua
local ent = ent
|
|
local scene = entities.currentScene()
|
|
local controller = entities.controller()
|
|
|
|
local timer = Timer.new()
|
|
if not timer:running() then
|
|
timer:start()
|
|
end
|
|
|
|
local state = 0
|
|
local currentDistance = 0
|
|
local polarity = 1
|
|
|
|
local transform = ent:getComponent("Transform")
|
|
local physicsBody = ent:getComponent("PhysicsBody")
|
|
local metadata = ent:getComponent("Metadata")
|
|
local metadataDoor = metadata["door"] or {}
|
|
|
|
local speed = metadataDoor["speed"] or 100.0
|
|
local wait = metadataDoor["wait"] or 4.0
|
|
local isRotating = (metadataDoor["axis"] ~= nil)
|
|
|
|
local targetDistance = 0
|
|
local moveDir = Vector3f(0, 0, 0)
|
|
local rotAxis = Vector3f(0, 1, 0)
|
|
local flags = metadataDoor["spawnflags"] or 0
|
|
|
|
local isToggle = (math.floor(flags / 32) % 2) ~= 0
|
|
if isToggle then
|
|
wait = -1
|
|
end
|
|
|
|
if isRotating then
|
|
local ax = metadataDoor["axis"]
|
|
rotAxis = Vector3f(ax[1], ax[2], ax[3]):normalize()
|
|
|
|
local dist = metadataDoor["distance"] or 90.0
|
|
|
|
local isReverse = (math.floor(flags / 2) % 2) ~= 0
|
|
if isReverse then
|
|
polarity = -1
|
|
end
|
|
|
|
polarity = polarity * -1
|
|
|
|
if dist < 0 then
|
|
polarity = polarity * -1
|
|
dist = math.abs(dist)
|
|
end
|
|
|
|
targetDistance = math.rad(dist)
|
|
speed = math.rad(speed)
|
|
else
|
|
local dir = metadataDoor["direction"]
|
|
if dir then moveDir = Vector3f(dir[1], dir[2], dir[3]):normalize() end
|
|
|
|
local lip = metadataDoor["lip"] or 8.0
|
|
|
|
if physicsBody:initialized() then
|
|
local obb = OBB(physicsBody:bounds())
|
|
local size = obb.extent * 2.0
|
|
|
|
local travelSize = math.abs(moveDir:dot(size))
|
|
targetDistance = travelSize - lip
|
|
else
|
|
targetDistance = 96.0 - lip
|
|
end
|
|
end
|
|
|
|
local soundEmitter = ent
|
|
|
|
local playSound = function( key, loop )
|
|
if not loop then loop = false end
|
|
local url = "/door/" .. key .. ".ogg"
|
|
soundEmitter:queueHook("sound:Emit.%UID%", {
|
|
filename = string.resolveURI(url, metadata["system"]["root"]),
|
|
spatial = true, streamed = true, volume = "sfx", loop = loop
|
|
}, 0)
|
|
end
|
|
|
|
local function toggleDoor( payload )
|
|
if state == 0 or state == 3 then
|
|
state = 1
|
|
playSound("default_move")
|
|
|
|
if isRotating and payload.uid ~= nil then
|
|
local isOneWay = (math.floor(flags / 16) % 2) ~= 0
|
|
|
|
if not isOneWay then
|
|
local user = entities.get( payload.user )
|
|
if user and physicsBody:initialized() then
|
|
local userPos = user:getComponent("Transform").position
|
|
|
|
local obb = OBB(physicsBody:bounds())
|
|
local doorCenter = obb.center
|
|
local hingePos = transform.position
|
|
|
|
local doorBlade = doorCenter - hingePos
|
|
local doorNormal = rotAxis:cross(doorBlade):normalize()
|
|
|
|
local delta = userPos - doorCenter
|
|
|
|
if doorNormal:dot(delta) > 0 then
|
|
polarity = 1
|
|
else
|
|
polarity = -1
|
|
end
|
|
|
|
local baseDist = metadataDoor["distance"] or 90.0
|
|
if baseDist < 0 then
|
|
polarity = polarity * -1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif state == 2 then
|
|
state = 3
|
|
playSound("default_move")
|
|
end
|
|
end
|
|
|
|
-- on tick
|
|
ent:bind( "tick", function(self)
|
|
local deltaMove = 0
|
|
local step = time.delta() * speed
|
|
|
|
if state == 1 then
|
|
deltaMove = step
|
|
currentDistance = currentDistance + step
|
|
|
|
if currentDistance >= targetDistance then
|
|
deltaMove = deltaMove - (currentDistance - targetDistance)
|
|
currentDistance = targetDistance
|
|
state = 2
|
|
timer:reset()
|
|
playSound("default_stop")
|
|
|
|
ent:queueHook("io:FireOutput.%UID%", { output = "OnOpen" }, 0)
|
|
end
|
|
elseif state == 3 then
|
|
deltaMove = -step
|
|
currentDistance = currentDistance - step
|
|
|
|
if currentDistance <= 0 then
|
|
deltaMove = deltaMove - currentDistance
|
|
currentDistance = 0
|
|
state = 0
|
|
playSound("default_stop")
|
|
end
|
|
elseif state == 2 and wait >= 0 then
|
|
if timer:elapsed() >= wait then
|
|
state = 3
|
|
playSound("default_move")
|
|
end
|
|
end
|
|
|
|
if deltaMove ~= 0 then
|
|
local finalMove = deltaMove * polarity
|
|
|
|
if isRotating then
|
|
local rot = Quaternion.axisAngle(rotAxis, finalMove)
|
|
if physicsBody:initialized() then
|
|
physicsBody:applyRotation(rot)
|
|
else
|
|
transform:rotate(rot)
|
|
end
|
|
else
|
|
local vec = moveDir * finalMove
|
|
if physicsBody:initialized() then
|
|
print("Moving by: ", finalMove, " Axis: ", moveDir.x, moveDir.y, moveDir.z)
|
|
physicsBody:setVelocity(moveDir * (finalMove / time.delta()))
|
|
else
|
|
transform.position = transform.position + vec
|
|
end
|
|
end
|
|
else
|
|
if not isRotating and physicsBody:initialized() then
|
|
physicsBody:setVelocity(Vector3f(0,0,0))
|
|
end
|
|
end
|
|
end )
|
|
|
|
-- on use
|
|
ent:addHook( "entity:Use.%UID%", function( payload )
|
|
if payload.user == ent:uid() then return end
|
|
|
|
local useOpens = (math.floor(flags / 256) % 2) ~= 0
|
|
|
|
if useOpens then
|
|
toggleDoor( payload )
|
|
|
|
ent:queueHook("io:FireOutput.%UID%", { output = "OnUse" }, 0)
|
|
else
|
|
playSound("default_locked")
|
|
end
|
|
end )
|
|
|
|
ent:addHook("io:Input.%UID%", function( payload )
|
|
local input = payload.input
|
|
print(ent:name() .. " received I/O Input: " .. input)
|
|
|
|
local mockPayload = {
|
|
user = payload.caller,
|
|
uid = ent:uid()
|
|
}
|
|
|
|
if input == "Open" and (state == 0 or state == 3) then
|
|
toggleDoor(mockPayload)
|
|
elseif input == "Close" and (state == 2 or state == 1) then
|
|
toggleDoor(mockPayload)
|
|
elseif input == "Toggle" or input == "Use" then
|
|
toggleDoor(mockPayload)
|
|
end
|
|
end) |