function bot_SoldierChargeBannerFix(condition, caller, activator) caller.m_flChargeMeter = 50 activator.m_flChargeMeter = 50 end --Script made by Therealscroob/Crilly, this script's goal is to get blast soldiers with the reserve shooter to pull out their --reserve shooter to attack targets airborne targets local function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end function ReserveCombo(_, activator) local callbacks = {} local check local terminated = false local secondary = activator:GetPlayerItemBySlot(1) local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not IsValid(secondary) then terminate() return end --Find all players within 1000 units of the activator, may be decreased due to how low the reserve shooter's damage is at range --this would be a nice base for a potential master AI script. local botLocation = activator:GetAbsOrigin() local sphereResults = ents.FindInSphere(botLocation, 1000) local filteredSphereResults = {} local lastEntry if sphereResults then for _, entity in pairs(sphereResults) do if entity:IsPlayer() and entity.m_iTeamNum ~= activator.m_iTeamNum and entity ~= lastEntry then if entity:InCond(81) or entity:InCond(98) or entity:InCond(99) or entity:InCond(125)then if not entity:InCond(4) and not entity:InCond(3) and not entity:InCond(66) then --so spies don't get assblasted table.insert(filteredSphereResults, entity) lastEntry = entity end end end end --PrintTable(filteredSphereResults) if filteredSphereResults and lastEntry then activator:WeaponSwitchSlot(1) secondary:SetAttributeValue("disable weapon switch", 1) --This is taken from build_ally_bot.lua, by royal. Mince was thanked in the original comment that appeared with this. local targetAngles = (lastEntry:GetAbsOrigin() - (activator:GetAbsOrigin() + Vector(0,0,activator["m_vecViewOffset[2]"]))):ToAngles() targetAngles = Vector(targetAngles[1], targetAngles[2], 0) activator:SnapEyeAngles(targetAngles) activator:RunScriptCode("activator.PressFireButton(0.01)", activator) else secondary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end else return end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end --Sawed down version of bot_monochrome_logic.lua, Here so his burst shotgun logic can be used on smaller robots. --Legacy functions, PaleBurstLogicOnAttack is the more optimized, better version function PaleBurstLogic(_, activator) local PASSIVE_RELOAD_SPEED_FACTOR = 0.8 local primary = activator:GetPlayerItemBySlot(0) local secondary = activator:GetPlayerItemBySlot(1) local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusAtomic = primary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local maxClip = (4 * clipBonusMult) + clipBonusAtomic local reloadDuration = ((((maxClip - 1) * 0.8) + 0.92) * primary:GetAttributeValueByClass("fast_reload", 1)) * PASSIVE_RELOAD_SPEED_FACTOR; local callbacks = {} local check local terminated = false local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end if primary ~= nil then if primary.m_iClip1 == 0 then activator:WeaponSwitchSlot(1) secondary:SetAttributeValue("disable weapon switch", 1) primary.m_iClip1 = maxClip if activator.m_hActiveWeapon ~= primary then timer.Simple(reloadDuration, function() secondary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end, 1) end end end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end function PaleBurstLogicMangler(_, activator) local PASSIVE_RELOAD_SPEED_FACTOR = 0.8 local primary = activator:GetPlayerItemBySlot(0) local secondary = activator:GetPlayerItemBySlot(1) local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusAtomic = primary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local maxClip = (4 * clipBonusMult) + clipBonusAtomic local reloadDuration = ((((maxClip - 1) * 0.8) + 0.92) * primary:GetAttributeValueByClass("fast_reload", 1)) * PASSIVE_RELOAD_SPEED_FACTOR; local callbacks = {} local check local terminated = false local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end if primary ~= nil then if primary.m_flEnergy == 0 then activator:WeaponSwitchSlot(1) secondary:SetAttributeValue("disable weapon switch", 1) primary.m_flEnergy = maxClip * 5 if activator.m_hActiveWeapon ~= primary then timer.Simple(reloadDuration, function() secondary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end, 1) end end end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end --Substantially more optimized than the fuckers above, only time I could think that this would be inferior in performance to the others --is if you're using a blackbox with a really really large clip, and if that is the case there is nothing stopping you from using the legacy functions. --Other application of the above functions is if you have some funky custom thing that depletes people's clips to 0 (and only to 0, if it reduces to a minimum of 1, there's no point) function paleBurstLogicOnAttack(param, activator, caller) --Shouldn't be possible for primary to be nil, given that the rocket launcher would need to fire to invoke this. local primary = activator:GetPlayerItemBySlot(0) --If you're not at 0, we don't care, this is what makes this orders of magnitude more optimized than the previous version. We --aren't checking if the clip is 0 every tick, and as a result, we don't need to check if the bot is alive every tick either. --bot_reserve_combo.lua could probably be optimized in a similar way, but that would result in functionality loss, and the gameplay concept of it --is a piece of shit anyway. if primary.m_iClip1 ~= 0 then return end --Pale bursts will cheat a bit when reloading to come up faster, was made with monochrome in mind (who was a gigaburst boss) --as a small punishment for making him expend his full clip rather than circle him or something. The pale bursts inherit this, could --probably put this on a colonel to make it more significant. local PASSIVE_RELOAD_SPEED_FACTOR = 0.8 local secondary = activator:GetPlayerItemBySlot(1) local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusAtomic = primary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local maxClip = (4 * clipBonusMult) + clipBonusAtomic --Hardcoded soldier rocket launcher constants, first rocket takes 0.92 flat, every subsequent rocket takes 0.8. This is then all --multiplied by reload attributes present on the bot, and then the passive reload speed factor local reloadDuration = ((((maxClip - 1) * 0.8) + 0.92) * primary:GetAttributeValueByClass("fast_reload", 1)) * PASSIVE_RELOAD_SPEED_FACTOR --If our clip is 0, switch to our secondary, and make it impossible to switch back, and silently reload our launcher. Wait reloadDuration seconds, then make it --possible to switch back, then force the bot to switch anyway. --So we've done that barrage of variable calculations above to determine how long the script should wait to make the bot switch back to their launcher, and nothing more. activator:WeaponSwitchSlot(1) secondary:SetAttributeValue("disable weapon switch", 1) primary.m_iClip1 = maxClip timer.Simple(reloadDuration, function() secondary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end, 1) end function paleBurstLogicOnAttackBlackRider(param, activator, caller) --Shouldn't be possible for primary to be nil, given that the grenade launcher would need to fire to invoke this. local primary = activator:GetPlayerItemBySlot(0) --If you're not at 0, we don't care, this is what makes this orders of magnitude more optimized than the previous version. We --aren't checking if the clip is 0 every tick, and as a result, we don't need to check if the bot is alive every tick either. --bot_reserve_combo.lua could probably be optimized in a similar way, but that would result in functionality loss, and the gameplay concept of it --is a piece of shit anyway. local melee = activator:GetPlayerItemBySlot(2) if primary.m_iClip1 ~= 0 and melee:GetAttributeValue("disable weapon switch") == 0 then return end --Pale bursts will cheat a bit when reloading to come up faster, was made with monochrome in mind (who was a gigaburst boss) --as a small punishment for making him expend his full clip rather than circle him or something. The pale bursts inherit this, could --probably put this on a colonel to make it more significant. local PASSIVE_RELOAD_SPEED_FACTOR = 1 local clipBonusMult = primary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusAtomic = primary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local maxClip = (4 * clipBonusMult) + clipBonusAtomic --Hardcoded demo grenade launcher constants, first grenade takes 1.24 flat, every subsequent grenade takes 0.6. This is then all --multiplied by reload attributes present on the bot, and then the passive reload speed factor local reloadDuration = ((((maxClip - 1) * 0.6) + 1.24) * primary:GetAttributeValueByClass("fast_reload", 1)) * PASSIVE_RELOAD_SPEED_FACTOR --If our clip is 0, switch to our melee, and make it impossible to switch back, and silently reload our launcher. Wait reloadDuration seconds, then make it --possible to switch back, then force the bot to switch anyway. --So we've done that barrage of variable calculations above to determine how long the script should wait to make the bot switch back to their launcher, and nothing more. activator:WeaponSwitchSlot(2) melee:SetAttributeValue("disable weapon switch", 1) primary:SetAttributeValue("hidden string attribute 3", nil) timer.Simple(reloadDuration, function() melee:SetAttributeValue("disable weapon switch", 0) primary:SetAttributeValue("hidden string attribute 3", "ALLOW_SWITCH") activator:WeaponSwitchSlot(0) --primary.m_iClip1 = maxClip end, 1) end --Variant of the above script that is designed for a rapid fire grenade launcher and burst sticky launcher demo function paleBurstLogicOnAttackSecondary(param, activator, caller) --Shouldn't be possible for secondary to be nil, given that the sticky launcher would need to fire to invoke this. local secondary = activator:GetPlayerItemBySlot(1) --If you're not at 0, we don't care, this is what makes this orders of magnitude more optimized than the previous version. We --aren't checking if the clip is 0 every tick, and as a result, we don't need to check if the bot is alive every tick either. --bot_reserve_combo.lua could probably be optimized in a similar way, but that would result in functionality loss, and the gameplay concept of it --is a piece of shit anyway. if secondary.m_iClip1 ~= 0 then return end --Pale bursts will cheat a bit when reloading to come up faster, was made with monochrome in mind (who was a gigaburst boss) --as a small punishment for making him expend his full clip rather than circle him or something. The pale bursts inherit this, could --probably put this on a colonel to make it more significant. local PASSIVE_RELOAD_SPEED_FACTOR = 0.8 local primary = activator:GetPlayerItemBySlot(0) local clipBonusMult = secondary:GetAttributeValueByClass("mult_clipsize", 1) local clipBonusAtomic = secondary:GetAttributeValueByClass("mult_clipsize_upgrade_atomic", 0) local maxClip = (8 * clipBonusMult) + clipBonusAtomic --Hardcoded demo sticky launcher constants, first sticky takes 1.09 flat, every subsequent sticky takes 0.67. This is then all --multiplied by reload attributes present on the bot, and then the passive reload speed factor local reloadDuration = ((((maxClip - 1) * 0.8) + 1.09) * secondary:GetAttributeValueByClass("fast_reload", 1)) * PASSIVE_RELOAD_SPEED_FACTOR --If our clip is 0, switch to our primary, and make it impossible to switch back, and silently reload our launcher. Wait reloadDuration seconds, then make it --possible to switch back, then force the bot to switch anyway. --So we've done that barrage of variable calculations above to determine how long the script should wait to make the bot switch back to their launcher, and nothing more. activator:WeaponSwitchSlot(0) primary:SetAttributeValue("disable weapon switch", 1) secondary.m_iClip1 = maxClip timer.Simple(reloadDuration, function() primary:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(1) end, 1) end --almost all of the code here was "borrowed" from Royall's sniper laser script, knowing when you're dead --and properly cleaning up is quite important for any script applied directly to bots. --Trace is from a sample script written by Bazooks function Parachute(_, activator) local callbacks = {} local check local terminated = false local Zvalue local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end local TraceDownwards = { start = activator, -- Start position vector. Can also be set to entity, in this case the trace will start from entity eyes position endpos = nil, -- End position vector. If nil, the trace will be fired in `angles` direction with `distance` length distance = 8192, -- Used if endpos is nil angles = Vector(90,0,0), -- Used if endpos is nil mask = MASK_SOLID, -- Solid type mask, see MASK_* globals collisiongroup = COLLISION_GROUP_DEBRIS, -- Pretend the trace to be fired by an entity belonging to this group. See COLLISION_GROUP_* globals mins = Vector(0,0,0), -- Extends the size of the trace in negative direction maxs = Vector(0,0,0), -- Extends the size of the trace in positive direction filter = nil -- Entity to ignore. Can be a single entity, table of entities, or a function with a single entity parameter } local downTraceTable = util.Trace(TraceDownwards) --the two values down here affect the maximum deploy height and the disengage height Zvalue = downTraceTable["StartPos"] - downTraceTable["HitPos"] - 68 if Zvalue[3] >= 200 then --increase this to make the parachute deploy when the bot is higher --print ("deploy parachute") activator:AddCond(80) end if Zvalue[3] < 150 then --increase this to make the parachute disengage when the bot is higher --print ("no more parachute") activator:RemoveCond(80) end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end --this is split off into a separate function so I don't bog down the already somewhat heavy original one with a weapon check function ParachuteAirstrike(_, activator) local callbacks = {} local check local terminated = false local Zvalue local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end local TraceDownwards = { start = activator, -- Start position vector. Can also be set to entity, in this case the trace will start from entity eyes position endpos = nil, -- End position vector. If nil, the trace will be fired in `angles` direction with `distance` length distance = 8192, -- Used if endpos is nil angles = Vector(90,0,0), -- Used if endpos is nil mask = MASK_SOLID, -- Solid type mask, see MASK_* globals collisiongroup = COLLISION_GROUP_DEBRIS, -- Pretend the trace to be fired by an entity belonging to this group. See COLLISION_GROUP_* globals mins = Vector(0,0,0), -- Extends the size of the trace in negative direction maxs = Vector(0,0,0), -- Extends the size of the trace in positive direction filter = nil -- Entity to ignore. Can be a single entity, table of entities, or a function with a single entity parameter } local downTraceTable = util.Trace(TraceDownwards) --the two values down here affect the maximum deploy height and the disengage height Zvalue = downTraceTable["StartPos"] - downTraceTable["HitPos"] - 68 if Zvalue[3] >= 200 then --increase this to make the parachute deploy when the bot is higher --print ("deploy parachute") activator:AddCond(80) activator:SetAttributeValue("fire rate bonus HIDDEN", 0.5) end if Zvalue[3] < 150 then --increase this to make the parachute disengage when the bot is higher --print ("no more parachute") activator:RemoveCond(80) activator:SetAttributeValue("fire rate bonus HIDDEN", nil) end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end --Stops demoknight charges unless the weapon they are holding allows them to do their thing function DemoknightSuppressChargeTemporarilyBlackRider(_, activator) local callbacks = {} local check local terminated = false local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end --this assumes that these weapons will not be replaced with new ones, but is more optimized due to not getting them every tick local melee = activator:GetPlayerItemBySlot(2) local primary = activator:GetPlayerItemBySlot(0) check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end if (activator.m_hActiveWeapon) then if activator.m_flChargeMeter > 98 and activator.m_hActiveWeapon:GetAttributeValue("hidden string attribute 2") ~= "ALLOW_CHARGE" then activator.m_flChargeMeter = 98 end if activator:InCond(17) then melee:SetAttributeValue("disable weapon switch", 1) if activator.m_hActiveWeapon ~= melee then activator:WeaponSwitchSlot(2) end elseif activator:InCond(17) == false and melee:GetAttributeValue("disable weapon switch") == 1 and primary:GetAttributeValue("hidden string attribute 3") == "ALLOW_SWITCH" then melee:SetAttributeValue("disable weapon switch", 0) activator:WeaponSwitchSlot(0) end end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end function DemoknightChargeLeap(_, activator) local callbacks = {} local check local terminated = false local function terminate() if terminated then return end terminated = true timer.Stop(check) removeCallbacks(activator, callbacks) end --this assumes that these weapons will not be replaced with new ones, but is more optimized due to not getting them every tick local shield = activator:GetPlayerItemBySlot(1) local chargeSpeedMult = shield:GetAttributeValueByClass("mod_charge_time", 1) local chargeTurningControlMult = activator:GetAttributeValue("mult charge turn control", true) if (chargeTurningControlMult ~= nil and chargeTurningControlMult > 3) or activator:GetAttributeValue("full charge turn control", true) then chargeTurningControlMult = 3 end local isCharging = false check = timer.Create(0.015, function() if not IsValid(activator) or not activator:IsAlive() then terminate() return end if isCharging == true and activator:InCond(125) ~= true then shield:SetAttributeValue("increased air control", 1) isCharging = false end if activator:InCond(17) then --done to guarantee that the charge scream will play, and to ensure the leap doesn't stack multiple times. timer.Simple(0.01, function() if activator:InCond(17) then activator:RemoveCond(17) isCharging = true shield:SetAttributeValue("increased air control", chargeTurningControlMult) local currentVelocity = activator.m_vecAbsVelocity local editedVelocity = Vector(currentVelocity[1],currentVelocity[2],(currentVelocity[3] + (600 * chargeSpeedMult))) activator:AddOutput("BaseVelocity " .. editedVelocity[1] .. " " .. editedVelocity[2] .. " " .. editedVelocity[3]) activator:SetForwardVelocity(500 * chargeSpeedMult) activator:AddCond(125, 1.2) end end) end end, 0) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end --Intelligently scales shield based on robot size and giant status function shieldHeavy(_, activator) local callbacks = {} local terminated = false local check local shield local function terminate() if terminated then return end terminated = true timer.Stop(check) if IsValid(shield) then shield:Kill() end removeCallbacks(activator, callbacks) end local shieldActive = true local activatorPrimary = activator:GetPlayerItemBySlot(0) --we have no reason to continue if we have no primary if not activatorPrimary then terminate() end local activeShieldModel = "" local shieldSpawnflags = 1 --precache as needed if activator.m_bIsMiniBoss == 1 then activeShieldModel = "models/props_mvm/mvm_player_shield2.mdl" shieldSpawnflags = 3 elseif activator.m_flModelScale > 1 then activeShieldModel = "models/props_mvm/mvm_player_shield.mdl" else activeShieldModel = "models/props_mvm/mvm_comically_small_player_shield.mdl" end activator.m_flRageMeter = 100 activator.m_bRageDraining = 1 shield = ents.CreateWithKeys("entity_medigun_shield", { teamnum = activator.m_iTeamNum, }, true, true) shield.m_hOwnerEntity = activator if activator.m_iTeamNum ~= 2 then shield.m_nSkin = 1 elseif activator.m_iTeamNum ~= 2 and activator.m_iTeamNum ~= 3 then shield.m_nSkin = 1 shield:AcceptInput("color", "255 255 255", nil, nil) activator:AcceptInput("addoutput", "rendermode 1", nil, nil) end shield:SetModel(activeShieldModel) --m_iWeaponState: 0 is idle, 1 is initial rev, 2 is firing, 3 is revved without firing check = timer.Create(0.015, function() if activatorPrimary.m_iWeaponState == 0 and shieldActive == true then shield:SetModel("models/empty.mdl") shieldActive = false --later we might want to dress up the shield engaging process with a sound and maybe a transparency fade, for now --it can just abruptly start existing once the heavy starts shooting else if shieldActive == false and activatorPrimary.m_iWeaponState > 1 then shield:SetModel(activeShieldModel) shieldActive = true end activator.m_flRageMeter = 100 activator.m_bRageDraining = 1 end end, 0) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) end --controversial, wanted to make spamming uber and crit cans to circumvent the boss' entire offense and HP pool respectively worse, --may be unnecessary. function BossCanteenResistance(_, activator) local callbacks = {} local terminated = false local function terminate() if terminated then return end terminated = true removeCallbacks(activator, callbacks) end callbacks.died = activator:AddCallback(ON_DEATH, function() terminate() end) callbacks.hurtpre = activator:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) local attacker = damageInfo.Attacker if not attacker or attacker:IsPlayer() == false then return end if attacker:InCond(34) or attacker:InCond(52) then damageInfo.Damage = damageInfo.Damage * 0.65 return true end end) callbacks.removed = activator:AddCallback(ON_REMOVE, function() terminate() end) callbacks.spawned = activator:AddCallback(ON_SPAWN, function() terminate() end) end