THE FUKIN SECONDARY FIRE FOR THE TERMS#19
Conversation
they use it when in danger :)
|
this is probably very ehhhh code |
|
the AR2 ball was the most annoying to get working properly |
StrawWagen
left a comment
There was a problem hiding this comment.
Better than no secondary fire support but not ready yet, and using some shortcuts that seriously compromise performance
| -- Specific logic for Half-Life 2 weapons | ||
| if class == "weapon_smg1" then | ||
| -- SMG Grenade: Good for mid-range. Don't use too close (self damage) or too far. | ||
| -- Increased chance in emergency | ||
| if distSq > (300*300) and distSq < (1500*1500) then | ||
| return math.random(1, 100) <= 20 -- 20% chance in emergency | ||
| end | ||
| elseif class == "weapon_ar2" then | ||
| -- Energy Ball: Good for long range and flushing enemies. | ||
| if distSq > (400*400) and distSq < (2000*2000) then | ||
| return math.random(1, 100) <= 15 -- 15% chance in emergency | ||
| end | ||
| elseif class == "weapon_shotgun" then | ||
| -- Double Barrel: Devastating at close range. | ||
| if distSq < (300*300) then | ||
| return math.random(1, 100) <= 50 -- 50% chance when close and in danger | ||
| end | ||
| end |
There was a problem hiding this comment.
this should ask the actual luawep entity for a method
eg, luawep:IsCloseEnoughToSecondaryFire
| -- START TRUE SECONDARY FIRE SUPPORT | ||
| -- Check if we should override primary fire with secondary fire | ||
| if not self:IsControlledByPlayer() and self:CanWeaponSecondaryAttack() and self:AI_ShouldUseSecondary(wep) then | ||
| self:WeaponSecondaryAttack() | ||
|
|
||
| -- Add a small delay after secondary fire before we can primary fire again | ||
| -- This prevents instant double attacks and mimics recoil/recovery | ||
| local delay = 1.0 | ||
| if wep:GetClass() == "weapon_shotgun_term" or wep:GetClass() == "weapon_shotgun" then | ||
| delay = 1.5 -- Double barrel takes longer | ||
| end | ||
|
|
||
| self.m_WeaponData.Primary.NextShootTime = CurTime() + delay | ||
| return true, "Fired_Secondary_Override" | ||
| end | ||
| -- END TRUE SECONDARY FIRE SUPPORT |
There was a problem hiding this comment.
Put this in the shooting_handler task
| myTbl = myTbl or entMeta.GetTable( self ) | ||
| if not myTbl then return false end -- Should not happen if self is valid, but safety first | ||
|
|
||
| wepsTbl = wepsTbl or entMeta.GetTable( wep ) -- LOGIC FIX: Use 'wep' not 'self' |
There was a problem hiding this comment.
AI slop comment, should be removed, doesn't make code more readable
| if not IsValid( wep ) then boring( wep ) return end | ||
| wepsTbl = wepsTbl or entMeta.GetTable( self ) | ||
|
|
||
| -- SAFETY FIX: Initialize tables early to prevent nil indexing later |
There was a problem hiding this comment.
AI slop comment, this is actually an optimisation to reduce _index calls
| -- Fix for projectile ownership and self-collision (SMG Grenade) | ||
| hook.Add("OnEntityCreated", "Terminator_ProjectileFixes", function(ent) | ||
| -- Wait a tick for initialization | ||
| timer.Simple(0, function() | ||
| if not IsValid(ent) then return end | ||
|
|
||
| local class = ent:GetClass() | ||
|
|
||
| -- Detect common secondary projectiles | ||
| if class == "grenade_ar2" or class == "prop_combine_ball" or class == "rpg_missile" or class == "obj_vj_grenade" then | ||
|
|
||
| local owner = ent:GetOwner() | ||
| local bot = nil | ||
|
|
||
| -- Scenario A: Owner is set to the Weapon (common in scripted weapons) | ||
| if IsValid(owner) and owner:IsWeapon() then | ||
| local parent = owner:GetOwner() | ||
| if IsValid(parent) and parent.isTerminatorHunterBased then | ||
| bot = parent | ||
| end | ||
| -- Scenario B: Owner is already the Bot (ideal, but check collision) | ||
| elseif IsValid(owner) and owner.isTerminatorHunterBased then | ||
| bot = owner | ||
| -- Scenario C: Owner is nil. Check strict proximity to a firing Terminator. | ||
| elseif not IsValid(owner) then | ||
| local pos = ent:GetPos() | ||
| for _, v in ipairs(ents.FindInSphere(pos, 70)) do | ||
| if v.isTerminatorHunterBased and v:GetActiveWeapon():GetLastShootTime() > CurTime() - 0.5 then | ||
| bot = v | ||
| break | ||
| end | ||
| end | ||
| end | ||
|
|
||
| if IsValid(bot) then | ||
| -- Ensure kill credit goes to the bot, not the weapon or nil | ||
| ent:SetOwner(bot) | ||
| ent.Owner = bot -- Some SWEPs check this Lua field | ||
|
|
||
| -- Extra fix for Combine Ball logic in engine | ||
| if class == "prop_combine_ball" then | ||
| -- Trigger the engine input to set owner, which handles internal dissolved pointers | ||
| ent:Fire("SetOwner", "!activator", 0, bot) | ||
| end | ||
|
|
||
| -- Prevent SMG grenade (and others) from exploding instantly on the bot's face | ||
| -- We use NoCollide to ensure the physics engine ignores the bot for this projectile | ||
| constraint.NoCollide(ent, bot, 0, 0) | ||
|
|
||
| -- Specific fix for grenade_ar2 which is very sensitive | ||
| if class == "grenade_ar2" then | ||
| local phys = ent:GetPhysicsObject() | ||
| if IsValid(phys) then | ||
| -- Ensure it has forward velocity so it clears the bounding box | ||
| local vel = phys:GetVelocity() | ||
| local aim = bot:GetAimVector() | ||
|
|
||
| -- If velocity is too low or weird, force it forward | ||
| if vel:Length() < 500 then | ||
| phys:SetVelocity(aim * 1000) | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end | ||
| end) | ||
| end) |
There was a problem hiding this comment.
This should be handled inside every weapon override, the entities are already available to modify and mess with there. it shouldn't be a monolith inside this expensive hook.
| -- Hook to forcibly attribute damage from these projectiles to the Terminator | ||
| -- This catches cases where the engine resets the attacker or uses the inflictor as attacker | ||
| hook.Add("EntityTakeDamage", "Terminator_ProjectileDamageCredit", function(target, dmginfo) | ||
| local inflictor = dmginfo:GetInflictor() | ||
| if not IsValid(inflictor) then return end | ||
|
|
||
| local class = inflictor:GetClass() | ||
| if class == "prop_combine_ball" or class == "grenade_ar2" then | ||
| local owner = inflictor:GetOwner() | ||
|
|
||
| -- If the projectile is owned by a terminator, ensure the damage is credited to them | ||
| if IsValid(owner) and owner.isTerminatorHunterBased then | ||
| dmginfo:SetAttacker(owner) | ||
| end | ||
| end | ||
| end) |
There was a problem hiding this comment.
Kinda fair, but it should probably be in each weapon's folder.
also try using the "entity as hook name" trick for it too because this is an expensive hook that doesn't need to be active all the time
eg, hook.Add( "EntityTakeDamage", ar2BallEntity,
| -- Generic fallback for scripted weapons that have secondary ammo | ||
| if wep:GetMaxClip2() > 0 and wep:Clip2() > 0 then | ||
| return math.random(1, 100) <= 10 | ||
| end |
There was a problem hiding this comment.
Good fallback, try testing it on multiple ( 10+ ) sweps though, sweps are so stupid
im finally able to do stuff again after being busy with personal stuff.