diff --git a/lua/autorun/sh_powerups_init.lua b/lua/autorun/sh_powerups_init.lua index 6e98c94..b34b4f0 100644 --- a/lua/autorun/sh_powerups_init.lua +++ b/lua/autorun/sh_powerups_init.lua @@ -5,7 +5,8 @@ end require( "logger" ) CFCPowerups = { - Logger = Logger( "CFC Powerups" ) + Logger = Logger( "CFC Powerups" ), + SharedHandlers = {}, -- For powerup handler classes that carry duplicate code between server and client relams } if SERVER then diff --git a/lua/entities/powerup_shotgun/cl_init.moon b/lua/entities/powerup_shotgun/cl_init.moon new file mode 100644 index 0000000..43fdd05 --- /dev/null +++ b/lua/entities/powerup_shotgun/cl_init.moon @@ -0,0 +1 @@ +include "shared.lua" diff --git a/lua/entities/powerup_shotgun/init.moon b/lua/entities/powerup_shotgun/init.moon new file mode 100644 index 0000000..d199d20 --- /dev/null +++ b/lua/entities/powerup_shotgun/init.moon @@ -0,0 +1,7 @@ +AddCSLuaFile "cl_init.lua" +AddCSLuaFile "shared.lua" +include "shared.lua" + +ENT.Base = "base_cfc_powerup" +ENT.Powerup = "powerup_shotgun" +ENT.Color = Color 75, 65, 75 diff --git a/lua/entities/powerup_shotgun/shared.moon b/lua/entities/powerup_shotgun/shared.moon new file mode 100644 index 0000000..66793d4 --- /dev/null +++ b/lua/entities/powerup_shotgun/shared.moon @@ -0,0 +1,9 @@ +ENT.Base = "base_cfc_powerup" + +ENT.Type = "anim" +ENT.PrintName = "Shotgun Powerup" +ENT.Purpose = "All guns shoot multiple bullets" +ENT.Category = "Powerups" + +ENT.Spawnable = true +ENT.AdminOnly = true diff --git a/lua/powerups/client/shotgun.moon b/lua/powerups/client/shotgun.moon new file mode 100644 index 0000000..c76a547 --- /dev/null +++ b/lua/powerups/client/shotgun.moon @@ -0,0 +1,32 @@ +import ShotgunPowerupHandler from CFCPowerups.SharedHandlers + +shotguns = {} + +removeShotgun = (ownerSteamID64) -> + shotgun = shotguns[ownerSteamID64] + return unless shotgun + + shotgun\Remove! + shotguns[ownerSteamID64] = nil + +net.Receive "CFC_Powerups-Shotgun-Start", -> + ownerSteamID64 = net.ReadString! + singleBulletsMin = net.ReadUInt 7 + singleBulletsMax = net.ReadUInt 7 + singleDamageMult = net.ReadFloat! + singleSpreadMult = net.ReadFloat! + singleSpreadAdd = net.ReadFloat! + multiBulletsMult = net.ReadFloat! + multiDamageMult = net.ReadFloat! + + removeShotgun ownerSteamID64 -- Just in case + + owner = player.GetBySteamID64 ownerSteamID64 + return unless IsValid owner + + shotguns[ownerSteamID64] = ShotgunPowerupHandler owner, singleBulletsMin, singleBulletsMax, singleDamageMult, singleSpreadMult, singleSpreadAdd, multiBulletsMult, multiDamageMult + +net.Receive "CFC_Powerups-Shotgun-Stop", -> + ownerSteamID64 = net.ReadString! + + removeShotgun ownerSteamID64 diff --git a/lua/powerups/config/sv_config.moon b/lua/powerups/config/sv_config.moon index b213d7a..1e5ea11 100644 --- a/lua/powerups/config/sv_config.moon +++ b/lua/powerups/config/sv_config.moon @@ -263,6 +263,39 @@ helpText: "What sound should play when the bolt acquires a target?" -- ======================================================================= +-- Shotgun ================================================================ +"cfc_powerups_shotgun_duration": + default: 300 + helpText: "How long does the Shotgun powerup last, in seconds" + +"cfc_powerups_shotgun_single_bullets_min": + default: 6 + helpText: "Minimum number of bullets for single-bullet weapons" + +"cfc_powerups_shotgun_single_bullets_max": + default: 8 + helpText: "Maximum number of bullets for single-bullet weapons" + +"cfc_powerups_shotgun_single_damage_multiplier": + default: 0.5 + helpText: "Damage multiplier for single-bullet weapons" + +"cfc_powerups_shotgun_single_spread_multiplier": + default: 1.25 + helpText: "Spread multiplier for single-bullet weapons" + +"cfc_powerups_shotgun_single_spread_add": + default: 0.04 + helpText: "Spread additive for single-bullet weapons" + +"cfc_powerups_shotgun_multi_bullets_multiplier": + default: 1.5 + helpText: "Multiplier against the number of bullets for multi-bullet weapons" + +"cfc_powerups_shotgun_multi_damage_multiplier": + default: 1.5 + helpText: "Damage multiplier for multi-bullet weapons" + -- Phoenix ============================================================= "cfc_powerups_phoenix_uses": default: 1 diff --git a/lua/powerups/loaders/cl_powerups_init.moon b/lua/powerups/loaders/cl_powerups_init.moon index 1a3abf6..a458322 100644 --- a/lua/powerups/loaders/cl_powerups_init.moon +++ b/lua/powerups/loaders/cl_powerups_init.moon @@ -1,4 +1,7 @@ +include "powerups/shared/shotgun.lua" + include "powerups/client/halos.lua" include "powerups/client/flux_shield.lua" include "powerups/client/thorns.lua" +include "powerups/client/shotgun.lua" include "powerups/client/curse.lua" diff --git a/lua/powerups/loaders/sv_powerups_init.moon b/lua/powerups/loaders/sv_powerups_init.moon index 24dc0db..58db559 100644 --- a/lua/powerups/loaders/sv_powerups_init.moon +++ b/lua/powerups/loaders/sv_powerups_init.moon @@ -3,6 +3,8 @@ include "utils/server/sv_config_manager.lua" include "utils/server/sv_powerups_manager.lua" include "utils/server/sv_powerups_spawner.lua" +include "powerups/shared/shotgun.lua" + include "powerups/server/base.lua" include "powerups/server/cluster_combine_ball.lua" include "powerups/server/regen.lua" @@ -15,13 +17,17 @@ include "powerups/server/grenadier.lua" include "powerups/server/flux_shield.lua" include "powerups/server/thorns.lua" include "powerups/server/magnetic_crossbow.lua" +include "powerups/server/shotgun.lua" include "powerups/server/phoenix.lua" include "powerups/server/super_speed.lua" include "powerups/server/curse.lua" +AddCSLuaFile "powerups/shared/shotgun.lua" + AddCSLuaFile "powerups/client/halos.lua" AddCSLuaFile "powerups/client/flux_shield.lua" AddCSLuaFile "powerups/client/thorns.lua" +AddCSLuaFile "powerups/client/shotgun.lua" AddCSLuaFile "powerups/client/curse.lua" resource.AddWorkshop "3114946264" diff --git a/lua/powerups/server/shotgun.moon b/lua/powerups/server/shotgun.moon new file mode 100644 index 0000000..4b9cfea --- /dev/null +++ b/lua/powerups/server/shotgun.moon @@ -0,0 +1,75 @@ +{get: getConf} = CFCPowerups.Config + +import ShotgunPowerupHandler from CFCPowerups.SharedHandlers + +util.AddNetworkString "CFC_Powerups-Shotgun-Start" +util.AddNetworkString "CFC_Powerups-Shotgun-Stop" + +export ShotgunPowerup +class ShotgunPowerup extends BasePowerup + @powerupID: "powerup_shotgun" + + @powerupWeights: + tier1: 1 + tier2: 1 + tier3: 1 + tier4: 1 + + new: (ply) => + super ply + + @ownerSteamID64 = @owner\SteamID64! + + @duration = getConf "shotgun_duration" + @singleBulletsMin = getConf "shotgun_single_bullets_min" + @singleBulletsMax = getConf "shotgun_single_bullets_max" + @singleDamageMult = getConf "shotgun_single_damage_multiplier" + @singleSpreadMult = getConf "shotgun_single_spread_multiplier" + @singleSpreadAdd = getConf "shotgun_single_spread_add" + @multiBulletsMult = getConf "shotgun_multi_bullets_multiplier" + @multiDamageMult = getConf "shotgun_multi_damage_multiplier" + + @timerName = "CFC-Powerups_Shotgun-#{@ownerSteamID64}" + @handler = ShotgunPowerupHandler ply, @singleBulletsMin, @singleBulletsMax, @singleDamageMult, @singleSpreadMult, @singleSpreadAdd, @multiBulletsMult, @multiDamageMult + + @ApplyEffect! + + ApplyEffect: => + super self + + timer.Create @timerName, @duration, 1, -> @Remove! + + -- Need to network to all clients so they can predict the new bullets correctly. + -- However, this isn't using NW or NW2, so players who join after won't see it correctly. + -- But that is preferable to using NW/NW2 slots, a permanent EFB hook listener, and needing to re-check the convars on client. + net.Start "CFC_Powerups-Shotgun-Start" + net.WriteString @ownerSteamID64 + net.WriteUInt @singleBulletsMin, 7 + net.WriteUInt @singleBulletsMax, 7 + net.WriteFloat @singleDamageMult + net.WriteFloat @singleSpreadMult + net.WriteFloat @singleSpreadAdd + net.WriteFloat @multiBulletsMult + net.WriteFloat @multiDamageMult + net.Broadcast! + + @owner\ChatPrint "You've gained #{@duration} seconds of the Shotgun powerup" + + Remove: => + super self + + timer.Remove @timerName + + @handler\Remove! + @handler = nil + + net.Start "CFC_Powerups-Shotgun-Stop" + net.WriteString @ownerSteamID64 + net.Broadcast! + + return unless IsValid @owner + + @owner\ChatPrint "You've lost the Shotgun powerup" + + -- TODO: Should the PowerupManager do this? + @owner.Powerups[@@powerupID] = nil diff --git a/lua/powerups/shared/shotgun.moon b/lua/powerups/shared/shotgun.moon new file mode 100644 index 0000000..e4af567 --- /dev/null +++ b/lua/powerups/shared/shotgun.moon @@ -0,0 +1,122 @@ + +-- Some addons shoot multiple separate bullets instead of using the Num param. +-- Put them here so they get treated properly, with the value being a function or string to get the intended bullet count. +FORCE_MULTI_CLASSES = { -- Direct class lookup + +} +FORCE_MULTI_CLASS_STARTS = { -- Anything that starts with these strings + "cw_": "Shots" +} + +forceMultiClassCache = {} +lastCommandNum = nil +commandSeedIncr = 0 + +isForcedMulti = (wep) -> + wepClass = wep\GetClass! + cached = forceMultiClassCache[wepClass] + return cached if cached ~= nil + + getter = FORCE_MULTI_CLASSES[wepClass] + + if not getter + for start, newGetter in *FORCE_MULTI_CLASS_STARTS + continue unless string.StartsWith wepClass, start + + getter = newGetter + break + + if not getter + forceMultiClassCache[wepClass] = false + return false + + -- Need to also check the gun's listed bullet count, to see if it actually shoots multiple bullets or not. + num = ( type getter == "function" ) and ( getter wep ) or wep[getter] or 1 + forcedMulti = num > 1 + + forceMultiClassCache[wepClass] = forcedMulti + return forcedMulti + +-- Handles the shared logic of modifying bullets for the shotgun powerup. +class ShotgunPowerupHandler + new: (owner, singleBulletsMin, singleBulletsMax, singleDamageMult, singleSpreadMult, singleSpreadAdd, multiBulletsMult, multiDamageMult) => + @owner = owner + @singleBulletsMin = singleBulletsMin + @singleBulletsMax = singleBulletsMax + @singleDamageMult = singleDamageMult + @singleSpreadMult = singleSpreadMult + @singleSpreadAdd = singleSpreadAdd + @multiBulletsMult = multiBulletsMult + @multiDamageMult = multiDamageMult + + @ownerSteamID64 = @owner\SteamID64! + @hookName = "CFC-Powerups_Shotgun-#{@ownerSteamID64}" + + @ApplyEffect! + + BulletWatcher: => + (ent, bullet) -> + return unless ent == @owner + + num = bullet.Num + + -- Multi-bullet gun + if num > 1 + bullet.Num = math.ceil bullet.Num * @multiBulletsMult + bullet.Damage = bullet.Damage * @multiDamageMult + return + + wep = ent\GetActiveWeapon! + return unless IsValid wep -- Shooting bullets with your mind? Nonsense! + + commandNum = lastCommandNum + + -- Bullets on players should always be fired in a predicted hook, but for just in case... + if GetPredictionPlayer! == ent + commandNum = ent\GetCurrentCommand!\CommandNumber! + + -- If multiple bullets are fired in the same command (i.e. with force-multi weapons), increment the seed + if commandNum == lastCommandNum + commandSeedIncr = commandSeedIncr + 1 + else + lastCommandNum = commandNum + commandSeedIncr = 0 + wep\EmitSound "weapons/shotgun/shotgun_fire6.wav", 75, 100, 1, CHAN_WEAPON -- Play a sound to make the powerup more noticeable, but only once per command + + seed = ent\EntIndex! .. commandNum .. commandSeedIncr + + -- Single-bullet gun + if not isForcedMulti wep + bullet.Num = util.SharedRandom seed, @singleBulletsMin, @singleBulletsMax + bullet.Damage = bullet.Damage * @singleDamageMult + + spread = bullet.Spread + spreadMult = @singleSpreadMult + spreadAdd = @singleSpreadAdd + + spread.x = spread.x * spreadMult + spreadAdd + spread.y = spread.y * spreadMult + spreadAdd + + return + + -- Forced-multi gun + bullet.Damage = bullet.Damage * @multiDamageMult + + multiBulletsMult = @multiBulletsMult + newNum = math.floor multiBulletsMult + leftover = multiBulletsMult - newNum + + if leftover > 0 + -- Leftover is used as a chance to add another bullet + if (util.SharedRandom seed, 0, 1) < leftover + newNum = newNum + 1 + + bullet.Num = newNum + + ApplyEffect: => + hook.Add "EntityFireBullets", @hookName, @BulletWatcher! + + Remove: => + hook.Remove "EntityFireBullets", @hookName + +CFCPowerups.SharedHandlers.ShotgunPowerupHandler = ShotgunPowerupHandler diff --git a/materials/entities/powerup_shotgun.png b/materials/entities/powerup_shotgun.png new file mode 100644 index 0000000..4e44799 Binary files /dev/null and b/materials/entities/powerup_shotgun.png differ