--thank you royal local function removeCallbacks(player, callbacks) if not IsValid(player) then return end for _, callbackId in pairs(callbacks) do player:RemoveCallback(callbackId) end end --temp value, we'll put bots in wherever our spawn is later on local BOT_HELL_VECTOR = Vector(0,0,0) local CLASS_TO_MODEL_TABLE_HUMAN = { "models/player/scout.mdl", "models/player/sniper.mdl", "models/player/soldier.mdl", "models/player/demo.mdl", "models/player/medic.mdl", "models/player/heavy.mdl", "models/player/pyro.mdl", "models/player/spy.mdl", "models/player/engineer.mdl" } local CLASS_TO_MODEL_TABLE_ROBOT_GIANT = { "models/bots/scout_boss/bot_scout_boss.mdl", "models/bots/sniper_boss/bot_sniper_boss.mdl", "models/bots/soldier_boss/bot_soldier_boss.mdl", "models/bots/demo_boss/bot_demo_boss.mdl", "models/bots/medic/bot_medic.mdl", "models/bots/heavy_boss/bot_heavy_boss.mdl", "models/bots/pyro_boss/bot_pyro_boss.mdl", "models/bots/spy/bot_spy.mdl", "models/bots/engineer/bot_engineer.mdl", } local CLASS_TO_MODEL_TABLE_ROBOT_COMMON = { "models/bots/scout/bot_scout.mdl", "models/bots/sniper/bot_sniper.mdl", "models/bots/soldier/bot_soldier.mdl", "models/bots/demo/bot_demo.mdl", "models/bots/medic/bot_medic.mdl", "models/bots/heavy/bot_heavy.mdl", "models/bots/pyro/bot_pyro.mdl", "models/bots/spy/bot_spy.mdl", "models/bots/engineer/bot_engineer.mdl", } local inWave = false function OnWaveInit() inWave = false end function OnWaveStart() inWave = true end --in case anyone else uses this script, they can set bot hell vector to wherever the spawn is on their map function setBotHellVectorX(changedVectorX) BOT_HELL_VECTOR = Vector(changedVectorX, BOT_HELL_VECTOR[2], BOT_HELL_VECTOR[3]) end function setBotHellVectorY(changedVectorY) BOT_HELL_VECTOR = Vector(BOT_HELL_VECTOR[1], changedVectorY, BOT_HELL_VECTOR[3]) end function setBotHellVectorZ(changedVectorZ) BOT_HELL_VECTOR = Vector(BOT_HELL_VECTOR[1], BOT_HELL_VECTOR[2], changedVectorZ) end AddEventCallback("player_spawn", function(eventTable) local activator = ents.GetPlayerByUserId(eventTable.userid) if activator:IsRealPlayer() == false then return end local callbacks = {} timer.Simple(0.01, function() callbacks.spawned = activator:AddCallback(ON_SPAWN, function() removeCallbacks(activator, callbacks) end) local activatorTaggingAttr = activator:GetAttributeValue("special item description 3") if activatorTaggingAttr == nil or activatorTaggingAttr == "GHOST" then activator:SetAttributeValue("special item description 3", "GHOST") activator.p_iOriginalClass = activator.m_iClass activator.p_iOriginalMetal = activator.m_iAmmo[TF_AMMO_METAL] activator.p_iOriginalPrimaryClip = activator:GetPlayerItemBySlot(0).m_iClip1 activator.p_iOriginalSecondaryClip = activator:GetPlayerItemBySlot(1).m_iClip1 activator.p_iOriginalHealth = activator.m_iHealth end end) local logicLoop logicLoop = timer.Create(0.2, function() local ejecting = false if not activator:IsAlive() then timer.Stop(logicLoop) return end if activator:GetAttributeValue("special item description 3") ~= "GHOST" then activator:Print(PRINT_TARGET_RIGHT, "PRESS SPECIAL ATTACK (MOUSE3) TO EXIT") if (activator.m_nButtons >= 33554432 or inWave == false) and ejecting == false then ejecting = true local bot local botNameReference = activator:GetAttributeValue("special item description 3") activator:RemoveCond(34) for _, player in pairs(ents.GetAllPlayers()) do --Look for a bot who has been 66'd, and has the same name as our reference if player.m_szNetname == botNameReference and player:InCond(TF_COND_STEALTHED_USER_BUFF_FADING) and player:IsRealPlayer() == false then bot = player break end end --this shouldn't be nil unless some mega fuckup happens, but it never hurts to check --if a mega fuckup did not happen, move the bot over to where you are, undrug it, and set its health --to yours if bot ~= nil then bot:SnapEyeAngles(Vector(activator["m_angEyeAngles[0]"],activator["m_angEyeAngles[1]"], 0)) bot:SetAbsOrigin(activator:GetAbsOrigin()) bot.m_iHealth = activator.m_iHealth bot:RemoveCond(TF_COND_STEALTHED_USER_BUFF_FADING) bot:RemoveCond(TF_COND_STUNNED) local botPrimary = bot:GetPlayerItemBySlot(0) if botPrimary then botPrimary.m_iClip1 = activator:GetPlayerItemBySlot(0).m_iClip1 botPrimary.m_iClip2 = activator:GetPlayerItemBySlot(0).m_iClip2 end local botSecondary = bot:GetPlayerItemBySlot(1) if botSecondary then botSecondary.m_iClip1 = activator:GetPlayerItemBySlot(1).m_iClip1 botSecondary.m_iClip2 = activator:GetPlayerItemBySlot(1).m_iClip2 end bot.m_flRageMeter = activator.m_flRageMeter bot.m_iDecapitations = activator.m_iDecapitations bot.m_iRevengeCrits = activator.m_iRevengeCrits bot.m_flChargeMeter = activator.m_flChargeMeter end local minibossStatus = activator:GetAttributeValue("is miniboss", false) activator.m_iTeamNum = 3 local buildingTable = ents.FindAllByClass("obj_*") local sentries = {} for _, entity in pairs(buildingTable) do if entity.m_hBuilder == activator and entity.m_iObjectType == 2 then table.insert(sentries, entity) end end activator:SwitchClassInPlace(activator.p_iOriginalClass) activator.m_iTeamNum = 2 local correctModelString = CLASS_TO_MODEL_TABLE_HUMAN[activator.m_iClass] activator:SetCustomModelWithClassAnimations(correctModelString) --Clear our old target's character attributes local robotAttributesTable = activator:GetAllAttributeValues(false) for name, value in pairs(robotAttributesTable) do activator:SetAttributeValue(name, nil) end activator.m_iAmmo[TF_AMMO_METAL] = activator.p_iOriginalMetal activator:GetPlayerItemBySlot(0).m_iClip1 = activator.p_iOriginalPrimaryClip activator:GetPlayerItemBySlot(1).m_iClip1 = activator.p_iOriginalSecondaryClip activator.m_iHealth = activator.p_iOriginalHealth timer.Simple(0.01, function() if(minibossStatus == 1) then activator:AddOutput("BaseVelocity 0 0 500") activator:SetForwardVelocity("-250") print("ejecting from a giant") else activator:AddOutput("BaseVelocity 0 0 250") activator:SetForwardVelocity("-125") print("ejecting from a common") end end) end else activator:Print(PRINT_TARGET_RIGHT, "MELEE FRIENDLY ROBOTS TO POSSESS THEM") end --print("I am not dead") --release control of the bot if you are holding special attack, and you are controlling a bot to begin with end, 0) callbacks.owie = activator:AddCallback(ON_DAMAGE_RECEIVED_PRE, function(_, damageInfo) -- just in case if not activator:IsAlive() then --print("Purged due to being dead") removeCallbacks(activator, callbacks) return end if activator:InCond(5) or activator:InCond(14) then return end local damage = damageInfo.Damage curHealth = activator.m_iHealth if ((damageInfo.DamageType & DMG_CRITICAL > 0) and damageInfo.Attacker.m_iTeamNum ~= activator.m_iTeamNum) then damage = damageInfo.Damage * 3.1 end if curHealth <= damage and (damageInfo.Attacker.m_iTeamNum ~= activator.m_iTeamNum or damageInfo.Attacker == activator) then damageInfo.Damage = 0 damageInfo.DamageType = DMG_GENERIC local botNameReference = activator:GetAttributeValue("special item description 3") if botNameReference ~= "GHOST" then local bot for _, player in pairs(ents.GetAllPlayers()) do --Look for a bot who has been 66'd, and has the same name as our reference if player.m_szNetname == botNameReference and player:InCond(TF_COND_STEALTHED_USER_BUFF_FADING) and player:IsRealPlayer() == false then bot = player end end if bot ~= nil then bot:SnapEyeAngles(Vector(activator["m_angEyeAngles[0]"],activator["m_angEyeAngles[1]"], 0)) bot:SetAbsOrigin(activator:GetAbsOrigin()) damageInfo.Damage = bot.m_iHealth timer.Simple(0.05, function() bot:TakeDamage(damageInfo) if bot:IsAlive() then bot:Suicide() end end) end local minibossStatus = activator:GetAttributeValue("is miniboss", false) activator.m_iTeamNum = 3 activator:SwitchClassInPlace(activator.p_iOriginalClass) activator.m_iTeamNum = 2 local correctModelString = CLASS_TO_MODEL_TABLE_HUMAN[activator.m_iClass] activator:SetCustomModelWithClassAnimations(correctModelString) --take your nonexistent damage local setHealthDmgInfo = { Attacker = damageInfo.Attacker, Inflictor = damageInfo.Inflictor, Weapon = damageInfo.Weapon, Damage = 0, CritType = 0, DamageType = damageInfo.DamageType, DamageCustom = damageInfo.DamageCustom, DamagePosition = damageInfo.DamagePosition, DamageForce = nil, ReportedPosition = damageInfo.ReportedPosition, } if(minibossStatus == 1) then activator:TakeDamage(setHealthDmgInfo) activator:AddOutput("BaseVelocity 0 0 1250") activator:SetForwardVelocity("-500") timer.Simple(1.1, function() activator:AddCond(80) end) else activator:TakeDamage(setHealthDmgInfo) activator:AddOutput("BaseVelocity 0 0 625") activator:SetForwardVelocity("-250") timer.Simple(0.55, function() activator:AddCond(80) end) end --Clear our old target's character attributes local robotAttributesTable = activator:GetAllAttributeValues(false) for name, value in pairs(robotAttributesTable) do activator:SetAttributeValue(name, nil) end activator.m_iAmmo[TF_AMMO_METAL] = activator.p_iOriginalMetal activator:GetPlayerItemBySlot(0).m_iClip1 = activator.p_iOriginalPrimaryClip activator:GetPlayerItemBySlot(1).m_iClip1 = activator.p_iOriginalSecondaryClip activator.m_iHealth = activator.p_iOriginalHealth return true end elseif (damageInfo.Attacker.m_iTeamNum ~= activator.m_iTeamNum or damageInfo.Attacker == activator) then local botNameReference = activator:GetAttributeValue("special item description 3") if botNameReference ~= "GHOST" then local bot for _, player in pairs(ents.GetAllPlayers()) do --Look for a bot who has been 66'd, and has the same name as our reference if player.m_szNetname == botNameReference and player:InCond(TF_COND_STEALTHED_USER_BUFF_FADING) and player:IsRealPlayer() == false then bot = player end end if bot ~= nil then timer.Simple(0.05, function() bot.m_iHealth = activator.m_iHealth bot:TakeDamage(damageInfo) end) end end end end) callbacks.dead = activator:AddCallback(ON_DEATH, function() local activatorTaggingAttr = activator:GetAttributeValue("special item description 3") if activatorTaggingAttr == nil or activatorTaggingAttr == "GHOST" then activator:SetAttributeValue("special item description 3", "GHOST") activator.p_iOriginalClass = activator.m_iClass else local bot for _, player in pairs(ents.GetAllPlayers()) do --Look for a bot who has been 66'd, and has the same name as our reference if player.m_szNetname == activatorTaggingAttr and player:InCond(TF_COND_STEALTHED_USER_BUFF_FADING) and player:IsRealPlayer() == false then bot = player end end if bot ~= nil then bot:SnapEyeAngles(Vector(activator["m_angEyeAngles[0]"],activator["m_angEyeAngles[1]"], 0)) bot:SetAbsOrigin(activator:GetAbsOrigin()) --bot.m_iHealth = activator.m_iHealth bot:RemoveCond(TF_COND_STEALTHED_USER_BUFF_FADING) bot:RemoveCond(TF_COND_STUNNED) end local robotAttributesTable = activator:GetAllAttributeValues(false) for name, value in pairs(robotAttributesTable) do activator:SetAttributeValue(name, nil) end end --print("Purged due to being dead, but later") timer.Simple(5, function() activator.m_iTeamNum = 3 activator:SwitchClass(activator.p_iOriginalClass) activator.m_iTeamNum = 2 local correctModelString = CLASS_TO_MODEL_TABLE_HUMAN[activator.m_iClass] activator:SetCustomModelWithClassAnimations(correctModelString) end) removeCallbacks(activator, callbacks) end) end) function checkIfMeleeHitAllyPossess(param, activator, caller) if activator:GetAttributeValue("special item description 3") ~= "GHOST" then return end if not util.IsLagCompensationActive() then util.StartLagCompensation(activator) end --ripped from red_sniper_laser.lua local function getEyeAngles(player) local pitch = player["m_angEyeAngles[0]"] local yaw = player["m_angEyeAngles[1]"] return Vector(pitch, yaw, 0) end --ripped from my med hunter script, hybrid of red sniper laser check and some original work on my end local TraceLineOfSight = { start = activator, -- Start position vector. Can also be set to entity, in this case the trace will start from entity eyes position distance = 100, -- Used if endpos is nil angles = getEyeAngles(activator), -- Used if endpos is nil mask = MASK_SOLID, -- Solid type mask, see MASK_* globals collisiongroup = COLLISION_GROUP_PLAYER, -- Pretend the trace to be fired by an entity belonging to this group. See COLLISION_GROUP_* globals } local lineOfSightTraceTable = util.Trace(TraceLineOfSight) local hitEntity = lineOfSightTraceTable.Entity --print(lineOfSightTraceTable.Entity) --If the trace hit a valid bot that is on your team, and they aren't in addcond 66 (currently being controlled by someone else), begin the possession logic. if IsValid(hitEntity) and hitEntity:IsBot() and hitEntity.m_iTeamNum == activator.m_iTeamNum and hitEntity:InCond(TF_COND_STEALTHED_USER_BUFF_FADING) == false then --Smash a rock over the bot's skull then hide them from the authorities hitEntity:AddCond(TF_COND_MVM_BOT_STUN_RADIOWAVE, 50000, activator) hitEntity:AddCond(TF_COND_STEALTHED_USER_BUFF_FADING, 50000) activator:AddCond(57, 0.5, activator) --Snap player's view to what the bot was looking at activator:SnapEyeAngles(Vector(hitEntity["m_angEyeAngles[0]"],hitEntity["m_angEyeAngles[1]"], 0)) activator.p_iOriginalMetal = activator.m_iAmmo[TF_AMMO_METAL] activator.p_iOriginalPrimaryClip = activator:GetPlayerItemBySlot(0).m_iClip1 activator.p_iOriginalSecondaryClip = activator:GetPlayerItemBySlot(1).m_iClip1 activator.p_iOriginalHealth = activator.m_iHealth --copypasted wholesale from the scout mech primary, spawns a set of particles, a lightning strike on the bot and a teleport particle on the player local teleParticle = ents.CreateWithKeys("info_particle_system", { effect_name = "teleportedin_red", start_active = 1, flag_as_weather = 0, }, true, true) teleParticle:SetAbsOrigin(activator:GetAbsOrigin()) teleParticle:Start() local teleParticle2 = ents.CreateWithKeys("info_particle_system", { effect_name = "wrenchmotron_teleport_beam", start_active = 1, flag_as_weather = 0, }, true, true) teleParticle2:SetAbsOrigin(activator:GetAbsOrigin()) teleParticle2:Start() timer.Simple(1, function() teleParticle:Remove() teleParticle2:Remove() end) --Kidnap bot, snap player to bot's old location activator:SetAbsOrigin(hitEntity:GetAbsOrigin()) hitEntity:AddOutput("BaseVelocity 0 0 0") hitEntity:SetForwardVelocity("0") hitEntity:SetAbsOrigin(BOT_HELL_VECTOR) --Clear our character attributes for name, value in pairs(activator:GetAllAttributeValues(false)) do activator:SetAttributeValue(name, nil) end --stops engie buildings from exploding activator.m_iTeamNum = 3 --Make us their class, order of operations here is important because a few sanity check attributes are applied --whenever the player is respawned this way, meaning the previous check will not clean them off. activator:SwitchClassInPlace(hitEntity.m_iClass) --Give us our target's character attributes local robotAttributesTable = hitEntity:GetAllAttributeValues(false) for name, value in pairs(robotAttributesTable) do activator:SetAttributeValue(name, value) end --prevents horrific server shattering consequences activator.m_iTeamNum = 2 activator:RemoveCond(114) --We do this to stop mini sentries from exploding whenever you eject from a bot local hasMiniSentryReplacement = activator:GetPlayerItemBySlot(2):GetAttributeValue("mod wrench builds minisentry") for i = 0, 8 do local firearm = hitEntity:GetPlayerItemBySlot(i) --if we exist, give the player a copy of us, then xerox our attributes onto the copy if firearm ~= nil then activator:GiveItem(firearm:GetItemName()) for name, value in pairs(firearm:GetAllAttributeValues()) do activator:GetPlayerItemBySlot(i):SetAttributeValue(name, value); end end end if hasMiniSentryReplacement == true then activator:GetPlayerItemBySlot(2):SetAttributeValue("mod wrench builds minisentry", 1) end if hitEntity:InCond(34) == true then activator:AddCond(34) end local primary = activator:GetPlayerItemBySlot(0) if primary and primary:GetAttributeValue("grenade launcher mortar mode") == 0 then primary:SetAttributeValue("grenade launcher mortar mode", 1) end activator.m_flRageMeter = hitEntity.m_flRageMeter activator.m_iDecapitations = hitEntity.m_iDecapitations activator.m_iRevengeCrits = hitEntity.m_iRevengeCrits activator.m_flChargeMeter = hitEntity.m_flChargeMeter if(hitEntity:GetPlayerItemBySlot(0)) then primary.m_iClip1 = hitEntity:GetPlayerItemBySlot(0).m_iClip1 end if(hitEntity:GetPlayerItemBySlot(1)) then activator:GetPlayerItemBySlot(1).m_iClip1 = hitEntity:GetPlayerItemBySlot(1).m_iClip1 end activator:SetAttributeValue("model scale", hitEntity.m_flModelScale) if hitEntity.m_bIsMiniBoss == 1 then activator:SetAttributeValue("is miniboss", 1) local correctModelString = CLASS_TO_MODEL_TABLE_ROBOT_GIANT[activator.m_iClass] activator:SetCustomModelWithClassAnimations(correctModelString) else local correctModelString = CLASS_TO_MODEL_TABLE_ROBOT_COMMON[activator.m_iClass] activator:SetCustomModelWithClassAnimations(correctModelString) end activator:SetAttributeValue("special item description 3", hitEntity.m_szNetname) activator.m_iHealth = hitEntity.m_iHealth end end