374 lines
14 KiB
Lua
374 lines
14 KiB
Lua
AddCSLuaFile()
|
|
|
|
ENT.PrintName = "Construction"
|
|
ENT.Type = "anim"
|
|
ENT.Base = "base_gmodentity"
|
|
ENT.Spawnable = false
|
|
ENT.AdminOnly = true
|
|
ENT.DoNotDuplicate = false
|
|
ENT._Seen = false
|
|
ENT._Lerp = 0
|
|
ENT._Ler2 = 0
|
|
|
|
function ENT:SetupDataTables()
|
|
self:NetworkVar("Int", 0, "State")
|
|
self:NetworkVar("Float", 0, "Progress")
|
|
self:NetworkVar("String", 0, "Nick")
|
|
self:NetworkVar("Entity", 0, "Owned")
|
|
self:NetworkVar("Entity", 1, "Player")
|
|
|
|
if SERVER then
|
|
self:NetworkVarNotify("Progress", function(self, name, old, new)
|
|
if new >= 99.9 then
|
|
if self:GetState() == 2 then return end
|
|
self:SetState(2)
|
|
|
|
if self.EntToBuild == "prop_physics" then
|
|
self.buildEnt = ents.Create("constructor_prop")
|
|
self.buildEnt:SetPos(self:GetPos() + vector_up*0.5)
|
|
self.buildEnt:SetAngles(self:GetAngles())
|
|
|
|
if self.EntModel then
|
|
self.buildEnt:SetModel(self.EntModel)
|
|
self.buildEnt.Model = self.EntModel
|
|
else
|
|
self.buildEnt:SetModel(self:GetModel())
|
|
end
|
|
|
|
self.buildEnt.InitialHealth = self.EntHealth or 10000
|
|
self.buildEnt.PropName = self:GetNick() or "Constructor Prop"
|
|
|
|
self.buildEnt:Spawn()
|
|
self.buildEnt:Activate()
|
|
self.buildEnt:SetNWEntity("SpikeOwner", self:GetPlayer())
|
|
self.buildEnt.BuilderCost = self.EntToBuildCost or 10
|
|
|
|
local phys = self.buildEnt:GetPhysicsObject()
|
|
if IsValid(phys) then
|
|
phys:EnableMotion(false)
|
|
end
|
|
|
|
if self.EntToBuild == "sw_sania" then
|
|
timer.Simple(0, function()
|
|
if not IsValid(self.buildEnt) then return end
|
|
|
|
local nearest
|
|
local dist = 200
|
|
|
|
for _, veh in ipairs(ents.FindInSphere(self:GetPos(), 200)) do
|
|
if veh.LVS then
|
|
local d = veh:GetPos():Distance(self:GetPos())
|
|
if d < dist then
|
|
dist = d
|
|
nearest = veh
|
|
end
|
|
end
|
|
end
|
|
|
|
if IsValid(nearest) then
|
|
local physTarget = nearest:GetBase() or nearest
|
|
|
|
self.buildEnt:SetPos(nearest:GetPos() + Vector(0,0,60))
|
|
self.buildEnt:SetAngles(nearest:GetAngles())
|
|
|
|
constraint.Weld(self.buildEnt, physTarget, 0, 0, 0, true)
|
|
|
|
print("[REB] РЭБ приварена к LVS:", nearest)
|
|
else
|
|
print("[REB] LVS техника не найдена рядом")
|
|
end
|
|
end)
|
|
end
|
|
|
|
undo.ReplaceEntity(self, self.buildEnt)
|
|
cleanup.ReplaceEntity(self, self.buildEnt)
|
|
|
|
sound.Play("weapons/building.wav", self:GetPos() + vector_up*16, 80, 120)
|
|
self:Remove()
|
|
return
|
|
else
|
|
self.buildEnt = ents.Create(self.EntToBuild)
|
|
|
|
if not IsValid(self.buildEnt) then
|
|
return
|
|
end
|
|
|
|
self.buildEnt:SetPos(self:GetPos() + vector_up*0.5)
|
|
self.buildEnt:SetAngles(self:GetAngles())
|
|
|
|
self.buildEnt:SetKeyValue("Modification", 1)
|
|
|
|
if self:GetNick() == "Rebel Turret" then
|
|
self.buildEnt:SetKeyValue("spawnflags", 512)
|
|
self.buildEnt:SetSaveValue("m_bHackedByAlyx", true)
|
|
end
|
|
|
|
self.buildEnt:SetSaveValue("m_bPlacedByPlayer", true)
|
|
self.buildEnt:SetSaveValue("m_Efficiency", 2)
|
|
self.buildEnt:SetSaveValue("m_CurrentWeaponProficiency", 100)
|
|
|
|
self.buildEnt:Spawn()
|
|
self.buildEnt:Activate()
|
|
self.buildEnt.BuilderCost = self.EntToBuildCost or 10
|
|
|
|
|
|
local owner = self:GetOwned() or self:GetOwner()
|
|
self.buildEnt:SetNWEntity("SpikeOwner", owner)
|
|
|
|
if self.buildEnt:GetClass():find("sent_ranged_healer") then
|
|
self.buildEnt:SetHealEverything(false)
|
|
self.buildEnt:SetHealRadius(256)
|
|
self.buildEnt:SetHealTeam(1001)
|
|
if owner and owner:IsPlayer() then
|
|
self.buildEnt:SetPlayer(owner)
|
|
end
|
|
self.buildEnt:SetReplenishArmor(false)
|
|
elseif self.buildEnt:GetClass():find("barricade") then
|
|
local phys = self.buildEnt:GetPhysicsObject()
|
|
if IsValid(phys) then
|
|
phys:EnableMotion(false)
|
|
end
|
|
self.buildEnt:SetPos(self:GetPos() + vector_up*-5)
|
|
elseif self.buildEnt:GetClass():find("item_") then
|
|
self.buildEnt:PhysicsInit(SOLID_VPHYSICS)
|
|
if IsValid(self.MyWeldedEnt) then
|
|
constraint.Weld(self.buildEnt, self.MyWeldedEnt, 0, 0, 0, 0, true)
|
|
else
|
|
local phys = self.buildEnt:GetPhysicsObject()
|
|
if IsValid(phys) then
|
|
phys:EnableMotion(false)
|
|
end
|
|
end
|
|
elseif self.buildEnt:GetClass() == "bouncingmortar" or
|
|
self.buildEnt:GetClass() == "ent_trappopeller_engine" then
|
|
local phys = self.buildEnt:GetPhysicsObject()
|
|
if IsValid(phys) then
|
|
phys:EnableMotion(false)
|
|
end
|
|
self.buildEnt:SetAngles(angle_zero)
|
|
elseif self.buildEnt:GetClass() == "npc_turret_floor" then
|
|
self.buildEnt:SetNWBool("RebSentri", true)
|
|
if self:GetNick() == "Rebel Turret" then
|
|
local v = self.buildEnt
|
|
v.FriendsWithAllPlayerAllies = true
|
|
v.PlayerFriendly = true
|
|
v.VJ_NPC_Class = {"CLASS_REBEL"}
|
|
v.DisableMakingSelfEnemyToNPCs = true
|
|
|
|
if math.random() < 0.33 then
|
|
v:SetSubMaterial(0, "models/combine_turrets/floor_turret/floor_turret_citizen")
|
|
v:SetMaterial("models/combine_turrets/floor_turret/floor_turret_citizen")
|
|
elseif math.random() > 0.33 then
|
|
v:SetSubMaterial(0, "models/combine_turrets/floor_turret/floor_turret_citizen2")
|
|
v:SetMaterial("models/combine_turrets/floor_turret/floor_turret_citizen2")
|
|
else
|
|
v:SetSubMaterial(0, "models/combine_turrets/floor_turret/floor_turret_citizen4")
|
|
v:SetMaterial("models/combine_turrets/floor_turret/floor_turret_citizen4")
|
|
end
|
|
end
|
|
elseif self.buildEnt:GetClass() == "combine_mine" then
|
|
local v = self.buildEnt
|
|
if math.random() < 0.33 then
|
|
v:SetSubMaterial(0, "Models/Combine_Mine/combine_mine_citizen")
|
|
v:SetMaterial("Models/Combine_Mine/combine_mine_citizen")
|
|
elseif math.random() > 0.33 then
|
|
v:SetSubMaterial(0, "Models/Combine_Mine/combine_mine_citizen"..math.random(2,3))
|
|
v:SetMaterial("Models/Combine_Mine/combine_mine_citizen"..math.random(2,3))
|
|
end
|
|
timer.Simple(1, function()
|
|
if IsValid(v) then
|
|
v:StopSound("npc/roller/mine/combine_mine_active_loop1.wav")
|
|
end
|
|
end)
|
|
end
|
|
|
|
undo.ReplaceEntity(self, self.buildEnt)
|
|
cleanup.ReplaceEntity(self, self.buildEnt)
|
|
|
|
sound.Play("weapons/building.wav", self:GetPos() + vector_up*16, 80, 120)
|
|
self:Remove()
|
|
return
|
|
end
|
|
else
|
|
self:SetColor(Color(255, 255, 255, math.Clamp(new/100*255, 32, 192)))
|
|
end
|
|
end)
|
|
|
|
self:NetworkVarNotify("Owned", function(self, name, old, new)
|
|
if old == new then return end
|
|
self.Owner = new
|
|
self:SetOwner(new)
|
|
if NADMOD then
|
|
NADMOD.PlayerMakePropOwner(new, self)
|
|
end
|
|
end)
|
|
|
|
self:NetworkVarNotify("Player", function(self, name, old, new)
|
|
if old == new then return end
|
|
self._Player = new
|
|
end)
|
|
end
|
|
end
|
|
|
|
function ENT:GetPlayer()
|
|
if SERVER then
|
|
return self._Player or self:GetVar("Player") or self:GetOwner()
|
|
else
|
|
return self:GetVar("Player") or self:GetOwner()
|
|
end
|
|
end
|
|
|
|
function ENT:SetPlayer(ply)
|
|
if not SERVER then return end
|
|
self._Player = ply
|
|
self:SetVar("Player", ply)
|
|
end
|
|
|
|
function ENT:Initialize()
|
|
if CLIENT then return end
|
|
|
|
if self.EntModel then
|
|
self:SetModel(self.EntModel)
|
|
else
|
|
self:SetModel("models/props_junk/wood_crate001a.mdl")
|
|
end
|
|
|
|
self:PhysicsInit(SOLID_VPHYSICS)
|
|
self:SetMoveType(MOVETYPE_VPHYSICS)
|
|
self:SetSolid(SOLID_VPHYSICS)
|
|
|
|
self:DrawShadow(false)
|
|
self:SetCollisionGroup(COLLISION_GROUP_NONE)
|
|
self:SetUseType(SIMPLE_USE)
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if IsValid(phys) then
|
|
phys:Wake()
|
|
end
|
|
|
|
self:SetProgress(0)
|
|
self:SetState(0)
|
|
self:SetNick("")
|
|
end
|
|
|
|
function ENT:Use(ply)
|
|
if ply:IsPlayer() then
|
|
if self:IsPlayerHolding() then return end
|
|
ply:PickupObject(self)
|
|
end
|
|
end
|
|
|
|
function ENT:OnTakeDamage( damage )
|
|
self:TakePhysicsDamage(damage)
|
|
end
|
|
|
|
function ENT:PhysicsCollide(data, phys)
|
|
if data.DeltaTime > 0.2 then
|
|
if data.Speed > 250 then
|
|
self:EmitSound("physics/metal/metal_box_impact_hard" .. math.random(1, 3) .. ".wav", 75, math.random(90,110), 0.5)
|
|
else
|
|
self:EmitSound("physics/metal/metal_box_impact_soft" .. math.random(1, 3) .. ".wav", 75, math.random(90,110), 0.2)
|
|
end
|
|
end
|
|
end
|
|
|
|
hook.Add( "GetPreferredCarryAngles", "BuilderCarryAngs", function( ent )
|
|
if ent:GetNWBool("RebSentri") then
|
|
return Angle( -10, 0, 0 )
|
|
end
|
|
end)
|
|
|
|
if SERVER then return end
|
|
|
|
function ENT:OnRemove()
|
|
if self:GetState() > 0 then
|
|
local ed = EffectData()
|
|
ed:SetOrigin(self:GetPos())
|
|
ed:SetEntity(self)
|
|
util.Effect( "entity_remove", ed, true, true )
|
|
end
|
|
end
|
|
|
|
function ENT:Think()
|
|
if self._Seen != self:BeingLookedAtByLocalPlayer() then
|
|
self._Seen = self:BeingLookedAtByLocalPlayer() self._Lerp = SysTime() +0.2
|
|
end
|
|
self._Ler2 = Lerp( 0.1, self._Ler2, self:GetProgress() )
|
|
end
|
|
|
|
local glow = Material( "models/wireframe" )
|
|
local Mat = Material( "particle/particle_ring_wave_addnofog" )
|
|
|
|
function ENT:Draw()
|
|
self:DrawModel( )
|
|
|
|
render.CullMode(MATERIAL_CULLMODE_CW)
|
|
self.DrawModel( self )
|
|
render.CullMode(MATERIAL_CULLMODE_CCW)
|
|
|
|
if self:GetState() == 0 then
|
|
render.SuppressEngineLighting( true )
|
|
render.SetBlend( 0.25 ) render.MaterialOverride( glow )
|
|
render.SetColorModulation( 1, 1, 0 )
|
|
self:DrawModel()
|
|
render.SetBlend( 1 ) render.MaterialOverride()
|
|
render.SetColorModulation( 1, 1, 1 )
|
|
render.SuppressEngineLighting( false )
|
|
else
|
|
local pro = math.Clamp( 1 -self:GetProgress()/100, 0, 1 )
|
|
render.SuppressEngineLighting( true )
|
|
render.SetBlend( pro/4 ) render.MaterialOverride( glow )
|
|
render.SetColorModulation( 1, 1, 1 )
|
|
self:DrawModel()
|
|
render.SetBlend( 1 ) render.MaterialOverride()
|
|
render.SetColorModulation( 1, 1, 1 )
|
|
render.SuppressEngineLighting( false )
|
|
end
|
|
if self._Seen or self._Lerp > SysTime() then
|
|
local ler = math.Clamp( ( self._Lerp -SysTime() )/0.2, 0, 1 )
|
|
if self._Seen then ler = 1-ler end
|
|
cam.Start2D()
|
|
local pos = self:WorldSpaceCenter():ToScreen()
|
|
local x, y, radius, seg, per = math.Round( pos.x ), math.Round( pos.y ), ler*40, 360, self._Ler2/100
|
|
for i=1, 6 do surface.DrawCircle( x, y, radius -7 +i, Color( 0, 0, 0, 192*ler ) ) end
|
|
per = isnumber( per ) and per or 1
|
|
local cir = {}
|
|
table.insert( cir, { x = x, y = y, u = 0.5, v = 0.5 } )
|
|
for i = 0, seg do
|
|
if i > math.ceil( seg*per ) then break end
|
|
local a = math.rad( ( i/seg )*-360 +180 )
|
|
table.insert( cir, { x = x +math.sin( a )*radius, y = y +math.cos( a )*radius, u = math.sin( a )/2 +0.5, v = math.cos( a )/2 +0.5 } )
|
|
end
|
|
local a = math.rad( 0 )
|
|
surface.SetMaterial( Mat ) surface.SetDrawColor( 255, 200, 25, 255*ler )
|
|
surface.DrawPoly( cir )
|
|
draw.TextShadow( {
|
|
text = math.Clamp( math.Round( self._Ler2 ), 0, 100 ).."%",
|
|
pos = { x, y },
|
|
font = "ScrapFont2",
|
|
xalign = TEXT_ALIGN_CENTER,
|
|
yalign = TEXT_ALIGN_CENTER,
|
|
color = Color( 255, 200, 25, ler*255 )
|
|
}, 1, ler*255 )
|
|
draw.TextShadow( {
|
|
text = self:GetNick(),
|
|
pos = { x, y -ler*52 },
|
|
font = "TargetID",
|
|
xalign = TEXT_ALIGN_CENTER,
|
|
yalign = TEXT_ALIGN_CENTER,
|
|
color = Color( 255, 200, 25, ler*255 )
|
|
}, 1, ler*255 )
|
|
if IsValid( self:GetOwned() ) then
|
|
draw.TextShadow( {
|
|
text = "("..self:GetOwned():Nick()..")",
|
|
pos = { x, y +ler*52 },
|
|
font = "TargetIDSmall",
|
|
xalign = TEXT_ALIGN_CENTER,
|
|
yalign = TEXT_ALIGN_CENTER,
|
|
color = Color( 255, 200, 25, ler*255 )
|
|
}, 1, ler*255 )
|
|
end
|
|
cam.End2D()
|
|
end
|
|
end
|