mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
199 lines
5.3 KiB
Lua
199 lines
5.3 KiB
Lua
|
|
--[[
|
||
|
|
| 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()
|
||
|
|
|
||
|
|
DEFINE_BASECLASS( "base_anim" )
|
||
|
|
|
||
|
|
ENT.PrintName = "Bouncy Ball"
|
||
|
|
ENT.Author = "Garry Newman"
|
||
|
|
ENT.Information = "An edible bouncy ball. Press USE on the bouncy ball to eat it."
|
||
|
|
ENT.Category = "Fun + Games"
|
||
|
|
|
||
|
|
ENT.Editable = true
|
||
|
|
ENT.Spawnable = true
|
||
|
|
ENT.AdminOnly = false
|
||
|
|
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||
|
|
|
||
|
|
ENT.MinSize = 4
|
||
|
|
ENT.MaxSize = 128
|
||
|
|
|
||
|
|
function ENT:SetupDataTables()
|
||
|
|
|
||
|
|
self:NetworkVar( "Float", 0, "BallSize", { KeyName = "ballsize", Edit = { type = "Float", min = self.MinSize, max = self.MaxSize, order = 1 } } )
|
||
|
|
self:NetworkVar( "Vector", 0, "BallColor", { KeyName = "ballcolor", Edit = { type = "VectorColor", order = 2 } } )
|
||
|
|
|
||
|
|
if ( SERVER ) then
|
||
|
|
self:NetworkVarNotify( "BallSize", self.OnBallSizeChanged )
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
-- This is the spawn function. It's called when a client calls the entity to be spawned.
|
||
|
|
-- If you want to make your SENT spawnable you need one of these functions to properly create the entity
|
||
|
|
--
|
||
|
|
-- ply is the name of the player that is spawning it
|
||
|
|
-- tr is the trace from the player's eyes
|
||
|
|
--
|
||
|
|
function ENT:SpawnFunction( ply, tr, ClassName )
|
||
|
|
|
||
|
|
if ( !tr.Hit ) then return end
|
||
|
|
|
||
|
|
local size = math.random( 16, 48 )
|
||
|
|
local SpawnPos = tr.HitPos + tr.HitNormal * size
|
||
|
|
|
||
|
|
-- Make sure the spawn position is not out of bounds
|
||
|
|
local oobTr = util.TraceLine( {
|
||
|
|
start = tr.HitPos,
|
||
|
|
endpos = SpawnPos,
|
||
|
|
mask = MASK_SOLID_BRUSHONLY
|
||
|
|
} )
|
||
|
|
|
||
|
|
if ( oobTr.Hit ) then
|
||
|
|
SpawnPos = oobTr.HitPos + oobTr.HitNormal * ( tr.HitPos:Distance( oobTr.HitPos ) / 2 )
|
||
|
|
end
|
||
|
|
|
||
|
|
local ent = ents.Create( ClassName )
|
||
|
|
ent:SetPos( SpawnPos )
|
||
|
|
ent:SetBallSize( size )
|
||
|
|
ent:Spawn()
|
||
|
|
ent:Activate()
|
||
|
|
|
||
|
|
return ent
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Initialize()
|
||
|
|
|
||
|
|
-- We do NOT want to execute anything below in this FUNCTION on CLIENT
|
||
|
|
if ( CLIENT ) then return end
|
||
|
|
|
||
|
|
-- Use the helibomb model just for the shadow (because it's about the same size)
|
||
|
|
self:SetModel( "models/Combine_Helicopter/helicopter_bomb01.mdl" )
|
||
|
|
|
||
|
|
-- We will put this here just in case, even though it should be called from OnBallSizeChanged in any case
|
||
|
|
self:RebuildPhysics()
|
||
|
|
|
||
|
|
-- Set the size if it wasn't set already..
|
||
|
|
if ( self:GetBallSize() == 0 ) then self:SetBallSize( 32 ) end
|
||
|
|
|
||
|
|
-- Select a random color for the ball, if one wasn't set.
|
||
|
|
if ( !self:GetBallColor():IsZero() ) then return end
|
||
|
|
|
||
|
|
self:SetBallColor( table.Random( {
|
||
|
|
Vector( 1, 0.3, 0.3 ),
|
||
|
|
Vector( 0.3, 1, 0.3 ),
|
||
|
|
Vector( 1, 1, 0.3 ),
|
||
|
|
Vector( 0.2, 0.3, 1 ),
|
||
|
|
} ) )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:RebuildPhysics( value )
|
||
|
|
|
||
|
|
-- This is necessary so that the vphysics.dll will not crash when attaching constraints to the new PhysObj after old one was destroyed
|
||
|
|
-- TODO: Somehow figure out why it happens and/or move this code/fix to the constraint library
|
||
|
|
self.ConstraintSystem = nil
|
||
|
|
|
||
|
|
local size = math.Clamp( value or self:GetBallSize(), self.MinSize, self.MaxSize ) / 2.1
|
||
|
|
self:PhysicsInitSphere( size, "metal_bouncy" )
|
||
|
|
self:SetCollisionBounds( Vector( -size, -size, -size ), Vector( size, size, size ) )
|
||
|
|
|
||
|
|
self:PhysWake()
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
if ( SERVER ) then
|
||
|
|
|
||
|
|
function ENT:OnBallSizeChanged( varname, oldvalue, newvalue )
|
||
|
|
|
||
|
|
-- Do not rebuild if the size wasn't changed
|
||
|
|
if ( oldvalue == newvalue ) then return end
|
||
|
|
|
||
|
|
self:RebuildPhysics( newvalue )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:KeyValue( key, val )
|
||
|
|
if ( key == "ball_size" ) then self:SetBallSize( val ) end
|
||
|
|
if ( key == "rendercolor" ) then self:SetBallColor( Vector( val ) / 255 ) end
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
local BounceSound = Sound( "garrysmod/balloon_pop_cute.wav" )
|
||
|
|
|
||
|
|
function ENT:PhysicsCollide( data, physobj )
|
||
|
|
|
||
|
|
-- Play sound on bounce
|
||
|
|
if ( data.Speed > 60 && data.DeltaTime > 0.2 ) then
|
||
|
|
|
||
|
|
local pitch = 32 + 128 - math.Clamp( self:GetBallSize(), self.MinSize, self.MaxSize )
|
||
|
|
sound.Play( BounceSound, self:GetPos(), 75, math.random( pitch - 10, pitch + 10 ), math.Clamp( data.Speed / 150, 0, 1 ) )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Bounce like a crazy bitch
|
||
|
|
local LastSpeed = math.max( data.OurOldVelocity:Length(), data.Speed )
|
||
|
|
local NewVelocity = physobj:GetVelocity()
|
||
|
|
NewVelocity:Normalize()
|
||
|
|
|
||
|
|
LastSpeed = math.max( NewVelocity:Length(), LastSpeed )
|
||
|
|
|
||
|
|
local TargetVelocity = NewVelocity * LastSpeed * 0.9
|
||
|
|
|
||
|
|
physobj:SetVelocity( TargetVelocity )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:OnTakeDamage( dmginfo )
|
||
|
|
|
||
|
|
-- React physically when shot/getting blown
|
||
|
|
self:TakePhysicsDamage( dmginfo )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function ENT:Use( activator, caller )
|
||
|
|
|
||
|
|
self:Remove()
|
||
|
|
|
||
|
|
if ( activator:IsPlayer() ) then
|
||
|
|
|
||
|
|
-- Give the collecting player some free health
|
||
|
|
local health = activator:Health()
|
||
|
|
activator:SetHealth( health + 5 )
|
||
|
|
activator:SendLua( "achievements.EatBall()" )
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
if ( SERVER ) then return end -- We do NOT want to execute anything below in this FILE on SERVER
|
||
|
|
|
||
|
|
local matBall = Material( "sprites/sent_ball" )
|
||
|
|
|
||
|
|
function ENT:Draw()
|
||
|
|
|
||
|
|
render.SetMaterial( matBall )
|
||
|
|
|
||
|
|
local pos = self:GetPos()
|
||
|
|
local lcolor = render.ComputeLighting( pos, Vector( 0, 0, 1 ) )
|
||
|
|
local c = self:GetBallColor()
|
||
|
|
|
||
|
|
lcolor.x = c.r * ( math.Clamp( lcolor.x, 0, 1 ) + 0.5 ) * 255
|
||
|
|
lcolor.y = c.g * ( math.Clamp( lcolor.y, 0, 1 ) + 0.5 ) * 255
|
||
|
|
lcolor.z = c.b * ( math.Clamp( lcolor.z, 0, 1 ) + 0.5 ) * 255
|
||
|
|
|
||
|
|
local size = math.Clamp( self:GetBallSize(), self.MinSize, self.MaxSize )
|
||
|
|
render.DrawSprite( pos, size, size, Color( lcolor.x, lcolor.y, lcolor.z, 255 ) )
|
||
|
|
|
||
|
|
end
|