Files
wnsrc/lua/entities/ent_musical_keyboard/init.lua

198 lines
5.0 KiB
Lua
Raw Normal View History

2024-08-04 23:54:45 +03:00
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include( "shared.lua" )
local MAX_USE_DISTANCE = 300 * 300
local function MakeKeyboardSpawner( ply, data )
if IsValid( ply ) and not ply:CheckLimit( "musical_keyboards" ) then return end
local ent = ents.Create( data.Class )
if not IsValid( ent ) then return end
ent:SetPos( data.Pos )
ent:SetAngles( data.Angle )
ent:Spawn()
ent:Activate()
ply:AddCount( "musical_keyboards", ent )
return ent
end
duplicator.RegisterEntityClass( "ent_musical_keyboard", MakeKeyboardSpawner, "Data" )
function ENT:SpawnFunction( ply, tr )
if tr.Hit then
return MakeKeyboardSpawner( ply, {
Pos = tr.HitPos,
Angle = Angle( 0, ply:EyeAngles().y + 90, 0 ),
Class = self.ClassName
} )
end
end
function ENT:Initialize()
self:SetModel( "models/styledstrike/musical_keyboard.mdl" )
self:PhysicsInit( SOLID_VPHYSICS )
self:SetMoveType( MOVETYPE_VPHYSICS )
self:SetSolid( SOLID_VPHYSICS )
self:SetUseType( SIMPLE_USE )
self:DrawShadow( true )
local phys = self:GetPhysicsObject()
if IsValid( phys ) then phys:Wake() end
if WireLib then
WireLib.CreateSpecialOutputs( self, { "NotePlayed" }, { "ARRAY" }, {
[[Triggered when the user played a note.
This array contains:
[1] Note number,
[2] Note velocity
[3] Instrument index (The number near each name on the instruments list)]]
} )
WireLib.CreateSpecialInputs( self, { "PlayNote" }, { "ARRAY" }, {
[[Changing this input will play a note.
The array should contain:
[1] Note number (1-127)
[2] Note velocity (1-127)
[3] Instrument index (The number near each name on the instruments list)]]
} )
self.reproduceQueue = {}
self.transmitQueue = {}
end
end
function ENT:Use( ply )
self:SetPlayer( ply )
end
function ENT:SetPlayer( ply )
if IsValid( self.Ply ) and not self.Ply:Alive() then
self.Ply = nil
end
if not IsValid( self.Ply ) and ply:Alive() then
net.Start( "mkeyboard.set_current_keyboard", false )
net.WriteEntity( self )
net.Send( ply )
self.Ply = ply
end
end
function ENT:RemovePlayer()
if IsValid( self.Ply ) then
net.Start( "mkeyboard.set_current_keyboard", false )
net.WriteEntity( nil )
net.Send( self.Ply )
end
self.Ply = nil
end
function ENT:Think()
self:NextThink( CurTime() )
self:UpdateNotes()
if IsValid( self.Ply ) and (
not self.Ply:Alive() or
self.Ply:GetPos():DistToSqr( self:GetPos() ) > MAX_USE_DISTANCE
) then
self:RemovePlayer()
end
return true
end
if not WireLib then
function ENT:UpdateNotes() end
function ENT:OnReceiveNotes() end
return
end
local function ValidateNumber( v, default, min, max )
return math.Clamp( math.Round( tonumber( v ) or default ), min, max )
end
function ENT:TriggerInput( name, value )
if name ~= "PlayNote" then return end
if not isnumber( value[1] ) then return end
local note = ValidateNumber( value[1], 0, 0, 127 )
if note == 0 then return end
local velocity = ValidateNumber( value[2], 127, 1, 127 )
local instrument = ValidateNumber( value[3], 1, 1, 127 ) -- Max. value is based on net.WriteUInt( 7 )
local queue = self.transmitQueue
-- Remember when we started putting notes
-- on the queue, and when we should send them
local t = SysTime()
if not self.queueTimer then
self.queueTimer = t + 0.4
self.queueStart = t
end
-- Add notes to the queue unless the limit was reached
local noteCount = #queue
if noteCount < MKeyboard.NET_MAX_NOTES then
queue[noteCount + 1] = {
note, velocity, instrument, t - self.queueStart
}
end
end
local SysTime = SysTime
function ENT:OnReceiveNotes( notes )
local t = SysTime()
local queue = self.reproduceQueue
for i, n in ipairs( notes ) do
-- i * 0.01 to prevent overriding stuff already on the queue
queue[t + n[4] + ( i * 0.01 )] = { n[1], n[2], n[3] }
end
end
local GetKeys = table.GetKeys
function ENT:UpdateNotes()
local now = SysTime()
-- If the queued notes are ready to be sent...
if self.queueTimer and now > self.queueTimer then
MKeyboard.BroadcastNotes( self.transmitQueue, self, true )
table.Empty( self.transmitQueue )
self.queueTimer = nil
end
-- Trigger the wire outputs while taking the time offsets into account
local queue = self.reproduceQueue
local timestamps = GetKeys( queue )
for _, t in ipairs( timestamps ) do
if now > t then
local n = queue[t]
WireLib.TriggerOutput( self, "NotePlayed", { n[1], n[2], n[3] } )
queue[t] = nil
end
end
end