Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grenades! #68

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
07a2977
Util functions for explosions with damage callbacks
legokidlogan Sep 24, 2024
7a012e5
Fix bugs with holstering throwables too early
legokidlogan Sep 25, 2024
36fdca5
Create the discombob and impact discombob
legokidlogan Sep 25, 2024
7c2e597
Make grenades collide with players
legokidlogan Sep 25, 2024
ec60ae9
Sorse moment
legokidlogan Sep 25, 2024
a615beb
Create the cluster grenade
legokidlogan Sep 25, 2024
f18ca29
Remove leftover test code
legokidlogan Sep 25, 2024
29697e6
Account for gmod not packing the frag grenade's world model material
legokidlogan Sep 25, 2024
3d9f5a8
Use different materials for the different grenades
legokidlogan Sep 25, 2024
2933b50
Add killicons and spawnmenu icons
legokidlogan Sep 26, 2024
ef9cfe9
Change display names
legokidlogan Sep 26, 2024
1b18373
Change display names
legokidlogan Sep 26, 2024
f4f3c29
Change display names
legokidlogan Sep 26, 2024
3c3e399
Create curse grenade
legokidlogan Sep 26, 2024
579b1f0
Set holdtype on deploy
legokidlogan Sep 26, 2024
6eb9fc7
Use a better var name
legokidlogan Sep 26, 2024
a2b2128
Add more options to cluster grenade settings
legokidlogan Sep 26, 2024
dcd6f53
Change mid-air split to a toggle on pressing r
legokidlogan Sep 26, 2024
457e4fd
Tweak cluster grenade balance
legokidlogan Sep 26, 2024
6e0d88b
R
legokidlogan Sep 26, 2024
8f74cc1
Clarity
legokidlogan Sep 26, 2024
7556c5e
Create the super cluster grenade
legokidlogan Sep 26, 2024
32f9f9a
Change explosion pitch for super cluster grenades
legokidlogan Sep 26, 2024
ded002a
Don't set timer if split limit is reached
legokidlogan Sep 26, 2024
595c0cf
Create anti-gravity grenade
legokidlogan Sep 26, 2024
325bd57
Allow for throwable classes to have extra cooldowns
legokidlogan Sep 27, 2024
84808f0
Use a lingering bubble for the antigrav grenade
legokidlogan Sep 27, 2024
b60ef3b
Tweak antigrav grenade settings
legokidlogan Sep 27, 2024
cd22076
More antigrav visual/auditory effects
legokidlogan Sep 27, 2024
4910d02
Split into cluster grenade and charged cluster grenade
legokidlogan Sep 27, 2024
07f76dd
Tweak charge gap
legokidlogan Sep 27, 2024
7e8fc48
Reduce discombob strength
legokidlogan Sep 27, 2024
99e4044
Further nerf other player knockback of impact discombob
legokidlogan Sep 27, 2024
2be545c
Tweak curse blacklist
legokidlogan Sep 27, 2024
51993a0
Remove impact discombob
legokidlogan Sep 27, 2024
6ab7c9b
Change print names to group grenades together
legokidlogan Sep 27, 2024
5713143
Ignore dead players, gmod apparently doesn't
legokidlogan Sep 28, 2024
0d0bdad
Disable ACF damage
legokidlogan Sep 28, 2024
32033fd
Change sound
legokidlogan Sep 28, 2024
e741724
Change sound
legokidlogan Sep 28, 2024
2275791
Buff
legokidlogan Sep 28, 2024
e20ab06
Shorten antigrav fuse on first impact
legokidlogan Sep 30, 2024
4c7f0e2
Buff antigrav grenade
legokidlogan Sep 30, 2024
9195e71
Return early if no fuse set
legokidlogan Sep 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lua/autorun/client/cfc_pvp_weapons_killicons.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
local icol = Color( 255, 255, 255, 255 )
local icolOrange = Color( 255, 80, 0, 255 )

killicon.Add( "cfc_bonk_shotgun", "vgui/hud/cfc_bonk_shotgun", icol )
killicon.Add( "cfc_trash_blaster", "vgui/hud/cfc_trash_blaster", icol ) -- Sadly won't appear since the kills will attribute to generic prop kill instead
killicon.Add( "cfc_ion_cannon", "vgui/hud/cfc_ion_cannon", icol )

killicon.Add( "cfc_simple_ent_cluster_grenade", "vgui/hud/cfc_simple_ent_cluster_grenade", icolOrange )
5 changes: 5 additions & 0 deletions lua/autorun/server/cfc_pvp_weapons_init.lua
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
resource.AddWorkshop( "3097864891" )


if SERVER then
include( "cfc_pvp_weapons/server/utils.lua" )
end
57 changes: 57 additions & 0 deletions lua/cfc_pvp_weapons/server/utils.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
CFCPvPWeapons = CFCPvPWeapons or {}


--[[
- util.BlastDamageInfo(), with damage callbacks.
- Do NOT call any damage-inflicting functions in the callbacks, it will cause feedback loops and/or misattribute the callback.
- If you need to inflict damage from the callbacks, use a timer, entity with a fuse, etc.

etdCallback: (optional) (function)
- A callback function that listens during EntityTakeDamage with HOOK_LOW.
- Whatever is returned by the function will be returned in the hook, if you need to block the normal damage event.
petdCallback: (optional) (function)
- A callback function that listens during PostEntityTakeDamage.
--]]
Comment on lines +4 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--[[
- util.BlastDamageInfo(), with damage callbacks.
- Do NOT call any damage-inflicting functions in the callbacks, it will cause feedback loops and/or misattribute the callback.
- If you need to inflict damage from the callbacks, use a timer, entity with a fuse, etc.
etdCallback: (optional) (function)
- A callback function that listens during EntityTakeDamage with HOOK_LOW.
- Whatever is returned by the function will be returned in the hook, if you need to block the normal damage event.
petdCallback: (optional) (function)
- A callback function that listens during PostEntityTakeDamage.
--]]
--- Applies blast damage and optionally hooks into damage events.
---
--- @param dmgInfo CTakeDamageInfo The damage info object containing damage details.
--- @param pos Vector The position where the blast damage originates.
--- @param radius number The radius of the blast damage.
--- @param etdCallback function? A callback function for the `EntityTakeDamage` hook with `HOOK_LOW` priority.
--- If the callback returns a value, it will be used in the hook, which can be used to block the normal damage event.
--- Do NOT call any damage-inflicting functions in this callback to avoid feedback loops or misattribution.
--- @param petdCallback? function A callback function for the `PostEntityTakeDamage` hook.
--- Similar to `etdCallback`, but triggered after the entity takes damage.
---
--- **Note:** If you need to inflict additional damage from the callback, use a timer, entity with a fuse, or similar workaround.

function CFCPvPWeapons.BlastDamageInfo( dmgInfo, pos, radius, etdCallback, petdCallback )
if etdCallback then
hook.Add( "EntityTakeDamage", "CFC_PvPWeapons_BlastDamageInfo", etdCallback, HOOK_LOW )
end

if petdCallback then
hook.Add( "PostEntityTakeDamage", "CFC_PvPWeapons_BlastDamageInfo", petdCallback )
end

util.BlastDamageInfo( dmgInfo, pos, radius )

if etdCallback then
hook.Remove( "EntityTakeDamage", "CFC_PvPWeapons_BlastDamageInfo" )
end

if petdCallback then
hook.Remove( "PostEntityTakeDamage", "CFC_PvPWeapons_BlastDamageInfo" )
end
end

-- Similar to CFCPvPWeapons.BlastDamageInfo(), but for util.BlastDamage().
function CFCPvPWeapons.BlastDamage( inflictor, attacker, pos, radius, damage, etdCallback, petdCallback )
local dmgInfo = DamageInfo()
dmgInfo:SetInflictor( inflictor )
dmgInfo:SetAttacker( attacker )
dmgInfo:SetDamage( damage )

CFCPvPWeapons.BlastDamageInfo( dmgInfo, pos, radius, etdCallback, petdCallback )
end

-- Spread is on 0-180 scale, output will be a unit vector.
function CFCPvPWeapons.SpreadDir( dir, pitchSpread, yawSpread )
yawSpread = yawSpread or pitchSpread

local ang = dir:Angle()
local right = ang:Right()
local up = ang:Up()

ang:RotateAroundAxis( right, math.Rand( -pitchSpread, pitchSpread ) )
ang:RotateAroundAxis( up, math.Rand( -yawSpread, yawSpread ) )

return ang:Forward()
end
172 changes: 172 additions & 0 deletions lua/entities/cfc_simple_ent_antigrav_grenade.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
AddCSLuaFile()

DEFINE_BASECLASS( "cfc_simple_ent_bubble_grenade" )

ENT.Base = "cfc_simple_ent_bubble_grenade"

ENT.Model = Model( "models/weapons/w_eq_fraggrenade.mdl" )

ENT.BubbleRadius = 250
ENT.BubbleDuration = 7
ENT.BubbleGrowDuration = 0.25
ENT.BubbleShrinkDuration = 0.25
ENT.EffectLingerOutsideBubble = 0

ENT.GravityMult = -2.5
ENT.PushStrength = 260 -- Pushes the player up to get them off the ground.
ENT.FuseOnImpact = 1 -- On the first impact, shortens the remaining fuse time to this.


function ENT:SetTimer( delay )
BaseClass.SetTimer( self, delay )

self.Beep = CurTime()
end

function ENT:Initialize()
BaseClass.Initialize( self )

self:SetMaterial( "models/weapons/w_models/cfc_frag_grenade/frag_grenade_antigrav" )

local fuseOnImpact = self.FuseOnImpact

if SERVER and fuseOnImpact then
timer.Simple( 0, function()
if not IsValid( self ) then return end

local fuseShortened = false

function self:PhysicsCollide()
local fuseLeft = self._explodeDelay
if not fuseLeft then return end
if fuseShortened then return end

fuseShortened = true

if fuseLeft > fuseOnImpact then
self:SetTimer( fuseOnImpact )
end
end
end )
end
Comment on lines +33 to +51
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this actually need a timer?

Suggested change
if SERVER and fuseOnImpact then
timer.Simple( 0, function()
if not IsValid( self ) then return end
local fuseShortened = false
function self:PhysicsCollide()
local fuseLeft = self._explodeDelay
if not fuseLeft then return end
if fuseShortened then return end
fuseShortened = true
if fuseLeft > fuseOnImpact then
self:SetTimer( fuseOnImpact )
end
end
end )
end
if not SERVER then return end
if not fuseOnImpact then return end
timer.Simple( 0, function()
if not IsValid( self ) then return end
local fuseShortened = false
function self:PhysicsCollide()
local fuseLeft = self._explodeDelay
if not fuseLeft then return end
if fuseShortened then return end
fuseShortened = true
if fuseLeft > fuseOnImpact then
self:SetTimer( fuseOnImpact )
end
end
end )

end

function ENT:CreateBubble()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Could you localize angles/colors in here?

local pos = self:WorldSpaceCenter()
local bubble = ents.Create( "cfc_simple_ent_bubble" )
bubble:SetPos( pos )
bubble:SetAngles( Angle( 0, 0, 0 ) )
bubble:SetMaterial( "models/props_combine/portalball001_sheet" )
bubble:Spawn()
bubble:SetBubbleRadius( self.BubbleRadius )

local cosmeticBubbles = {}

local bubble2 = ents.Create( "cfc_simple_ent_bubble" )
bubble2:SetPos( pos )
bubble2:SetAngles( Angle( 0, 0, 0 ) )
bubble2:SetMaterial( "sprites/heatwave" )
bubble2:Spawn()
bubble2:SetBubbleRadius( self.BubbleRadius )
bubble2:SetColor( Color( 255, 255, 255, 100 ) )
bubble2:SetRenderMode( RENDERMODE_TRANSCOLOR )
bubble2._bubbleScaleMult = 1
table.insert( cosmeticBubbles, bubble2 )

local bubble3 = ents.Create( "cfc_simple_ent_bubble" )
bubble3:SetPos( pos )
bubble3:SetAngles( Angle( 0, 0, 0 ) )
bubble3:SetMaterial( "sprites/heatwave" )
bubble3:Spawn()
bubble3:SetBubbleRadius( self.BubbleRadius )
bubble3:SetColor( Color( 255, 255, 255, 100 ) )
bubble3:SetRenderMode( RENDERMODE_TRANSCOLOR )
bubble3._bubbleScaleMult = -1
table.insert( cosmeticBubbles, bubble3 )

sound.Play( "ambient/levels/labs/electric_explosion1.wav", pos, 90, 110 )
sound.Play( "ambient/fire/ignite.wav", pos, 90, 75, 0.5 )
sound.Play( "ambient/machines/machine1_hit2.wav", pos, 90, 100 )

return bubble, cosmeticBubbles
end

function ENT:BubbleStartTouch( ent )
if not ent:IsPlayer() then return end
if not ent:Alive() then return end

-- Check if we're allowed to affect the player (there might be a build/pvp system, etc)
local allowed = false

hook.Add( "EntityTakeDamage", "CFC_PvPWeapons_AntiGravityGrenade_CheckIfDamageIsAllowed", function()
allowed = true

return true
end, HOOK_LOW )

local dmgInfo = DamageInfo()
dmgInfo:SetAttacker( self:GetOwner() )
dmgInfo:SetInflictor( self )
dmgInfo:SetDamage( 100 )
dmgInfo:SetDamageType( ent:InVehicle() and DMG_VEHICLE or DMG_GENERIC )

ent:TakeDamageInfo( dmgInfo )
hook.Remove( "EntityTakeDamage", "CFC_PvPWeapons_AntiGravityGrenade_CheckIfDamageIsAllowed" )

if not allowed then return end

-- Apply the effect
ent:SetGravity( self.GravityMult )

if ent:IsOnGround() then
ent:SetVelocity( Vector( 0, 0, self.PushStrength ) )
end

ent._cfcPvPWeapons_AntiGravityGrenade = self

local rf = RecipientFilter()
rf:AddPlayer( ent )

sound.Play( "ambient/machines/machine1_hit2.wav", ent:EyePos(), 75, 120 )
util.ScreenShake( ent:EyePos(), 3, 5, 1.5, 500, true, ent )
Comment on lines +127 to +131
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you forget to use the recipientfilter here?


return true
end
Comment on lines +94 to +134
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is going to work like you think it will.

A much simpler and more reliable option:

  • Simply deal the damage here
  • Have a new PostEntityTakeDamage hook that checks for cfc_simple_ent_antigrav_grenade as the inflictor, and that took == true, and then run the second part of the effect

I believe the only difference will be that the bubbles will pop on non-pvpers, but I think that's fine


function ENT:BubbleTouch( ent )
if ent:IsOnGround() then
ent:SetVelocity( Vector( 0, 0, self.PushStrength ) )
end
Comment on lines +137 to +139
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ent:IsOnGround() then
ent:SetVelocity( Vector( 0, 0, self.PushStrength ) )
end
if not ent:IsOnGround() then return end
ent:SetVelocity( Vector( 0, 0, self.PushStrength ) )

end

function ENT:BubbleEndTouch()
end

function ENT:BubbleEndEffect( ent )
if not ent:IsPlayer() then return end

-- Prevent grenades from resetting gravity early if the player quickly enters another one.
local otherGrenade = ent._cfcPvPWeapons_AntiGravityGrenade
if otherGrenade ~= self and IsValid( otherGrenade ) then return end

ent:SetGravity( 1 )
ent._cfcPvPWeapons_AntiGravityGrenade = nil
end

function ENT:Think()
if SERVER and self.Beep and self.Beep <= CurTime() then
self:EmitSound( "npc/scanner/combat_scan4.wav", 75, 120 )

local time = 1

if self._explodeTime and self._explodeTime - CurTime() <= 1.5 then
time = 0.3
end

self.Beep = CurTime() + time
end
Comment on lines +157 to +167
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move this to a ENT:Beep() function that handles the rate limiting and so forth


BaseClass.Think( self )

return true
end
39 changes: 39 additions & 0 deletions lua/entities/cfc_simple_ent_bubble.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
AddCSLuaFile()

ENT.Base = "base_anim"
ENT.Type = "anim"

ENT.AutomaticFrameAdvance = true

ENT.Model = Model( "models/cfc_pvp_weapons/bubble.mdl" )


function ENT:SetupDataTables()
self:NetworkVar( "Float", 0, "BubbleRadius" )
end

function ENT:Initialize()
self:SetModel( self.Model )
self:DrawShadow( false )

if CLIENT then
local radius = self:GetBubbleRadius()
self:SetRenderBounds( Vector( -radius, -radius, -radius ), Vector( radius, radius, radius ) )

self:NetworkVarNotify( "BubbleRadius", function( ent, _, _, new )
ent:SetRenderBounds( Vector( -new, -new, -new ), Vector( new, new, new ) )
end )
end
end

function ENT:SetUpPhysics()
self:PhysicsInit( SOLID_VPHYSICS )
self:SetMoveType( MOVETYPE_VPHYSICS )
self:SetSolid( SOLID_VPHYSICS )
self:SetNotSolid( true )
self:GetPhysicsObject():EnableMotion( false )
end

function ENT:ACF_PreDamage()
return false
end
Loading