function IsValidRealPlayer(ent) return IsValid(ent) and ent:IsRealPlayer(); end function IsValidPlayer(ent) return IsValid(ent) and ent:IsPlayer(); end function IsValidAlivePlayer(ent) return IsValid(ent) and ent:IsPlayer() and ent:IsAlive(); end CEntity.SetAttributeValues = function(self, attributes) if (IsValid(self)) then for attr, val in pairs(attributes) do self:SetAttributeValue(attr, val); end end end CEntity.GetTeam = function(self) if self:IsValid() then return self.m_iTeamNum end end CEntity.OnTeam = function(self, team) if self:IsValid() then return self.m_iTeamNum == team end end math.round = function(num, decimals) if (not decimals or decimals <= 0) then return math.floor(num + 0.5) else local mod = 10 ^ decimals return math.floor((num * mod) + 0.5) / mod end end math.clamp = function( value, min, max ) if min and max then if min > max then min, max = max, min end if value > max then value = max end if min > value then value = min end return value elseif min and ( not max ) then return math.min( value ) elseif max and ( not min ) then return math.max( value ) end end CEntity.GetEyeAngles = function(self) if (IsValidPlayer(self)) then return Vector( self.m_angEyeAngles[1], self.m_angEyeAngles[2], 0 ) end end CEntity.GetEyePos = function(self) if (not IsValidPlayer(self)) then return; end local eyepos = self:GetAbsOrigin(); eyepos.z = eyepos.z + self["m_vecViewOffset[2]"]; return eyepos end CEntity.CountUnlockedSpells = function(self) if (not IsValidPlayer(self)) then return; end return #self.SpellTable end CEntity.PlayParentedParticle = function(self, particle, offset, remove_after, RemoveFunction) if (not IsValid(self)) then return; end particle = ents.CreateWithKeys("info_particle_system", { effect_name=particle, start_active=1, ["$modules"]="fakeparent", ["$positiononly"]=1, }, true, true) local entity_origin = self:GetAbsOrigin(); if (offset) then entity_origin = entity_origin + offset; end particle.m_vecOrigin = entity_origin; particle["$SetFakeParent"](particle, self); particle["Start"](particle); timer.Create(remove_after, function() pcall(particle["Remove"], particle); if (RemoveFunction) then pcall(RemoveFunction); end end, 1); return particle; end CEntity.IsMidair = function(self) if (IsValidAlivePlayer(self)) then return not (self.movetype == MOVETYPE_WALK and (self.m_fFlags & FL_ONGROUND ~= 0)); end end CEntity.GetPlayerVelocity = function(self) if (IsValidPlayer(self)) then return self.m_vecAbsVelocity end end CEntity.SetPlayerVelocity = function(self, vel) if (IsValidAlivePlayer(self)) then self.m_vecAbsVelocity = vel end end CVector.Unpack = function(self) return self[1], self[2], self[3] end function lerp(start, goal, exp) return start + (goal - start) * exp end function PlaySound(sound, position) local ent = ents.CreateWithKeys("info_target", {}, true, true); ent:SetAbsOrigin(position); ent:PlaySound(sound); ent:Remove(); end function CreateClientSidedProp( classname, table, client ) local prop = ents.CreateWithKeys( classname, table, true, true ) prop:Enable() prop:HideToAll() prop:ShowTo( client ) return prop end function GetRandomPointInCircle( Radius ) --welcome to fucked up math local pi = math.pi local theta = math.random() * Radius * pi local r = math.random() + math.random() if r >= 1 then r = 2 - r end --local dist = ( r * math.cos( theta ) )^2 + ( r * math.sin( theta ) )^2 --dist = math.sqrt( dist ) --print( dist * Radius ) --print( ( r * math.cos( theta ) ) * Radius, ( r * math.sin( theta ) ) * Radius ) return Vector( ( r * math.cos( theta ) ) * Radius, ( r * math.sin( theta ) ) * Radius, 0 ) end function CustomHitbox( origin, maxs, mins, filt ) local st1 = origin + Vector( maxs[1], maxs[2], maxs[3] ) local ed1 = origin + Vector( mins[1], mins[2], mins[3] ) local st2 = origin + Vector( maxs[1], maxs[2], mins[3] ) local ed2 = origin + Vector( mins[1], mins[2], maxs[3] ) local st3 = origin + Vector( mins[1], maxs[2], maxs[3] ) local ed3 = origin + Vector( maxs[1], mins[2], mins[3] ) local st4 = origin + Vector( mins[1], maxs[2], mins[3] ) local ed4 = origin + Vector( maxs[1], mins[2], maxs[3] ) local tr1 = util.Trace( { start = st1, endpos = ed1, filter = filt } ) local tr2 = util.Trace( { start = st2, endpos = ed2, filter = filt } ) local tr3 = util.Trace( { start = st3, endpos = ed3, filter = filt } ) local tr4 = util.Trace( { start = st4, endpos = ed4, filter = filt } ) if tr1.Hit or tr2.Hit or tr3.Hit or tr4.Hit then return false else return true end end local CHEATERS = { ["[U:1:1770405241]"] = true, ["[U:1:1704340995]"] = true, ["[U:1:1922018405]"] = true, ["[U:1:1904913778]"] = true, ["[U:1:1062396597]"] = true, ["[U:1:1916202565]"] = true, ["[U:1:1723121518]"] = true, ["[U:1:1877411735]"] = true, ["[U:1:221152966]"] = true, ["[U:1:1883157641]"] = true, ["[U:1:1885514529]"] = true, ["[U:1:1644350202]"] = true, ["[U:1:1841779628]"] = true, ["[U:1:349826851]"] = true, ["[U:1:386700108]"] = true, ["[U:1:97203339]"] = true, ["[U:1:74057001]"] = true, ["[U:1:1712924683]"] = true, ["[U:1:1786692235]"] = true, ["[U:1:1314698454]"] = true, ["[U:1:1268276814]"] = true, ["[U:1:1007530715]"] = true, ["[U:1:432526137]"] = true, ["[U:1:1017755058]"] = true, ["[U:1:1735802732]"] = true, ["[U:1:172744906]"] = true, ["[U:1:1719864092]"] = true, ["[U:1:1415441535]"] = true, ["[U:1:418343582]"] = true, ["[U:1:399239913]"] = true, ["[U:1:145288356]"] = true, ["[U:1:1267741971]"] = true, ["[U:1:41024556]"] = true, ["[U:1:213021739]"] = true, ["[U:1:425291587]"] = true, ["[U:1:164500106]"] = true, ["[U:1:837368705]"] = true, ["[U:1:130490845]"] = true, ["[U:1:114550444]"] = true, ["[U:1:89784922]"] = true, ["[U:1:874295988]"] = true, ["[U:1:1427498087]"] = true, ["[U:1:400236800]"] = true, ["[U:1:1302787525]"] = true, ["[U:1:1183809195]"] = true, ["[U:1:1572558078]"] = true, ["[U:1:1251129637]"] = true, ["[U:1:427894071]"] = true, ["[U:1:1226042555]"] = true, ["[U:1:1018883373]"] = true, ["[U:1:67368924]"] = true, ["[U:1:34513941]"] = true, ["[U:1:92521691]"] = true, ["[U:1:143642940]"] = true, ["[U:1:1049365161]"] = true, ["[U:1:86699889]"] = true, ["[U:1:103643619]"] = true, ["[U:1:412199207]"] = true, ["[U:1:134142630]"] = true, ["[U:1:1008509390]"] = true, ["[U:1:237981327]"] = true, ["[U:1:840925169]"] = true, ["[U:1:477029644]"] = true, ["[U:1:1924480034]"] = true, ["[U:1:1101504870]"] = true, ["[U:1:1547208917]"] = true, ["[U:1:1365131859]"] = true, ["[U:1:89784922]"] = true, ["[U:1:1226799266]"] = true, ["[U:1:1173812518]"] = true, ["[U:1:998943685]"] = true, ["[U:1:1433062718]"] = true, ["[U:1:1173714004]"] = true, ["[U:1:819776027]"] = true, ["[U:1:1145096557]"] = true, ["[U:1:823667499]"] = true, ["[U:1:830605347]"] = true, ["[U:1:1307419174]"] = true, ["[U:1:1256195134]"] = true, ["[U:1:1202421555]"] = true, ["[U:1:1301528028]"] = true, ["[U:1:322547794]"] = true, ["[U:1:1665468033]"] = true, ["[U:1:259701995]"] = true, ["[U:1:1033125380]"] = true, ["[U:1:882994776]"] = true, ["[U:1:1683068248]"] = true, ["[U:1:891985556]"] = true, ["[U:1:1400389325]"] = true, ["[U:1:74094238]"] = true, ["[U:1:1278691361]"] = true, ["[U:1:1520275434]"] = true, ["[U:1:1862471601]"] = true, ["[U:1:1296772921]"] = true, ["[U:1:95255355]"] = true, ["[U:1:1478524000]"] = true, ["[U:1:1870229588]"] = true, ["[U:1:1458906148]"] = true, ["[U:1:1623515566]"] = true, ["[U:1:1156944372]"] = true, ["[U:1:1910463882]"] = true, ["[U:1:788649579]"] = true, } UPGRADE_UPGRADE = 0; UPGRADE_APPLY = 1; UPGRADE_DOWNGRADE = 2; UPGRADE_RESTORE = 3; CLR_WHITE = {250, 245, 240}; CLR_RED = {250, 50, 0}; CLR_ORANGE = {250, 100, 50}; CLR_LIMEGREEN = {100, 250, 50}; CLR_BLUE = {50, 100, 250}; CLR_PURPLE = {150, 50, 175}; CLR_MAGENTA = {250, 50, 150}; common_spell_time = 10; rare_spell_time = 60; bolt_spell_time = 5; common_timer_value = common_spell_time; rare_timer_value = rare_spell_time; WIZARD_NONE = 0; WIZARD_USE_MANA = 3; WIZARD_USE_ROLLS = 2; WIZARD_USE_BOLT = 1; SPELL_TYPE_NONE = 0; SPELL_TYPE_COMMON = 1; SPELL_TYPE_RARE = 2; wizard_rng_rolls_custom_spells = true; SPELL_CHOOSING = -2; SPELL_NONE = -1; SPELL_FIREBALL = 0; SPELL_BALLOBATS = 1; SPELL_HEALINGAURA = 2; SPELL_PUMPKINMIRV = 3; SPELL_SUPERJUMP = 4; SPELL_INVISIBILITY = 5; SPELL_TELEPORT = 6; SPELL_TESLABOLT = 7; SPELL_MINIFY = 8; SPELL_METEORSHOWER = 9; SPELL_SUMMONMONOCULUS = 10; SPELL_SUMMONSKELETONS = 11; SPELL_KARTBOXINGROCKET = 12; SPELL_KARTBASEJUMP = 13; SPELL_KARTOVERHEAL = 14; SPELL_KARTBOMBHEAD = 15; SPELL_CUSTOM_CROCKET = 16; SPELL_CUSTOM_GRAVITYBOMB = 17; SPELL_CUSTOM_MAGICBOLT_T1 = 18; SPELL_CUSTOM_MAGICBOLT_T2 = 19; SPELL_CUSTOM_MAGICBOLT_T3 = 20; SPELL_CUSTOM_MAGICBOLT_T4 = 21; SPELL_CUSTOM_MAGICBOLT_T5 = 22; SPELL_CUSTOM_MAGICBOLT_T6 = 23; SPELL_CUSTOM_MAGICBOLT_T7 = 24; SPELL_CUSTOM_MAGICBOLT_T8 = 25; SPELL_CUSTOM_CRITBOOST = 26; SPELL_TIER_COMMON = 0 SPELL_TIER_RARE = 1 spell_projectile_class_map = { tf_projectile_spellfireball = SPELL_FIREBALL, tf_projectile_spellbats = SPELL_BALLOBATS, tf_projectile_spellmirv = SPELL_PUMPKINMIRV, tf_projectile_spelltransposeteleport = SPELL_TELEPORT, tf_projectile_lightningorb = SPELL_TESLABOLT, tf_projectile_spellmeteorshower = SPELL_METEORSHOWER, tf_projectile_spellspawnboss = SPELL_SUMMONMONOCULUS, tf_projectile_spellspawnhorde = SPELL_SUMMONSKELETONS, tf_projectile_spellkartorb = SPELL_KARTBOXINGROCKET, }; spell_rng_drop_chances = { [SPELL_TIER_COMMON] = 0.95, [SPELL_TIER_RARE] = 0.05, } spell_rng_melee_common_chances = { [SPELL_FIREBALL] = { roll_chance=0.5, charge_chances = {0.3, 0.7} }, [SPELL_HEALINGAURA] = { roll_chance=0.2, charge_chances = {0.4, 0.5, 0.1, } }, [SPELL_PUMPKINMIRV] = { roll_chance=0.15, charge_chances = {0.7, 0.2, 0.1, } }, [SPELL_BALLOBATS] = { roll_chance=0.15, charge_chances = {0.1, 0.2, 0.7, } }, }; spell_rng_melee_rare_chances = { [SPELL_SUMMONSKELETONS] = { roll_chance=0.5, charge_chances = {0.9, 0.1,} }, [SPELL_SUMMONMONOCULUS] = { roll_chance=0.3, charge_chances = {0.9, 0.1,} }, [SPELL_METEORSHOWER] = { roll_chance=0.10, charge_chances = {1 } }, [SPELL_TESLABOLT] = { roll_chance=0.10, charge_chances = {1 } }, }; spell_rng_common_chances = { [SPELL_FIREBALL] = { roll_chance=0.5, charge_chances = {0.2, 0.7, 0.07, 0.03} }, [SPELL_HEALINGAURA] = { roll_chance=1, charge_chances = {0.4, 0.5, 0.1, } }, [SPELL_PUMPKINMIRV] = { roll_chance=0.15, charge_chances = {0.7, 0.2, 0.1, } }, [SPELL_CUSTOM_CROCKET] = { roll_chance=0.15, charge_chances = {0.7, 0.2, 0.1, } }, }; spell_rng_rare_chances = { [SPELL_SUMMONSKELETONS] = { roll_chance=0.5, charge_chances = {0.9, 0.1,} }, [SPELL_SUMMONMONOCULUS] = { roll_chance=0.3, charge_chances = {0.9, 0.1,} }, [SPELL_METEORSHOWER] = { roll_chance=0.10, charge_chances = {1 } }, [SPELL_TESLABOLT] = { roll_chance=0.05, charge_chances = {1 } }, [SPELL_CUSTOM_GRAVITYBOMB] = { roll_chance=0.05, charge_chances = {1 } }, }; spell_data = { [SPELL_CHOOSING] = { name = "...", charges = 0, mana_cost = nil, roll_time = 0, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_NONE, }, [SPELL_NONE] = { name = "None", charges = 0, mana_cost = 0, roll_time = 0, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_NONE, }, [SPELL_FIREBALL] = { name = "Fireball", charges = 2, mana_cost = 300, roll_time = 2, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_BALLOBATS] = { name = "Ball O' Bats", charges = 3, mana_cost = 300, roll_time = 1, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_HEALINGAURA] = { name = "Healing Aura", charges = 2, mana_cost = 400, roll_time = 3, is_custom = true, fake_icon = SPELL_HEALINGAURA, SpawnFunction = SpellHealingAuraSpawn, spell_type = SPELL_TYPE_COMMON, }, [SPELL_CUSTOM_CRITBOOST] = { name = "Critboost", charges = 1, mana_cost = 500, roll_time = 3, is_custom = true, fake_icon = SPELL_HEALINGAURA, SpawnFunction = SpellCustomCritboostAuraSpawn, spell_type = SPELL_TYPE_COMMON, }, [SPELL_PUMPKINMIRV] = { name = "Pumpkin MIRV", charges = 2, mana_cost = 300, roll_time = 2, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_SUPERJUMP] = { name = "Superjump", charges = 2, mana_cost = 100, roll_time = 1, is_custom = true, fake_icon = SPELL_SUPERJUMP, SpawnFunction = SpellSuperjumpSpawn, spell_type = SPELL_TYPE_COMMON, }, [SPELL_INVISIBILITY] = { name = "Invisibility", charges = 1, mana_cost = 200, roll_time = 1, is_custom = true, fake_icon = SPELL_INVISIBILITY, SpawnFunction = SpellInvisibilitySpawn, spell_type = SPELL_TYPE_COMMON, }, [SPELL_TELEPORT] = { name = "Teleport", charges = 2, mana_cost = 300, roll_time = 1, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_TESLABOLT] = { name = "Tesla Bolt", charges = 1, mana_cost = 2000, roll_time = 7, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_RARE, }, [SPELL_MINIFY] = { name = "Minify", charges = 2, mana_cost = 300, roll_time = 1, is_custom = true, fake_icon = SPELL_MINIFY, SpawnFunction = SpellMinifySpawn, spell_type = SPELL_TYPE_RARE, }, [SPELL_METEORSHOWER] = { name = "Meteor Shower", charges = 1, mana_cost = 2500, roll_time = 7, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_RARE, }, [SPELL_SUMMONMONOCULUS] = { name = "Summon Monoculus", charges = 1, mana_cost = 1250, roll_time = 5, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_RARE, }, [SPELL_SUMMONSKELETONS] = { name = "Summon Skeletons", charges = 1, mana_cost = 1250, roll_time = 5, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_RARE, }, [SPELL_KARTBOXINGROCKET] = { name = "Boxing Rocket", charges = 5, mana_cost = 450, roll_time = 3, is_custom = false, fake_icon = nil, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_KARTBASEJUMP] = { name = "Bumper Car Base Jump", charges = 2, mana_cost = 200, roll_time = 2, is_custom = true, fake_icon = SPELL_KARTBASEJUMP, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_KARTOVERHEAL] = { name = "Bumper Car Overheal", charges = 2, mana_cost = 600, roll_time = 3, is_custom = true, fake_icon = SPELL_KARTOVERHEAL, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_KARTBOMBHEAD] = { name = "Bumper Car Bomb Head", charges = 2, mana_cost = 500, roll_time = 4, is_custom = true, fake_icon = SPELL_KARTBOMBHEAD, SpawnFunction = nil, spell_type = SPELL_TYPE_COMMON, }, [SPELL_CUSTOM_CROCKET] = { name = "Crocket!", charges = 3, mana_cost = 500, roll_time = 3, is_custom = true, fake_icon = SPELL_FIREBALL, SpawnFunction = SpellCustomCrocketSpawn, spell_type = SPELL_TYPE_COMMON, }, [SPELL_CUSTOM_GRAVITYBOMB] = { name = "Gravity Bomb", charges = 1, mana_cost = 2500, roll_time = 7, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomGravityBombSpawn, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T1] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT1, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T2] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT2, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T3] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT3, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T4] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT4, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T5] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT5, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T6] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT6, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T7] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT7, spell_type = SPELL_TYPE_RARE, }, [SPELL_CUSTOM_MAGICBOLT_T8] = { name = "Magic Bolt", charges = 1, mana_cost = 100, roll_time = 2, is_custom = true, fake_icon = SPELL_TESLABOLT, SpawnFunction = SpellCustomMagicboltT8, spell_type = SPELL_TYPE_RARE, }, }; ALCHEMIST_NONE = 0 ALCHEMIST_PLACE = 1 ALCHEMIST_SELF = 2 ALCHEMIST_THROWN = 3 FLASK_CRAFTING = -2 FLASK_NONE = -1 FLASK_PLACEABLE_SMALL = 0 FLASK_PLACEABLE_MEDIUM = 1 FLASK_PLACEABLE_LARGE = 2 FLASK_SELF_GHOST = 3 FLASK_SELF_UBER = 4 FLASK_SELF_FLIGHT = 5 FLASK_SELF_STRENGTH = 6 FLASK_THROWN_HEALING = 7 FLASK_THROWN_LINGERING_HEALING = 8 FLASK_THROWN_LINGERING_UBER = 9 FLASK_THROWN_SPEED = 10 FLASK_THROWN_DEFENSE = 11 FLASK_THROWN_ACID = 12 FLASK_THROWN_EMPTY = 13 FLASK_THROWN_COMBUSTION = 14 FLASK_THROWN_EXPLOSIVE = 15 FLASK_THROWN_DEBUFF = 16 FLASK_THROWN_SLOW = 17 FLASK_THROWN_GRAVITY = 18 FLASK_TYPE_NONE = 0; FLASK_TYPE_CREATE = 1; FLASK_TYPE_SELF = 2; FLASK_TYPE_PROJ = 3; flask_data = { [FLASK_CRAFTING] = { name = "Crafting...", charges = 0, stam_cost = nil, roll_time = 0, is_custom = false, flask_type = FLASK_TYPE_NONE, }, [FLASK_NONE] = { name = "None", charges = 0, stam_cost = 0, roll_time = 0, is_custom = false, flask_type = FLASK_TYPE_NONE, }, [FLASK_PLACEABLE_SMALL] = { name = "Small Healing Potion", charges = 3, stam_cost = 15, roll_time = 3, is_custom = true, flask_type = FLASK_TYPE_CREATE, Attr = "heal rate penalty", placeable_data = { model = "models/props_halloween/hwn_flask_vial.mdl", modelscale = 0.8, skin = 6, DefaultAnim = "Idle", renderfx = 15, }, }, [FLASK_PLACEABLE_MEDIUM] = { name = "Medium Healing Potion", charges = 2, stam_cost = 25, roll_time = 4, is_custom = true, flask_type = FLASK_TYPE_CREATE, Attr = "mult charge turn control", placeable_data = { model = "models/props_halloween/hwn_flask_vial.mdl", modelscale = 1, skin = 5, DefaultAnim = "Idle", renderfx = 15, }, }, [FLASK_PLACEABLE_LARGE] = { name = "Large Healing Potion", charges = 2, stam_cost = 40, roll_time = 5, is_custom = true, flask_type = FLASK_TYPE_CREATE, Attr = "ubercharge rate penalty", placeable_data = { model = "models/props_halloween/hwn_flask_vial.mdl", modelscale = 1.25, skin = 3, DefaultAnim = "Idle", renderfx = 15, }, }, [FLASK_SELF_GHOST] = { name = "Ghost Potion", charges = 1, stam_cost = 20, roll_time = 1, is_custom = true, flask_type = FLASK_TYPE_SELF, Attr = "increase player capture value", }, [FLASK_SELF_UBER] = { name = "Uber Potion", charges = 1, stam_cost = 75, roll_time = 5, is_custom = true, flask_type = FLASK_TYPE_SELF, Attr = "add cloak on hit", }, [FLASK_SELF_FLIGHT] = { name = "Flight Potion", charges = 2, stam_cost = 30, roll_time = 2, is_custom = true, flask_type = FLASK_TYPE_SELF, Attr = "disguise damage reduction", }, [FLASK_SELF_STRENGTH] = { name = "Strength Potion", charges = 1, stam_cost = 35, roll_time = 3, is_custom = true, flask_type = FLASK_TYPE_SELF, Attr = "disguise no burn", }, [FLASK_THROWN_HEALING] = { name = "Instant Health Potion", charges = 4, stam_cost = 50, roll_time = 3, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "max pipebombs decreased", }, [FLASK_THROWN_LINGERING_HEALING] = { name = "Lingering Healing Potion", charges = 2, stam_cost = 50, roll_time = 4, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "Projectile range increased", }, [FLASK_THROWN_LINGERING_UBER] = { name = "Lingering Uber Potion", charges = 1, stam_cost = 75, roll_time = 7.5, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "Projectile range decreased", }, [FLASK_THROWN_SPEED] = { name = "Speed Potion", charges = 3, stam_cost = 30, roll_time = 2, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "cannot giftwrap", }, [FLASK_THROWN_DEFENSE] = { name = "Tough Potion", charges = 2, stam_cost = 40, roll_time = 3, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "mod medic killed marked for death", }, [FLASK_THROWN_ACID] = { name = "Acid Flask", charges = 2, stam_cost = 50, roll_time = 4, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "mod rage damage boost", }, [FLASK_THROWN_EMPTY] = { name = "Empty Flask", charges = 5, stam_cost = 10, roll_time = 0.5, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "selfmade description", }, [FLASK_THROWN_COMBUSTION] = { name = "Combustion Potion", charges = 4, stam_cost = 25, roll_time = 2, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "custom employee number", }, [FLASK_THROWN_EXPLOSIVE] = { name = "Explosive Potion", charges = 3, stam_cost = 40, roll_time = 3, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "damage applies to sappers", }, [FLASK_THROWN_DEBUFF] = { name = "Weakening Potion", charges = 2, stam_cost = 35, roll_time = 4, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "mod mini-crit airborne deploy", }, [FLASK_THROWN_SLOW] = { name = "Slowing Potion", charges = 1, stam_cost = 30, roll_time = 2, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "always tradable", }, [FLASK_THROWN_GRAVITY] = { name = "Levitation Potion", charges = 1, stam_cost = 100, roll_time = 10, is_custom = true, flask_type = FLASK_TYPE_PROJ, Attr = "gesture speed increase", }, }; base_spell_menu = { timeout = 0, title = "Choose a Spell!", itemsPerPage = nil, flags = MENUFLAG_BUTTON_EXIT, onSelect = OnSpellMenuSelect, onCancel = nil, }; base_flask_menu = { timeout = 0, title = "Choose a Flask!", itemsPerPage = nil, flags = MENUFLAG_BUTTON_EXIT, onSelect = OnSpellMenuSelect, onCancel = nil, }; CEntity.ShowHudTextSimple = function(self, text, channel, x, y, clr, a, fadetime, holdtime) if (not IsValidRealPlayer(self)) then return; end alpha = alpha or 0; fadetime = fadetime or 0.25; holdtime = holdtime or 2; local r, g, b; if (clr and #clr == 3) then r, g, b = table.unpack(clr); else r, g, b = 255, 255, 255; end self:ShowHudText({ channel = channel, x = x, y = y, effect = 0, r1 = r, g1 = g, b1 = b, a1 = a, r2 = r, g2 = g, b2 = b, a2 = a, fadeinTime = fadetime, fadeoutTime = fadetime, holdTime = holdtime, fxTime = 0, }, text); end function CreateSpellMenuForPlayer(player) if (not IsValidRealPlayer(player)) then return; end local userid = player:GetUserId(); local new_menu = {}; -- Inherit from base spell menu for key, val in pairs(base_spell_menu) do new_menu[key] = val; end new_menu["onSelect"] = function( player, index, value ) OnSpellMenuSelect( player,index,value ) end -- Populate with player's unlocked spells for spell, playerspelldata in pairs( player.SpellTable ) do new_menu[spell] = { text = spell_data[ player.SpellTable[ spell ] ].name, value = player.SpellTable[ spell ], disabled = false }; end return new_menu; end function CreateFlaskMenuForPlayer(player) --WIP if (not IsValidRealPlayer(player)) then return; end local userid = player:GetUserId(); local new_menu = {}; -- Inherit from base spell menu for key, val in pairs(base_flask_menu) do new_menu[key] = val; end new_menu["onSelect"] = function( player, index, value ) OnFlaskMenuSelect( player,index,value ) end -- Populate with player's unlocked spells for flask, flaskdata in pairs( player.FlaskTable ) do new_menu[flask] = { text = tostring( flask_data[ player.FlaskTable[ flask ] ].charges ) .. " " .. flask_data[ player.FlaskTable[ flask ] ].name .. " [" .. flask_data[ player.FlaskTable[ flask ] ].stam_cost .. "]", value = player.FlaskTable[ flask ], disabled = false }; end return new_menu; end function OnSpellMenuSelect(player, selectedIndex, value) player.SpellIndex = selectedIndex value = tonumber(value); if (not player:IsWizard()) then return; end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end -- We add a small delay to prevent frame perfect spell cast then spell switch which avoids -- paying mana for the spell just cast (SPELL_CHOOSING has a mana cost of 0) local bonus_charges = 0 if spell_data[ player.SpellTable[ player.SpellIndex ] ].spell_type == SPELL_TYPE_COMMON then bonus_charges = player.upgrades_spelltype_data[ "common_extra_charges" ] else bonus_charges = player.upgrades_spelltype_data[ "rare_extra_charges" ] end timer.Create(0.25, function() SelectSpell(spellbook, value, spell_data[ player.SpellTable[ player.SpellIndex ] ].charges + bonus_charges, ( spell_data[ player.SpellTable[ player.SpellIndex ] ].roll_time * player.upgrades_spelltype_data[ "roll_time" ] ), true, true ) end, 1); end function OnFlaskMenuSelect( player, selectedIndex, value ) player.FlaskIndex = selectedIndex value = tonumber(value); if ( player.m_iClass ~= TF_CLASS_MEDIC ) then return end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end -- Get the stam cost of this flask local current_stam_cost = 0; --if (spell >= 0 or (customspell and customspell >= 0)) then local cost = flask_data[ player.FlaskTable[ player.FlaskIndex ] ].stam_cost if (cost) then current_stam_cost = cost; end --end -- Not enough stam for this flask if (math.round( player.Current_Stam, 0 ) - current_stam_cost < 0) then local player_origin = player:GetAbsOrigin(); player:TakeDamage({ Attacker = player, Inflictor = entity, Weapon = player.m_hActiveWeapon, Damage = 25, DamageType = DMG_SHOCK, DamageCustom = TF_DMG_CUSTOM_NONE, DamagePosition = player_origin, DamageForce = Vector(0,0,0), ReportedPosition = player_origin, }); player:PlaySoundToSelf("Halloween.spell_lightning_cast"); player:Print(PRINT_TARGET_CENTER, "Not enough stamina!"); return; end -- Valid spell cast player.Current_Stam = player.Current_Stam - current_stam_cost; local bonus_charges = 0 bonus_charges = spellbook:GetAttributeValue( "sniper no headshots" ) or 0 local roll_mult = 1 roll_mult = ( 10 - ( spellbook:GetAttributeValue( "elevate to unusual if applicable" ) or 0 ) ) / 10 --timer.Simple( 0.25, function() SelectFlask( spellbook, value, flask_data[ player.FlaskTable[ player.FlaskIndex ] ].charges + bonus_charges, flask_data[ player.FlaskTable[ player.FlaskIndex ] ].roll_time * roll_mult, true, true ) --end) end function FireCustomWeaponMimic(player, keyvalues, playerattributes, itemattributes, custommodel, customsound, customparticles, offset) if (not IsValidRealPlayer(player)) then return; end offset = offset or Vector(0,0,0) -- Inherit owner eye angles local player_eye_angles = player:GetEyeAngles(); if (not player_eye_angles) then player_eye_angles = Vector(0, 0, 0); end offset:Rotate( player_eye_angles:ToAngles() ) --if not offset then offset == Vector( 0, 0, 0 ) end local mimic = ents.CreateWithKeys("tf_point_weapon_mimic", keyvalues, true, true) mimic["$SetOwner"](mimic, player); local current_player_attributes = {}; -- Populate current_player_attributes with attributes to be modified from playerattributes if (playerattributes) then for attr, val in pairs(playerattributes) do local currentattr = player:GetAttributeValue(attr); if (not currentattr) then -- We need to know later that this attribute needs to be modified, so we can't set it to nil current_player_attributes[attr] = "\0"; else current_player_attributes[attr] = currentattr; end player:SetAttributeValue(attr, val); end end -- Modify mimic's weapon attributes if (itemattributes) then for index, attr in pairs(itemattributes) do mimic["$AddWeaponAttribute"](mimic, attr); end end local dmg_bonus = 1 local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (spellbook and spellbook.m_iClassname == "tf_weapon_spellbook") then dmg_bonus = spellbook:GetAttributeValue( "dmg penalty vs players" ) or 1 mimic["$AddWeaponAttribute"](mimic, dmg_bonus) end mimic:SetAbsAngles(player_eye_angles); -- Inherit owner eye origin local player_eye_origin = player:GetEyePos(); mimic:SetAbsOrigin(player_eye_origin + offset); -- Stuff to do when the mimic weapon fires function HandleMimicChanges(value, activator, caller) -- Add particle effects to the projectile local particleentities = {}; if (customparticles) then for index, particlename in pairs(customparticles) do local particle = ents.CreateWithKeys("info_particle_system", { effect_name=particlename, start_active=1, ["$modules"]="fakeparent", }, true, true); table.insert(particleentities, particle); local origin = activator:GetAbsOrigin(); particle.m_vecOrigin = origin; particle["$SetFakeParent"](particle, activator); particle["Start"](particle); end end -- Set the projectile's model if (custommodel) then activator["$SetModelSpecial"](activator, custommodel); end -- Kaboom activator:AddCallback(ON_REMOVE, function() -- Clean up particles for index, particle in pairs(particleentities) do particle:Remove(); end PrintTable( current_player_attributes ) -- Revert player's attributes for attr, val in pairs(current_player_attributes) do if (val == "\0") then player:SetAttributeValue(attr, nil); else player:SetAttributeValue(attr, nil); end end end); end mimic:AddOutput("$OnFire popscript,$HandleMimicChanges,,0,-1"); mimic["FireOnce"](mimic); if (customsound) then player:PlaySoundToSelf(customsound); end timer.Simple( 20, function() if mimic:IsValid() then mimic:Remove(); end end) end function FireCustomWeaponMimicDownward(player, keyvalues, playerattributes, itemattributes, custommodel, customsound, customparticles, offset) --gay ass code forced me to copy func if (not IsValidRealPlayer(player)) then return; end offset = offset or Vector(0,0,0) -- Inherit owner eye angles local player_eye_angles = player:GetEyeAngles(); if (not player_eye_angles) then player_eye_angles = Vector(0, 0, 0); end offset:Rotate( player_eye_angles:ToAngles() ) --if not offset then offset == Vector( 0, 0, 0 ) end local mimic = ents.CreateWithKeys("tf_point_weapon_mimic", keyvalues, true, true) mimic["$SetOwner"](mimic, player); local current_player_attributes = {}; -- Populate current_player_attributes with attributes to be modified from playerattributes if (playerattributes) then for attr, val in pairs(playerattributes) do local currentattr = player:GetAttributeValue(attr); if (not currentattr) then -- We need to know later that this attribute needs to be modified, so we can't set it to nil current_player_attributes[attr] = "\0"; else current_player_attributes[attr] = currentattr; end player:SetAttributeValue(attr, val); end end -- Modify mimic's weapon attributes if (itemattributes) then for index, attr in pairs(itemattributes) do mimic["$AddWeaponAttribute"](mimic, attr); end end local dmg_bonus = 1 local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (spellbook and spellbook.m_iClassname == "tf_weapon_spellbook") then dmg_bonus = spellbook:GetAttributeValue( "dmg penalty vs players" ) or 1 mimic["$AddWeaponAttribute"](mimic, dmg_bonus) end mimic:SetAbsAngles( Vector( 90, 0, 0 ) ); -- Inherit owner eye origin local player_eye_origin = player:GetEyePos(); mimic:SetAbsOrigin(player_eye_origin + offset); -- Stuff to do when the mimic weapon fires function HandleMimicChanges(value, activator, caller) -- Add particle effects to the projectile local particleentities = {}; if (customparticles) then for index, particlename in pairs(customparticles) do local particle = ents.CreateWithKeys("info_particle_system", { effect_name=particlename, start_active=1, ["$modules"]="fakeparent", }, true, true); table.insert(particleentities, particle); local origin = activator:GetAbsOrigin(); particle.m_vecOrigin = origin; particle["$SetFakeParent"](particle, activator); particle["Start"](particle); end end -- Set the projectile's model if (custommodel) then activator["$SetModelSpecial"](activator, custommodel); end -- Kaboom activator:AddCallback(ON_REMOVE, function() -- Clean up particles for index, particle in pairs(particleentities) do particle:Remove(); end -- Revert player's attributes for attr, val in pairs(current_player_attributes) do if (val == "\0") then player:SetAttributeValue(attr, nil); else player:SetAttributeValue(attr, val); end end end); end mimic:AddOutput("$OnFire popscript,$HandleMimicChanges,,0,-1"); mimic["FireOnce"](mimic); if (customsound) then player:PlaySoundToSelf(customsound); end timer.Simple( 20, function() if mimic:IsValid() then mimic:Remove(); end end) end function SpellHealingAuraSpawn(player, spellbook) if (not IsValidRealPlayer(player)) then return; end local entities = ents.FindInSphere(player:GetAbsOrigin(), 96); for index, ent in pairs(entities) do if (IsValidPlayer(ent) and ent.m_iTeamNum == player.m_iTeamNum) then ent:AddCond(TF_COND_INVULNERABLE, 2); ent:AddCond(TF_COND_HALLOWEEN_QUICK_HEAL, 6); end end player:PlaySoundToSelf("Halloween.spell_overheal"); end function SpellCustomCritboostAuraSpawn(player, spellbook) if (not IsValidRealPlayer(player)) then return; end player:AddCond( 37, 7.5 ) player:PlaySoundToSelf("Halloween.spell_overheal"); end function SpellSuperjumpSpawn(player, spellbook) if (not IsValidRealPlayer(player)) then return; end local velocity = player.m_vecAbsVelocity; if (velocity.z < 0) then velocity.z = 0; end velocity.z = (velocity.z + 500) * 2; if (velocity.z > 1500) then velocity.z = 1500; end player.m_vecAbsVelocity = velocity; player:PlaySoundToSelf("Halloween.spell_blastjump"); end function SpellInvisibilitySpawn(player, spellbook) if (not IsValidRealPlayer(player)) then return; end player:AddCond(TF_COND_STEALTHED_USER_BUFF, 6); player:SetAttributeValue("dmg taken increased", 0.5); player:PlaySoundToSelf("Halloween.spell_stealth"); timer.Create(6, function() if not (IsValid(player)) then return; end player:SetAttributeValue("dmg taken increased", 1); end, 1); end function SpellMinifySpawn(player, spellbook) if (not IsValidRealPlayer(player)) then return; end if (player.is_minified) then return; end player.is_minified = true; local fire_rate = player:GetAttributeValue("fire rate bonus") or 1; local melee_res = player:GetAttributeValue("mult dmgtaken from melee") or 1; player["SetForcedTauntCam"](player, 1); player:AddCond(TF_COND_SPEED_BOOST, 8); player:AddCond(TF_COND_HALLOWEEN_TINY, 8); player:SetAttributeValues({ ["fire rate bonus"] = 0.5, ["voice pitch scale"] = 1.25, ["major increased jump height"] = 1.5, ["mult dmgtaken from melee"] = 0.6, }); timer.Create(8, function() if (not IsValid(player)) then return; end player["SetForcedTauntCam"](player, 0); player:SetAttributeValues({ ["fire rate bonus"] = fire_rate, ["voice pitch scale"] = 1, ["major increased jump height"] = 1, ["mult dmgtaken from melee"] = melee_res, }); player.is_minified = false; end, 1); end function SpellCustomCrocketFired(value, activator, caller) local firetime = CurTime(); local think_timer = nil; think_timer = timer.Create(0.015, function() if (IsValid(activator)) then -- Explode after a short period if (CurTime() >= firetime + 5) then local origin = activator:GetAbsOrigin(); util.ParticleEffect("rd_robot_explosion_smoke_linger", origin); activator:PlaySound("BaseExplosionEffect.Sound"); -- Damage enemy players in the blast radius local entities = ents.FindInSphere(origin, 146); for index, ent in pairs(entities) do if (IsValidAlivePlayer(ent) and ent.m_iTeamNum ~= activator.m_iTeamNum) then ent:TakeDamage({ Attacker = activator.m_hOwnerEntity, Inflictor = activator, Weapon = nil, Damage = 40, DamageType = DMG_GENERIC, DamageCustom = TF_DMG_CUSTOM_NONE, DamagePosition = origin, DamageForce = Vector(0,0,0), ReportedPosition = origin, }); end end activator:Remove(); return; end local player = activator.m_hOwnerEntity; if (not IsValidRealPlayer(player)) then return; end -- Owner doesn't have homing rockets upgrade, don't continue if (not player:GetAttributeValue("sticky detonate mode")) then return; end local player_eye_angles = player:GetEyeAngles(); if (not player_eye_angles) then player_eye_angles = Vector(90, 0, 0); end -- Fire trace from owner's eyes and set rocket's angles and velocity towards hit position if (not util.IsLagCompensationActive()) then util.StartLagCompensation(player) local traceresult = util.Trace({ start = player, endpos = nil, distance = 8192, angles = player_eye_angles, mask = MASK_SHOT, collisiongroup = COLLISION_GROUP_PLAYER, mins = Vector(0,0,0), maxs = Vector(0,0,0), filter = {player, activator}, }); util.FinishLagCompensation(player) if (traceresult.Hit and traceresult.HitPos) then local target_angles = (traceresult.HitPos - activator:GetAbsOrigin()):ToAngles(); activator:SetAbsAngles(target_angles); activator.m_vecAbsVelocity = target_angles:GetForward() * 1100; end end else -- Projectile is dead, stop thinking if (think_timer) then pcall(timer.Stop, think_timer); think_timer = nil; end end end, 0); end function SpellCustomCrocketSpawn(player, spellbook) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$OnFire"] = "popscript,$SpellCustomCrocketFired,,0,-1", Crits = true, }, nil, nil, nil, "Weapon_RPG.SingleCrit", nil); end function SpellCustomGravityBombFired(value, activator, caller) -- We need to access the projectile's owner's team after it's been removed local caster = activator.m_hOwnerEntity; local caster_team = caster.m_iTeamNum; activator:AddCallback(ON_REMOVE, function() local offset = Vector(0, 0, 70); activator:PlayParentedParticle("flaregun_energyfield_red", offset, 4); activator:PlayParentedParticle("dxhr_lightningball_parent_red", offset, 4); local epicenter = activator:GetAbsOrigin() + offset; -- Suck enemy players into epicenter for duration local entities = {}; timer.Create(0.015, function() entities = ents.FindInSphere(epicenter, 180); for index, ent in pairs(entities) do if (IsValidAlivePlayer(ent) and ent.m_iTeamNum ~= caster_team) then local player_origin = ent:GetAbsOrigin(); -- Ensure victim becomes airborne when at low velocity if (not ent:IsMidair()) then player_origin.z = player_origin.z + 32; ent:SetAbsOrigin(player_origin); end local velocity_dir = (epicenter - player_origin):ToAngles(); local distance = epicenter:Distance(player_origin); local player_velocity = velocity_dir:GetForward() * (distance ^ 1.25); ent.m_vecAbsVelocity = player_velocity; end end end, math.round(2.1 / 0.015)); -- Explode afterwards timer.Create(4.2, function() local origin = epicenter; origin.z = origin.z - 35; util.ParticleEffect("rd_robot_explosion_smoke_linger", origin); PlaySound("BaseExplosionEffect.Sound", origin); -- Damage enemy players in the blast radius for index, ent in pairs(entities) do if (IsValidAlivePlayer(ent) and ent.m_iTeamNum ~= caster_team) then ent:TakeDamage({ Attacker = caster, Inflictor = nil, Weapon = nil, Damage = 300, DamageType = DMG_GENERIC, DamageCustom = TF_DMG_CUSTOM_NONE, DamagePosition = origin, DamageForce = Vector(0,0,0), ReportedPosition = origin, }); local velocity_dir = Vector(math.random(-90, -45), math.random(-180, 180), 0); velocity_dir = velocity_dir:GetForward() * math.random(500, 1000); ent.m_vecAbsVelocity = velocity_dir; end end end, 1); end) end function ExplosiveBolt(damage, activator, caller) --activator is the one with the weapon, caller is the one that got hit if 50 > damage then return end if caller:IsPlayer() and ( caller.m_iTeamNum ~= activator.m_iTeamNum ) then util.ParticleEffect( "mvm_loot_explosion", caller:GetEyePos() ) caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") caller:PlaySound("Weapon_LooseCannon.Explode") local BlastDamage = damage * 0.8 local BlastRadius = damage * 0.8 if BlastDamage > 120 then BlastDamage = 120 end if BlastRadius > 120 then BlastRadius = 120 end for _, others in pairs(ents.FindInSphere(caller:GetAbsOrigin(),BlastRadius)) do if others:IsPlayer() and ( others.m_iTeamNum ~= activator.m_iTeamNum ) and ( others ~= caller ) then others:TakeDamage({Damage = BlastDamage, Attacker = activator, DamageType = DMG_BLAST}) end end end end function OnSpellProjectileSpawned(entity) local player = entity.m_hOwnerEntity; if (not IsValidRealPlayer(player) or not ( player:GetPlayerItemBySlot(2):GetItemName() == "Mage Staff" )) then return; end -- Projectiles spawned by Meteor Shower should be ignored if (entity.m_hLauncher == entity.m_hOwnerEntity and entity.m_iClassname == "tf_projectile_spellfireball") then return; end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end local spell = spellbook.m_iSelectedSpellIndex; local customspell = spellbook._m_iCustomSelectedSpellIndex; if (player.MageType == WIZARD_USE_MANA) then -- Get the mana cost of this spell local current_mana_cost = 0; if (spell >= 0 or (customspell and customspell >= 0)) then local cost = spell_data[ player.SpellTable[ player.SpellIndex ] ].mana_cost if (cost) then current_mana_cost = cost; end end current_mana_cost = current_mana_cost * player.upgrades_spelltype_data[ "mana_cost" ] -- Not enough mana for this spell if (player.current_mana - current_mana_cost < 0) then local player_origin = player:GetAbsOrigin(); player:TakeDamage({ Attacker = player, Inflictor = entity, Weapon = player.m_hActiveWeapon, Damage = 25, DamageType = DMG_SHOCK, DamageCustom = TF_DMG_CUSTOM_NONE, DamagePosition = player_origin, DamageForce = Vector(0,0,0), ReportedPosition = player_origin, }); entity:Remove(); player:PlaySoundToSelf("Halloween.spell_lightning_cast"); player:Print(PRINT_TARGET_CENTER, "Not enough mana!"); return; end -- Valid spell cast player.current_mana = player.current_mana - current_mana_cost; end -- Call customspell spawn callback if available if (spellbook and customspell) then entity:Remove(); if customspell == SPELL_HEALINGAURA then --Never do this but this old code didn't work at all so I have to do this shitty mess SpellHealingAuraSpawn( player, spellbook ) elseif customspell == SPELL_SUPERJUMP then SpellSuperjumpSpawn( player, spellbook ) elseif customspell == SPELL_INVISIBILITY then SpellInvisibilitySpawn( player, spellbook ) elseif customspell == SPELL_MINIFY then SpellMinifySpawn( player, spellbook ) elseif customspell == SPELL_CUSTOM_CROCKET then SpellCustomCrocketSpawn( player, spellbook ) elseif customspell == SPELL_CUSTOM_GRAVITYBOMB then SpellCustomGravityBombSpawn( player, spellbook ) elseif customspell == SPELL_CUSTOM_CRITBOOST then SpellCustomCritboostAuraSpawn( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T1 then SpellCustomMagicboltT1( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T2 then SpellCustomMagicboltT2( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T3 then SpellCustomMagicboltT3( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T4 then SpellCustomMagicboltT4( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T5 then SpellCustomMagicboltT5( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T6 then SpellCustomMagicboltT6( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T7 then SpellCustomMagicboltT7( player, spellbook ) elseif customspell == SPELL_CUSTOM_MAGICBOLT_T8 then SpellCustomMagicboltT8( player, spellbook ) end end end function OnFlaskProjectileSpawned( entity ) local player = entity.m_hOwnerEntity; if (not IsValidRealPlayer(player) or not ( player.m_iClass == TF_CLASS_MEDIC )) then return; end if (entity.m_hLauncher == entity.m_hOwnerEntity and entity.m_iClassname == "tf_projectile_spellfireball") then return; end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end local spell = spellbook.m_iSelectedSpellIndex; local customspell = spellbook._m_iCustomSelectedSpellIndex; if (spellbook and customspell) then entity:Remove(); if customspell == FLASK_PLACEABLE_SMALL then --Never do this but this old code didn't work at all so I have to do this shitty mess local Tbl = { origin = player.LastPlaceableSpot[1] .. " " .. player.LastPlaceableSpot[2] .. " " .. player.LastPlaceableSpot[3], powerup_model = flask_data[ FLASK_PLACEABLE_SMALL ].placeable_data.model, AutoMaterialize = 0, OnPlayerTouch = "!self,kill,,0,-1", targetname = "DEBUG" } local powerup = ents.CreateWithKeys( "item_healthkit_small", Tbl, true, true ) powerup.m_nSkin = flask_data[ FLASK_PLACEABLE_SMALL ].placeable_data.Skin powerup.m_flModelScale = flask_data[ FLASK_PLACEABLE_SMALL ].placeable_data.modelscale powerup:RunScriptCode( "self.SetSkin(6)" ) elseif customspell == FLASK_PLACEABLE_MEDIUM then local Tbl = { origin = player.LastPlaceableSpot[1] .. " " .. player.LastPlaceableSpot[2] .. " " .. player.LastPlaceableSpot[3], powerup_model = flask_data[ FLASK_PLACEABLE_MEDIUM ].placeable_data.model, AutoMaterialize = 0, OnPlayerTouch = "!self,kill,,0,-1", targetname = "DEBUG" } local powerup = ents.CreateWithKeys( "item_healthkit_medium", Tbl, true, true ) powerup.m_nSkin = flask_data[ FLASK_PLACEABLE_MEDIUM ].placeable_data.Skin powerup.m_flModelScale = flask_data[ FLASK_PLACEABLE_MEDIUM ].placeable_data.modelscale powerup:RunScriptCode( "self.SetSkin(5)" ) elseif customspell == FLASK_PLACEABLE_LARGE then local Tbl = { origin = player.LastPlaceableSpot[1] .. " " .. player.LastPlaceableSpot[2] .. " " .. player.LastPlaceableSpot[3], powerup_model = flask_data[ FLASK_PLACEABLE_LARGE ].placeable_data.model, AutoMaterialize = 0, OnPlayerTouch = "!self,kill,,0,-1", targetname = "DEBUG" } local powerup = ents.CreateWithKeys( "item_healthkit_medium", Tbl, true, true ) powerup.m_nSkin = flask_data[ FLASK_PLACEABLE_LARGE ].placeable_data.Skin powerup.m_flModelScale = flask_data[ FLASK_PLACEABLE_LARGE ].placeable_data.modelscale powerup:RunScriptCode( "self.SetSkin(3)" ) elseif customspell == FLASK_SELF_GHOST then player:PlaySound( "BumperCar.HitGhost" ) player:AddCond( 77, 20 ) player:SetCustomModelWithClassAnimations( "models/props_halloween/ghost_no_hat_red.mdl" ) player:Print( PRINT_TARGET_CENTER, "You have been transformed into a ghost for 20 seconds." ) timer.Simple( 15, function() player:Print( PRINT_TARGET_CENTER, "Ghost Potion will wear off in 5 seconds." ) end) timer.Simple( 20, function() player:RemoveCond( 77 ) player:SetCustomModelWithClassAnimations( "" ) end) elseif customspell == FLASK_SELF_UBER then player:AddCond( 52, 8 ) player:PlaySound( "Powerup.PickUpTemp.Uber" ) elseif customspell == FLASK_SELF_FLIGHT then player:PlaySound( "Powerup.PickUpAgility" ) player:Print( PRINT_TARGET_CENTER, "You feel much lighter." ) player:SetAttributeValue( "air dash count", 10 ) player:SetAttributeValue( "major increased jump height", 1.5 ) player:SetAttributeValue( "cancel falling damage", 1 ) timer.Simple( 15, function() player:Print( PRINT_TARGET_CENTER, "You feel normal again" ) player:SetAttributeValue( "air dash count", nil ) player:SetAttributeValue( "major increased jump height", nil ) player:SetAttributeValue( "cancel falling damage", nil ) end) elseif customspell == FLASK_SELF_STRENGTH then player:Print( PRINT_TARGET_CENTER, "You feel much stronger" ) player:PlaySound( "Powerup.PickUpStrength" ) player:SetAttributeValue( "damage bonus", 1.8 ) player:SetAttributeValue( "mult dmg vs giants", 2 ) player:SetAttributeValue( "mult dmg vs tanks", 3 ) timer.Simple( 10, function() player:Print( PRINT_TARGET_CENTER, "You feel normal again" ) player:SetAttributeValue( "damage bonus", nil ) player:SetAttributeValue( "mult dmg vs giants", nil ) player:SetAttributeValue( "mult dmg vs tanks", nil ) end) elseif customspell == FLASK_THROWN_HEALING then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Healing Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_LINGERING_HEALING then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Lingering Healing Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_LINGERING_UBER then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Lingering Uber Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_SPEED then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Speed Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_DEFENSE then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Tough Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_ACID then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Acid Flask", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_EMPTY then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Empty Flask", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_COMBUSTION then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Combustion Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_EXPLOSIVE then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Explosive Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_DEBUFF then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Weakening Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_SLOW then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Slowing Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); elseif customspell == FLASK_THROWN_GRAVITY then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Levitation Potion", }, nil, nil, nil, "weapons/iceaxe/iceaxe_swing1.wav", nil); end end end function GravityProj( projectile,activator,weapon ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) local Targets = {} local prop = ents.CreateWithKeys( "prop_dynamic", { model = "models/props_invasion/2fort/chem_spill_1.mdl", solid = 0, disableshadows = 1, rendercolor = "0 255 0", rendermode = 1, renderamt = 0 }, true, true ) prop:PlayParentedParticle( "hwn_cart_cap_neutral", Vector( 0, 0, 24 ), 5 ) local Trace = util.Trace( { start = projectile:GetAbsOrigin() + Vector( 0, 0, 16 ), distance = 10000, angles = Vector( 90, 0, 0 ), filter = ents.GetAllPlayers() } ) prop:SetAbsOrigin( Trace.HitPos ) for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 250 ) ) do if player:IsPlayer() and ( player:GetTeam() ~= activator:GetTeam() ) and ( player:IsAlive() ) then table.insert( Targets, player ) player:SetPlayerVelocity( Vector( 0, 0, 650 ) ) player.DamageCallback = player:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) if dmginfo.DamageType == DMG_FALL then player:RemoveCallback( ON_DAMAGE_RECEIVED_PRE, player.DamageCallback ) dmginfo.Attacker = activator dmginfo.Damage = math.min( dmginfo.Damage * 2.5, 1500 ) return true end end) end end timer.Create( 0.1, function() for _, tar in pairs( Targets ) do tar:SetPlayerVelocity( Vector( 0, 0, math.max( math.abs( tar:GetPlayerVelocity()[3] ) + 50 ), 100 ) ) end end, 49 ) timer.Simple( 5.2, function() for _, tar in pairs( Targets ) do tar:TakeDamage({ Attacker = activator, Damage = 101, DamageType = DMG_GENERIC | DMG_NEVERGIB | DMG_PREVENT_PHYSICS_FORCE, DamageCustom = TF_DMG_CUSTOM_BLEEDING, CritType = 0 }) timer.Simple(0.1, function() tar:SetPlayerVelocity( Vector( 0, 0, -2000 ) ) end) end prop:Remove() end) end) end function SlowingProj( projectile,activator,weapon ) projectile.m_nSkin = 1 projectile:RunScriptCode( "self.SetSkin(1)" ) end function AcidProj( projectile,activator,weapon ) projectile.m_nSkin = 4 projectile:RunScriptCode( "self.SetSkin(4)" ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) local prop = ents.CreateWithKeys( "prop_dynamic", { model = "models/props_invasion/2fort/chem_spill_1.mdl", solid = 0, disableshadows = 1, rendercolor = "0 255 0", rendermode = 1 }, true, true ) local Trace = util.Trace( { start = projectile:GetAbsOrigin() + Vector( 0, 0, 16 ), distance = 10000, angles = Vector( 90, 0, 0 ), filter = ents.GetAllPlayers() } ) prop:SetAbsOrigin( Trace.HitPos ) prop:PlaySound( "ambient/levels/canals/toxic_slime_sizzle3.wav" ) prop:PlayParentedParticle( "utaunt_hands_goop_green", Vector( 16, 8, 16 ), 5 ) prop:PlayParentedParticle( "utaunt_bubbles_glow_green_parent", Vector( 16, 8, 16 ), 4 ) for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 150 ) ) do if player:IsPlayer() and ( player:GetTeam() ~= activator:GetTeam() ) and ( player:IsAlive() ) then player:TakeDamage({ Attacker = activator, Damage = 48, DamageType = DMG_GENERIC | DMG_NEVERGIB | DMG_PREVENT_PHYSICS_FORCE, DamageCustom = TF_DMG_CUSTOM_BLEEDING, CritType = 0 }) end end timer.Create( 0.1, function() for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 150 ) ) do if player:IsPlayer() and ( player:GetTeam() ~= activator:GetTeam() ) and ( player:IsAlive() ) then player:TakeDamage({ Attacker = activator, Damage = 12, DamageType = DMG_GENERIC | DMG_NEVERGIB | DMG_PREVENT_PHYSICS_FORCE, DamageCustom = TF_DMG_CUSTOM_BLEEDING, CritType = 0 }) end end end, 49 ) timer.Simple( 5.1, function() prop:Remove() end) end) end function SpeedProj( projectile,activator,weapon ) projectile.m_nSkin = 2 projectile:RunScriptCode( "self.SetSkin(2)" ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) for _, player in pairs( ents.FindInSphere( projectile:GetAbsOrigin(), 240 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then player:AddCond( 32, 5 ) end end end) end function ToughProj( projectile,activator,weapon ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) for _, player in pairs( ents.FindInSphere( projectile:GetAbsOrigin(), 240 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then player:AddCond( 26, 6 ) end end end) end function HealingProj( projectile,activator,weapon ) projectile.m_nSkin = 6 projectile:RunScriptCode( "self.SetSkin(6)" ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) for _, player in pairs( ents.FindInSphere( projectile:GetAbsOrigin(), 200 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then local MaxHealth = player.m_iMaxHealth + player:GetAttributeValueByClass("add_maxhealth_nonbuffed", 0) + player:GetAttributeValueByClass("add_maxhealth", 0) local fakeEventTable = { patient = player:GetUserId(), healer = activator:GetUserId(), amount = 50 } --scoreboard credit. FireEvent("player_healed", fakeEventTable) player:PlaySoundToSelf("HealthKit.Touch") player.m_iHealth = math.min( player.m_iHealth + 50, MaxHealth ) end end end) end function LingeringHealingProj( projectile,activator,weapon ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) local prop = ents.CreateWithKeys( "prop_dynamic", { model = "models/props_invasion/2fort/chem_spill_1.mdl", solid = 0, disableshadows = 1 }, true, true ) local Trace = util.Trace( { start = projectile:GetAbsOrigin() + Vector( 0, 0, 16 ), distance = 10000, angles = Vector( 90, 0, 0 ), filter = ents.GetAllPlayers() } ) prop:SetAbsOrigin( Trace.HitPos ) for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 200 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then local MaxHealth = player.m_iMaxHealth + player:GetAttributeValueByClass("add_maxhealth_nonbuffed", 0) + player:GetAttributeValueByClass("add_maxhealth", 0) local fakeEventTable = { patient = player:GetUserId(), healer = activator:GetUserId(), amount = 5 } --scoreboard credit. FireEvent("player_healed", fakeEventTable) player.m_iHealth = math.min( player.m_iHealth + 5, MaxHealth * 2 ) end end timer.Create( 0.1, function() for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 200 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then local MaxHealth = player.m_iMaxHealth + player:GetAttributeValueByClass("add_maxhealth_nonbuffed", 0) + player:GetAttributeValueByClass("add_maxhealth", 0) local fakeEventTable = { patient = player:GetUserId(), healer = activator:GetUserId(), amount = 5 } --scoreboard credit. FireEvent("player_healed", fakeEventTable) player.m_iHealth = math.min( player.m_iHealth + 5, MaxHealth * 2 ) end end end, 29 ) timer.Simple( 3.1, function() prop:Remove() end) end) end function LingeringUberProj( projectile,activator,weapon ) projectile.CallBack = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.CallBack ) local prop = ents.CreateWithKeys( "prop_dynamic", { model = "models/props_invasion/2fort/chem_spill_1.mdl", solid = 0, disableshadows = 1, rendercolor = "255 0 0", rendermode = 1, renderamt = 0 }, true, true ) local Trace = util.Trace( { start = projectile:GetAbsOrigin() + Vector( 0, 0, 16 ), distance = 10000, angles = Vector( 90, 0, 0 ), filter = ents.GetAllPlayers() } ) prop:SetAbsOrigin( Trace.HitPos ) prop:PlaySound( "Powerup.PickUpTemp.Uber" ) prop:PlayParentedParticle( "eyeboss_team_red", Vector( 0, 0, 48 ), 4 ) for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 200 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then player:AddCond( 57, 0.5 ) end end timer.Create( 0.1, function() for _, player in pairs( ents.FindInSphere( prop:GetAbsOrigin(), 200 ) ) do if player:IsPlayer() and ( player:GetTeam() == activator:GetTeam() ) and ( player:IsAlive() ) then player:AddCond( 57, 0.5 ) end end end, 39 ) timer.Simple( 4.1, function() prop:Remove() end) end) end function OnSpellProjectileCreated(entity, classname) entity:AddCallback(ON_SPAWN, OnSpellProjectileSpawned); entity:AddCallback(ON_SPAWN, OnFlaskProjectileSpawned); end for ent, index in pairs(spell_projectile_class_map) do ents.AddCreateCallback(ent, OnSpellProjectileCreated); end -- Spawn function for the Gravity Bomb spell function SpellCustomGravityBombSpawn(player, spellbook) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_GRENADELAUNCHER", ["$OnFire"] = "popscript,$SpellCustomGravityBombFired,,0,-1", Crits = true, }, nil, { "Projectile speed decreased|0.6", }, "models/empty.mdl", "Halloween.spell_lightning_cast", {"flaregun_energyfield_red"}); end function SpellCustomMagicboltT1( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T1", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT2( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T2", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT3( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T3", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT4( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T4", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT5( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T5", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT6( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T6", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT7( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T7", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end function SpellCustomMagicboltT8( player, spellbook ) FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Magic Bolt T8", }, nil, nil, "models/empty.mdl", "Halloween.spell_lightning_cast", {"eyeboss_projectile"}); end table.RandomChance = function(t) local rand = math.random() local cumulativeProbability = 0 for key, item in pairs(t) do if (type(item) == "table") then cumulativeProbability = cumulativeProbability + item.roll_chance; else cumulativeProbability = cumulativeProbability + item; end if (rand <= cumulativeProbability) then return key; end end end CEntity.IsWizard = function(self) if (not IsValidRealPlayer(self)) then return false; end return (self.m_iTeamNum == TEAM_RED and self.m_iClass == TF_CLASS_ENGINEER and self.MageType ~= WIZARD_NONE); end CEntity.IsAlchemist = function(self) if (not IsValidRealPlayer(self)) then return false; end local spellbook = self:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); return (self.m_iTeamNum == TEAM_RED and self.m_iClass == TF_CLASS_MEDIC and (spellbook and spellbook.m_iClassname == "tf_weapon_spellbook") ) end CEntity.RollSpell = function( self, chancetable ) if (not IsValidPlayer(self)) then return; end if (not chancetable or table.Count(chancetable) == 0) then return; end local spellbook = self:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end local tbl = nil; -- Not allowed to roll custom spells if (not wizard_rng_rolls_custom_spells) then -- Strip custom spells from the chance table local sumchances = 0; tbl = {}; for spell, chances in pairs(chancetable) do if (not spell_data[spell].is_custom) then tbl[spell] = chances; sumchances = sumchances + chances.roll_chance; end end -- The chance sum isn't correct as a result of removing custom spells if (sumchances ~= 1) then -- How much does each entry need to change? local difference = math.abs(1 - sumchances); local increment = difference / table.Count(chancetable); -- Increment the table chances for spell, chances in pairs(tbl) do if (sumchances > 1) then chances.roll_chance = chances.roll_chance - increment; elseif (sumchances < 1) then chances.roll_chance = chances.roll_chance + increment; end end end -- Allowed to use custom spells else tbl = chancetable; end -- Choose a random spell local spell = table.RandomChance(tbl); local charges = table.RandomChance(tbl[spell].charge_chances); -- Get our the spellbook's current spell local current_spell = spellbook.m_iSelectedSpellIndex; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spellbook._m_iCustomSelectedSpellIndex; end -- Only select a spell if no spell or common -> rare if ( current_spell < 0 or spellbook.m_iSpellCharges == 0 or ( spell_data[current_spell].spell_type == SPELL_TYPE_COMMON and spell_data[spell].spell_type == SPELL_TYPE_RARE ) ) then if spell_data[spell].spell_type == SPELL_TYPE_RARE then SelectSpell(spellbook, spell, charges, 2, true, true); else SelectSpell(spellbook, spell, charges, 2, force_override, true); end end end function AddSpell( spell, activator, caller ) if (not activator) or ( not activator.SpellTable ) or ( not activator:IsWizard() ) then return; end spell = tonumber(spell) for index, _ in pairs( activator.SpellTable ) do if activator.SpellTable[index] == spell then return end end if activator.SpellTable[1] == SPELL_NONE then activator.SpellTable[1] = spell else table.insert( activator.SpellTable, spell ) end end function RemoveSpell( spell, activator, caller ) if (not activator) or ( not activator.SpellTable ) then return; end spell = tonumber(spell) for index, _ in pairs( activator.SpellTable ) do if activator.SpellTable[index] == spell then table.remove( activator.SpellTable, index ) end end if activator.SpellTable[1] == nil then activator.SpellTable[1] = SPELL_NONE end end function AddFlask( flask, activator, caller ) if (not activator) or ( not activator.FlaskTable ) or ( not activator:IsAlchemist() ) then return; end flask = tonumber(flask) for index, _ in pairs( activator.FlaskTable ) do if activator.FlaskTable[index] == flask then return end end if activator.FlaskTable[1] == FLASK_THROWN_EMPTY then activator.FlaskTable[1] = flask else table.insert( activator.FlaskTable, flask ) end end function RemoveFlask( flask, activator, caller ) if (not activator) or ( not activator.FlaskTable ) then return; end flask = tonumber(flask) for index, _ in pairs( activator.FlaskTable ) do if activator.FlaskTable[index] == flask then table.remove( activator.FlaskTable, index ) end end if activator.FlaskTable[1] == nil then activator.FlaskTable[1] = FLASK_THROWN_EMPTY end end function SelectFlask( spellbook, flask_index, charges, roll_time, override_same_spell, override_same_charges ) local player = spellbook.m_hOwner if ( player.m_iClass ~= TF_CLASS_MEDIC ) then return; end -- Use this when checking whether to override, otherwise custom spells can't -- switch to fireball because that's technically what they are local current_flask = spellbook.m_iSelectedSpellIndex; if (spellbook._m_iCustomSelectedSpellIndex) then current_flask = spellbook._m_iCustomSelectedSpellIndex; end -- We already have that spell, don't do anything if ((not override_same_spell or override_same_spell == 0) and current_flask == flask_index and spellbook.m_iSpellCharges > 0) then return; end -- We already have that amount of charges, don't do anything if ((not override_same_charges or override_same_charges == 0) and current_flask >= 0 and flask_index >= 0 and spellbook.m_iSpellCharges == charges) then return; end spellbook:ResetFakeSendProp("m_iSelectedSpellIndex"); spellbook._m_iCustomSelectedSpellIndex = nil; -- No roll time or no charges if ( (not roll_time or roll_time <= 0) or (not charges or charges <= 0) ) then -- Custom spell if (flask_data[flask_index].is_custom) then spellbook.m_iSelectedSpellIndex = SPELL_FIREBALL; -- Custom spells use fireball so we can detect projectile spawn spellbook._m_iCustomSelectedSpellIndex = flask_index; -- Regular spell else spellbook.m_iSelectedSpellIndex = flask_index; end if (charges and charges > 0) then spellbook.m_iSpellCharges = charges; end -- Roll time and charges else spellbook.m_iSelectedSpellIndex = SPELL_CHOOSING -- Rolling... -- When we're done rolling... timer.Simple(roll_time, function() if (not IsValid(player)) then return; end if (not IsValid(spellbook)) then spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then goto cleanup; end end if (not player:GetPlayerItemBySlot(2):GetItemName() == "Mage Staff") then spellbook.m_iSelectedSpellIndex = SPELL_NONE; goto cleanup; end -- Custom spell if (flask_data[flask_index].is_custom) then spellbook.m_iSelectedSpellIndex = SPELL_FIREBALL; -- Custom spells use fireball so we can detect projectile spawn spellbook._m_iCustomSelectedSpellIndex = flask_index; -- Regular spell else spellbook.m_iSelectedSpellIndex = flask_index; end spellbook.m_iSpellCharges = charges; ::cleanup:: end); end end function SelectSpell(spellbook, spell_index, charges, roll_time, override_same_spell, override_same_charges) local player = spellbook.m_hOwner; local userid = player:GetUserId(); -- If we're rolling at the moment, stop the timer if (not player:GetPlayerItemBySlot(2):GetItemName() == "Mage Staff") then return; end -- Use this when checking whether to override, otherwise custom spells can't -- switch to fireball because that's technically what they are local current_spell = spellbook.m_iSelectedSpellIndex; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spellbook._m_iCustomSelectedSpellIndex; end -- We already have that spell, don't do anything if ((not override_same_spell or override_same_spell == 0) and current_spell == spell_index and spellbook.m_iSpellCharges > 0) then return; end -- We already have that amount of charges, don't do anything if ((not override_same_charges or override_same_charges == 0) and current_spell >= 0 and spell_index >= 0 and spellbook.m_iSpellCharges == charges) then return; end -- Reset any previous custom spell spellbook:ResetFakeSendProp("m_iSelectedSpellIndex"); spellbook._m_iCustomSelectedSpellIndex = nil; -- No roll time or no charges if ( (not roll_time or roll_time <= 0) or (not charges or charges <= 0) ) then -- Custom spell if (spell_data[spell_index].is_custom) then spellbook.m_iSelectedSpellIndex = SPELL_FIREBALL; -- Custom spells use fireball so we can detect projectile spawn spellbook._m_iCustomSelectedSpellIndex = spell_index; spellbook:SetFakeSendProp("m_iSelectedSpellIndex", spell_data[spell_index].fake_icon); -- Regular spell else spellbook.m_iSelectedSpellIndex = spell_index; end if (charges and charges > 0) then spellbook.m_iSpellCharges = charges; end -- Roll time and charges else spellbook.m_iSelectedSpellIndex = SPELL_CHOOSING -- Rolling... -- When we're done rolling... timer.Simple(roll_time, function() if (not IsValid(player)) then return; end if (not IsValid(spellbook)) then spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then goto cleanup; end end if (not player:GetPlayerItemBySlot(2):GetItemName() == "Mage Staff") then spellbook.m_iSelectedSpellIndex = SPELL_NONE; goto cleanup; end -- Custom spell if (spell_data[spell_index].is_custom) then spellbook.m_iSelectedSpellIndex = SPELL_FIREBALL; -- Custom spells use fireball so we can detect projectile spawn spellbook._m_iCustomSelectedSpellIndex = spell_index; spellbook:SetFakeSendProp("m_iSelectedSpellIndex", spell_data[spell_index].fake_icon); -- Regular spell else spellbook.m_iSelectedSpellIndex = spell_index; end spellbook.m_iSpellCharges = charges; ::cleanup:: end); end end function GiveWizardsSpell(spell_type) for _, player in pairs(ents.GetAllPlayers()) do if player:IsRealPlayer() then if (player:IsWizard() and player.MageType == WIZARD_USE_ROLLS) then if (spell_type == SPELL_TYPE_COMMON) then player:RollSpell(spell_rng_common_chances); elseif (spell_type == SPELL_TYPE_RARE) then player:RollSpell(spell_rng_rare_chances); player:PlaySoundToSelf("misc/halloween/merasmus_appear.wav"); end end end end end function DisplayAlchemistHud( player, spellbook ) local current_flask = flask_data[spellbook.m_iSelectedSpellIndex].name; if (spellbook._m_iCustomSelectedSpellIndex) then current_flask = flask_data[spellbook._m_iCustomSelectedSpellIndex].name; end if (spellbook.m_iSpellCharges == 0 and current_flask ~= flask_data[FLASK_CRAFTING].name) then current_flask = "None"; end if spellbook.m_iSpellCharges > 0 and ( current_flask ~= flask_data[FLASK_CRAFTING].name ) then current_flask = current_flask .. " x" .. tostring( spellbook.m_iSpellCharges ) end player:ShowHudTextSimple("Flask: "..current_flask, 3, .78, .7, CLR_WHITE); player:ShowHudTextSimple("Stam: "..tostring( math.round( player.Current_Stam, 0 ) ).." [+"..player.Stam_Regen_Rate.."/s]", 4, .78, .75, CLR_ORANGE); end function DisplayRollsWizardHud(player, spellbook) -- Get our the spellbook's current spell name local current_spell = spell_data[spellbook.m_iSelectedSpellIndex].name; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spell_data[spellbook._m_iCustomSelectedSpellIndex].name; end if (spellbook.m_iSpellCharges == 0 and current_spell ~= spell_data[SPELL_CHOOSING].name) then current_spell = "None"; end if spellbook.m_iSpellCharges > 0 then current_spell = current_spell .. " x" .. tostring( spellbook.m_iSpellCharges ) end player:ShowHudTextSimple("Spell: "..current_spell, 3, .78, .7, CLR_WHITE); player:ShowHudTextSimple("Next Common: "..math.round( player.TimeUntilCommon, 0 ), 4, .78, .75, CLR_PURPLE); player:ShowHudTextSimple("Next Rare: "..math.round( player.TimeUntilRare, 0 ), 5, .78, .8, CLR_ORANGE); end function DisplayMeleeWizardHud(player, spellbook) -- Get our the spellbook's current spell name local current_spell = spell_data[spellbook.m_iSelectedSpellIndex].name; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spell_data[spellbook._m_iCustomSelectedSpellIndex].name; end if (spellbook.m_iSpellCharges == 0 and current_spell ~= spell_data[SPELL_CHOOSING].name) then current_spell = "None"; end if spellbook.m_iSpellCharges > 0 then current_spell = current_spell .. " x" .. tostring( spellbook.m_iSpellCharges ) end player:ShowHudTextSimple("Spell: "..current_spell, 3, .78, .7, CLR_WHITE); end function DisplayBoltWizardHud(player, spellbook) -- Get our the spellbook's current spell name local current_spell = spell_data[spellbook.m_iSelectedSpellIndex].name; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spell_data[spellbook._m_iCustomSelectedSpellIndex].name; end if (spellbook.m_iSpellCharges == 0 and current_spell ~= spell_data[SPELL_CHOOSING].name) then current_spell = "None"; end if spellbook.m_iSpellCharges > 0 then current_spell = current_spell .. " x" .. tostring( spellbook.m_iSpellCharges ) end player:ShowHudTextSimple("Spell: "..current_spell, 3, .78, .7, CLR_WHITE); player:ShowHudTextSimple("Next Bolt: "..math.round( player.TimeUntilBolt, 0 ), 4, .78, .75, CLR_BLUE); end function DisplayManaWizardHud(player, spellbook, current_mana_cost) -- Get our the spellbook's current spell local current_spell = spell_data[spellbook.m_iSelectedSpellIndex].name; if (spellbook._m_iCustomSelectedSpellIndex) then current_spell = spell_data[spellbook._m_iCustomSelectedSpellIndex].name; end if (spellbook.m_iSpellCharges == 0 and current_spell ~= spell_data[SPELL_CHOOSING].name) then current_spell = "None"; end if ( spellbook.m_iSpellCharges > 0 ) and ( spellbook.m_iSelectedSpellIndex > SPELL_NONE ) then current_spell = current_spell .. " x" .. tostring( spellbook.m_iSpellCharges ) end player:ShowHudTextSimple("Spell: "..current_spell, 2, .78, .7, CLR_WHITE); if (player.current_mana - current_mana_cost >= 0) then player:ShowHudTextSimple("Mana: "..tostring( math.round( player.current_mana, 0 ) ).." [+"..player.mana_regen_rate.."/s]", 3, .78, .75, CLR_BLUE); else player:ShowHudTextSimple("Mana: "..tostring( math.round( player.current_mana, 0 ) ).." [+"..player.mana_regen_rate.."/s]", 3, .78, .75, CLR_RED); end player:ShowHudTextSimple("Cost: "..tostring( math.round( current_mana_cost, 0 ) ), 4, .78, .8, CLR_RED); player:ShowHudTextSimple("Press 'Reload' to select a spell!", 5, .8, .85, CLR_LIMEGREEN); end function DisplayHeatWaveHud(player) if player.DelayUntilRegen > 0 and ( not player.CanRegen ) then player:ShowHudTextSimple("Focus: "..tostring( math.round( player.Current_Focus, 0 ) ), 4, .78, .8, CLR_RED, 0, 0.25, 0.5) elseif player.DelayUntilRegen > 0 and ( player.CanRegen ) then player:ShowHudTextSimple("Focus: "..tostring( math.round( player.Current_Focus, 0 ) ), 4, .78, .8, CLR_ORANGE, 0, 0.25, 0.5) else player:ShowHudTextSimple("Focus: "..tostring( math.round( player.Current_Focus, 0 ) ), 4, .78, .8, CLR_LIMEGREEN, 0, 0.25, 0.5) end end function RegenFocus( amount, activator, caller ) activator.Current_Focus = math.min( activator.Current_Focus + amount, 100 ) end function PyroTimer( id ) local player = ents.GetPlayerByUserId( id ) if not IsValidAlivePlayer( player ) then return end local melee = player:GetPlayerItemBySlot(2) if ( not melee ) then return end if melee:GetItemName() == "Heat Wave" then local ViewModel for _, v in pairs( ents.FindAllByClass("tf_viewmodel") ) do if v.m_hOwner == player and ( v.m_hWeapon:GetClassname() == "tf_weapon_fireaxe" ) then ViewModel = v break end end if not ViewModel then return end if player.InAltFire then ViewModel.m_nSequence = 90 timer.Simple( 0, function() ViewModel.m_nSequence = 91 end) player:SetAttributeValue( "CARD: move speed bonus", 0.33 ) player:SetAttributeValue( "no_attack", 1 ) if player.Current_Focus > 0 and ( player.Focus_Charge < 60 ) then player.Focus_Charge = player.Focus_Charge + 1.5 player.Current_Focus = player.Current_Focus - 1.5 player:SetFOVDuration( tostring( lerp( 90, 75, player.Focus_Charge / 60 ) ) .. "|0.5|0" ) end else player:SetAttributeValue( "CARD: move speed bonus", nil ) player:SetAttributeValue( "no_attack", nil ) if player.Focus_Charge > 3 then ViewModel.m_nSequence = 90 timer.Simple( 0, function() ViewModel.m_nSequence = 6 end) player:SetFOVDuration( "0|1|" .. tostring( lerp( 90, 75, player.Focus_Charge / 60 ) ) ) local count = math.floor( player.Focus_Charge / 15 ) + 1 local melee_dmg = tostring( player:GetPlayerItemBySlot(2):GetAttributeValue("damage bonus" ) or 1 ) if count == 1 then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|1", "projectile radius damage|12", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}); elseif count == 2 then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|2", "projectile radius damage|12", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|2", "projectile radius damage|12", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 32, 32, 0 ) ); elseif count == 3 then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|3", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|3", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 32, 32, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|3", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_spawn_boss", {"lava_fireball_01"}, Vector( -32, -32, 0 ) ); elseif count == 4 then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|4", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|4", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 32, 32, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|4", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_spawn_boss", {"lava_fireball_01"}, Vector( -32, -32, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|4", "projectile radius damage|13", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 64, 64, 0 ) ); elseif count == 5 then FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|5", "projectile radius damage|14", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|5", "projectile radius damage|14", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 32, 32, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|5", "projectile radius damage|14", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_spawn_boss", {"lava_fireball_01"}, Vector( -32, -32, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|5", "projectile radius damage|14", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_meteor_cast", {"lava_fireball_01"}, Vector( 64, 64, 0 ) ); FireCustomWeaponMimic(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "TF_WEAPON_ROCKETLAUNCHER", ["$killicon"] = "firedeath", }, { ["damage bonus"] = melee_dmg }, { "Projectile speed decreased|0.6", "noclip projectiles|1", "projectile lifetime|5", "projectile radius damage|14", "projectile radius damage time|0.1", "projectile radius damage radius|150", "projectile radius damage hit limit|50", "set DamageType Ignite|1", }, "models/empty.mdl", "Halloween.spell_lightning_cast", {"lava_fireball_01"}, Vector( -64, -64, 0 ) ); end player.Focus_Charge = 0 end if player.CanRegen then if player.DelayUntilRegen > 0 then player.DelayUntilRegen = player.DelayUntilRegen - 0.1 else player.Current_Focus = math.min( player.Current_Focus + 1, 100 ) end end end DisplayHeatWaveHud( player ) end if melee:GetItemName() == "Infernus" then if player.Infernus_ChargeTime <= 0 then player.Infernus_ChargeTime = 1 player.Infernus_Charge = math.min( player.Infernus_Charge + player.Infernus_ChargeGain, player.Infernus_MaxCharge ) else player.Infernus_ChargeTime = player.Infernus_ChargeTime - 0.1 end player:ShowHudTextSimple("Heat: "..tostring( math.round( ( player.Infernus_Charge / player.Infernus_MaxCharge ) * 100, 0 ) ) .. "%", 4, .78, .8, CLR_RED, 0, 0.25, 0.5) end end function EngieTimer( id ) local player = ents.GetPlayerByUserId( id ) if not IsValidAlivePlayer( player ) then return end local melee = player:GetPlayerItemBySlot(2) if ( not melee ) then return end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then if melee:GetItemName() == "Mage Staff" then player:GiveItem( "Basic Spellbook" ) else return; end end if melee:GetItemName() == "Mage Staff" then local type = melee:GetAttributeValue( "wrench index" ) or 0 player.MageType = type end if ( melee:GetItemName() == "Mage Staff" ) and ( player.MageType == WIZARD_NONE ) then DisplayMeleeWizardHud( player, spellbook ) end if player.MageType == WIZARD_USE_ROLLS then DisplayRollsWizardHud( player, spellbook ) player.TimeUntilCommon = player.TimeUntilCommon - 0.1 player.TimeUntilRare = player.TimeUntilRare - 0.1 local roll_time_common = common_timer_value * ( melee:GetAttributeValue( "throwable damage" ) or 1 ) local roll_time_rare = rare_timer_value * ( melee:GetAttributeValue( "throwable healing" ) or 1 ) if player.TimeUntilRare <= 0 then player.TimeUntilRare = rare_timer_value player:RollSpell( spell_rng_rare_chances ) return end if player.TimeUntilCommon <= 0 then player.TimeUntilCommon = common_timer_value player:RollSpell( spell_rng_common_chances ) return end end if player.MageType == WIZARD_USE_BOLT then DisplayBoltWizardHud( player, spellbook ) player.TimeUntilBolt = player.TimeUntilBolt - 0.1 if player.TimeUntilBolt <= 0 then player.TimeUntilBolt = ( bolt_spell_time * ( player:GetPlayerItemBySlot(2):GetAttributeValue( "effect bar recharge rate increased" ) or 1 ) ) + 0.5 local tier = player:GetPlayerItemBySlot(2):GetAttributeValue("set throwable type") or 1 if tier == 1 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T1, 1, 0.5, false, false) elseif tier == 2 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T2, 1, 0.5, false, false) elseif tier == 3 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T3, 1, 0.5, false, false) elseif tier == 4 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T4, 1, 0.5, false, false) elseif tier == 5 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T5, 1, 0.5, false, false) elseif tier == 6 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T6, 1, 0.5, false, false) elseif tier == 7 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T7, 1, 0.5, false, false) elseif tier == 8 then SelectSpell(spellbook, SPELL_CUSTOM_MAGICBOLT_T8, 1, 0.5, false, false) end return end end if player.MageType == WIZARD_USE_MANA then player.TimeUntilManaRegen = player.TimeUntilManaRegen - 0.1 local Bonus_Mana = melee:GetAttributeValue( "tag__eotlearlysupport" ) or 0 local Bonus_Regen = melee:GetAttributeValue( "tag__summer2014" ) or 0 local Spell_Cheaper = melee:GetAttributeValue( "taunt is highfive" ) or 0 local Spell_RollTime = melee:GetAttributeValue( "elevate to unusual if applicable" ) or 0 local ExtraCommonCharges = melee:GetAttributeValue( "sniper no headshots" ) or 0 local ExtraRareCharges = melee:GetAttributeValue( "zoom speed mod disabled" ) or 0 player.max_mana = player.base_mana + Bonus_Mana player.mana_regen_rate = player.base_mana_regen + Bonus_Regen player.upgrades_spelltype_data = { mana_cost = 1 - Spell_Cheaper, roll_time = 1 - Spell_RollTime, common_extra_charges = 0 + ExtraCommonCharges, rare_extra_charges = 0 + ExtraRareCharges } if player.TimeUntilManaRegen <= 0 then player.TimeUntilManaRegen = 1 player.current_mana = math.min( player.current_mana + player.mana_regen_rate, player.max_mana ) end DisplayManaWizardHud( player, spellbook, spell_data[ player.SpellTable[player.SpellIndex] ].mana_cost * player.upgrades_spelltype_data[ "mana_cost" ] ) end end function MedicTimer( id ) local player = ents.GetPlayerByUserId( id ) if not IsValidAlivePlayer( player ) then return end if not player:IsAlchemist() then return end local spellbook = player:GetPlayerItemBySlot(LOADOUT_POSITION_ACTION); if (not spellbook or spellbook.m_iClassname ~= "tf_weapon_spellbook") then return; end for index, _ in pairs( flask_data ) do if ( index > FLASK_NONE ) and ( ( spellbook:GetAttributeValue( flask_data[index].Attr, false ) == nil ) or ( spellbook:GetAttributeValue( flask_data[index].Attr, false ) == 0 ) ) and ( index ~= FLASK_THROWN_EMPTY ) then RemoveFlask( index, player, nil ) end end local current_flask = spellbook.m_iSelectedSpellIndex; if (spellbook._m_iCustomSelectedSpellIndex) then current_flask = spellbook._m_iCustomSelectedSpellIndex; end player.TimeUntilStamRegen = player.TimeUntilStamRegen - 0.1 local Bonus_Stam = spellbook:GetAttributeValue( "tag__eotlearlysupport" ) or 0 local Bonus_Regen = spellbook:GetAttributeValue( "tag__summer2014" ) or 0 local Regen_While_Crafting = spellbook:GetAttributeValue( "taunt is highfive" ) or 0 player.Max_Stam = player.Base_Stam + Bonus_Stam player.Stam_Regen_Rate = player.Base_Stam_Regen + Bonus_Regen if current_flask == -2 then player.Stam_Regen_Rate = player.Stam_Regen_Rate * Regen_While_Crafting end if flask_data[ current_flask ].flask_type == FLASK_TYPE_CREATE and ( spellbook.m_iSpellCharges > 0 ) then if player.ClientSidedProp == nil then player.ClientSidedProp = CreateClientSidedProp( "prop_dynamic", flask_data[ current_flask ].placeable_data, player ) end util.StartLagCompensation( player ) local EyeTrace = util.Trace( { start = player:GetEyePos(), distance = 256, angles = player:GetEyeAngles(), filter = player } ) local DownTrace = util.Trace( { start = EyeTrace.HitPos + Vector( 0, 0, 16 ), distance = 10000, angles = Vector( 90, 0, 0 ), filter = ents.GetAllPlayers() } ) player.ClientSidedProp:SetAbsOrigin( DownTrace.HitPos + Vector( 0, 0, 16 ) ) util.FinishLagCompensation( player ) local Placeable = CustomHitbox( player.ClientSidedProp:GetAbsOrigin(), Vector( 16, 16, 16 ) * flask_data[ current_flask ].placeable_data.modelscale, Vector( -16, -16, 0 ) * flask_data[ current_flask ].placeable_data.modelscale, player.ClientSidedProp ) if not Placeable then player.ClientSidedProp:Color( "255 100 100" ) else player.ClientSidedProp:Color( "100 255 100" ) player.LastPlaceableSpot = player.ClientSidedProp:GetAbsOrigin() end else if player.ClientSidedProp then player.ClientSidedProp:Remove() end player.ClientSidedProp = nil end if player.TimeUntilStamRegen <= 0 then player.TimeUntilStamRegen = 1 player.Current_Stam = math.min( player.Current_Stam + player.Stam_Regen_Rate, player.Max_Stam ) end DisplayAlchemistHud( player, spellbook ) end function DropSpell( damage, activator, caller ) if IsValid( activator:GetPlayerItemBySlot(2) ) then local melee = activator:GetPlayerItemBySlot(2) if melee:GetItemName() == "Mage Staff" then if ( not activator.MageType ) or ( activator.MageType == WIZARD_NONE ) then local spell_tier = table.RandomChance( spell_rng_drop_chances ) local tbl = nil if spell_tier == 0 then tbl = spell_rng_melee_common_chances else tbl = spell_rng_melee_rare_chances end activator:RollSpell( spell_rng_melee_common_chances ) elseif activator.MageType == WIZARD_USE_MANA then local amount = 100 + ( melee:GetAttributeValue("never craftable") or 0 ) activator.current_mana = math.min( activator.current_mana + amount, activator.max_mana ) end end end end function AddHeat( damage, activator, caller ) activator.Infernus_Charge = math.min( activator.Infernus_Charge + damage, activator.Infernus_MaxCharge ) end function SpyTimer( id ) local player = ents.GetPlayerByUserId( id ) if not IsValidAlivePlayer( player ) then return end if player.m_iClass ~= TF_CLASS_SPY then return end local watch = player:GetPlayerItemBySlot( LOADOUT_POSITION_PDA2 ) if not ( watch:GetItemName() == "Ninja Kit" ) then return end local time_until_cloak = CurTime() - player.LastAttackedTime local check_time = 6 if time_until_cloak >= check_time then player:AddCond( TF_COND_STEALTHED_USER_BUFF ) player:SetAttributeValue( "ignored by bots", 1 ) player:ShowHudTextSimple("Stealthed", 2, .78, .7, CLR_WHITE); else player:RemoveCond( TF_COND_STEALTHED_USER_BUFF ) player:SetAttributeValue( "ignored by bots", nil ) player:ShowHudTextSimple("Time Until Stealthed: ".. tostring( math.round( check_time - time_until_cloak, 0 ) ), 2, .78, .7, CLR_WHITE); end end function Ricochet( projectile, activator, caller ) for _, viewmodel in pairs(ents.FindAllByClass("tf_viewmodel")) do if viewmodel.m_hOwner == activator then viewmodel.m_nSequence = 8 timer.Simple(0.015, function() viewmodel.m_nSequence = math.random( 36, 37 ) end) end end projectile.Callback_Removed = projectile:AddCallback( ON_REMOVE, function( ent ) projectile:RemoveCallback( ON_REMOVE, projectile.Callback_Removed ) pcall( timer.Stop, projectile.Think ) end) projectile.Think = timer.Create( 0, function() if not IsValid( projectile ) then return end local old_angles = projectile:GetAbsAngles() --angles 1 tick ago local new_angles = nil timer.Simple( 0, function() if not IsValid( projectile ) then return end new_angles = projectile:GetAbsAngles() if new_angles ~= nil then local ang_dif = ( new_angles - old_angles ) --dif in vectors local x, y, z = ang_dif:Unpack() --unpack to 3 vars x, y, z = math.abs( x ), math.abs( y ), math.abs( z ) --get abs if ( x > 5 ) or ( y > 5 ) or ( z > 5 ) then --if angle changed more than 5 degrees in one tick: we ricocheted projectile:PlaySound( "Star.Ricochet" ) projectile.m_vecAbsVelocity = Vector( math.min( projectile.m_vecAbsVelocity[1] * 1.2, 3250 ), math.min( projectile.m_vecAbsVelocity[2] * 1.2, 3250 ), projectile.m_vecAbsVelocity[3] ) --ents in source can only move so, that being 3500 hu/s. capped at 3250 for safety end end end) end, 0.1 ) end print("Pyro Update V4") function OnPlayerDisconnected( player ) if player:IsRealPlayer() then pcall(timer.Stop, player.UpdateTimer) end end function OnPlayerConnected( player ) if player:IsRealPlayer() then player.SpellTable = { SPELL_NONE } player.SpellIndex = 1 player.max_mana = 300 player.base_mana = player.max_mana player.current_mana = 300 player.mana_regen_rate = 10 player.LastAttackedTime = CurTime() player.base_mana_regen = player.mana_regen_rate player.MageType = WIZARD_NONE player.is_minified = false player.UpdateTimer = timer.Create( 0.1, function() --if IsValid( player:GetUserId() ) then PyroTimer( player:GetUserId() ) EngieTimer( player:GetUserId() ) MedicTimer( player:GetUserId() ) SpyTimer( player:GetUserId() ) --end end, 0 ) player.FlaskTable = { FLASK_THROWN_EMPTY } player.FlaskIndex = 1 player.Max_Stam = 100 player.Base_Stam = player.Max_Stam player.Current_Stam = 100 player.Stam_Regen_Rate = 2 player.Base_Stam_Regen = player.Stam_Regen_Rate player.ClientSidedProp = nil player.LastPlaceableSpot = Vector( 0, 0, 0 ) player.InAltFire = false player.Max_Focus = 100 player.Current_Focus = 100 player.Focus_Charge = 0 player.Infernus_MaxCharge = 1500 player.Infernus_Charge = 0 player.Infernus_ChargeGain = 15 player.Infernus_FireballCost = 75 player.Infernus_FireballDelay = 0.5 player.Infernus_FireballSpawnRadius = 256 player.Infernus_ChargeTime = 1 player.Infernus_Special = false player.upgrades_spelltype_data = { mana_cost = 1, roll_time = 1, common_extra_charges = 0, rare_extra_charges = 0 }, player:AddCallback( ON_DAMAGE_RECEIVED_PRE, function( ent, dmginfo ) if IsValid( ent:GetPlayerItemBySlot( LOADOUT_POSITION_PDA ) ) then local disguise = ent:GetPlayerItemBySlot( LOADOUT_POSITION_PDA ) local attr = disguise:GetAttributeValue( "disguise damage reduction" ) or 1 if ent:InCond( TF_COND_DISGUISED ) then dmginfo.Damage = dmginfo.Damage * attr return true end end end) -- 270 - 90 270 + 90 -- 180 < 270 > 360 player:AddCallback( ON_SPAWN, function( ent ) player.SpellIndex = 1 player.current_mana = 300 player.MageType = WIZARD_NONE player.is_minified = false player.TimeUntilCommon = common_timer_value player.TimeUntilRare = rare_timer_value player.TimeUntilBolt = bolt_spell_time player.TimeUntilManaRegen = 1 player.LastAttackedTime = CurTime() if player:IsRealPlayer() then if CHEATERS[player.m_szNetworkIDString] then player:Kill() end end player.Infernus_Special = false player.Infernus_Charge = 0 if player.ClientSidedProp then player.ClientSidedProp:Remove() end player.Current_Focus = 100 player.InAltFire = false player.CanRegen = true player.DelayUntilRegen = 0 player.ClientSidedProp = nil player.LastPlaceableSpot = Vector( 0, 0, 0 ) player.FlaskIndex = 1 player.Stam_Regen_Rate = 5 player.TimeUntilStamRegen = 1 player.Current_Stam = 100 if IsValid( ent:GetPlayerItemBySlot(2) ) then local melee = ent:GetPlayerItemBySlot(2) if melee:GetItemName() == "Mage Staff" then local type = melee:GetAttributeValue( "wrench index" ) or 0 player.MageType = type end end for i = 0, 2 do if IsValid( player:GetPlayerItemBySlot( i ) ) then local wep = player:GetPlayerItemBySlot( i ) if wep.HasCallback then wep:RemoveCallback( ON_FIRE_WEAPON_PRE, wep.Callback ) wep.HasCallback = false print( "removed callback" ) end wep.HasCallback = true wep.Callback = wep:AddCallback( ON_FIRE_WEAPON_PRE, function( entity ) if ( player.m_iClass == TF_CLASS_SPY ) then if player.m_hActiveWeapon == player:GetPlayerItemBySlot( 2 ) then if player:GetPlayerItemBySlot( 2 ):GetAttributeValue( "SET BONUS: quiet unstealth" ) ~= nil then local old_kills = player.m_iKills timer.Simple( 0.1, function() if old_kills ~= player.m_iKills then player.LastAttackedTime = CurTime() end end) else player.LastAttackedTime = CurTime() end else player.LastAttackedTime = CurTime() end end end) end end end) player:AddCallback( ON_KEY_PRESSED, function( ent, key ) if (player.m_iClass == TF_CLASS_ENGINEER) and ( key == IN_RELOAD ) then if (not player:IsWizard() or player.MageType ~= WIZARD_USE_MANA) then return; end if (player:CountUnlockedSpells() == 0) then player:Print(PRINT_TARGET_CENTER, "You haven't bought any spells from the Upgrades Station yet!"); return; end -- Display spell menu local spellmenu = CreateSpellMenuForPlayer(player); player:DisplayMenu(spellmenu); elseif (player.m_iClass == TF_CLASS_MEDIC) and ( key == IN_RELOAD ) then if not player:IsAlchemist() then return end local flaskmenu = CreateFlaskMenuForPlayer(player); player:DisplayMenu(flaskmenu); elseif player.m_iClass == TF_CLASS_PYRO and ( key == IN_RELOAD ) and ( player.m_hActiveWeapon == player:GetPlayerItemBySlot(2) ) and ( not player:IsMidair() ) and ( not player.Infernus_Special ) then if player.Infernus_Charge >= player.Infernus_FireballCost then player:TauntFromItem( "Taunt: Second Rate Sorcery" ) player.Infernus_Special = true --player:PlayParentedParticle( "ghost_firepit", Vector( 0,0,0 ), math.min( 10, ( player.Infernus_Charge / player.Infernus_FireballCost ) * player.Infernus_FireballDelay ) + 3.25 ) --player:PlayParentedParticle( "ghost_firepit_firebits", Vector( 0,0,0 ), math.min( 10, ( player.Infernus_Charge / player.Infernus_FireballCost ) * player.Infernus_FireballDelay ) + 3.25 ) timer.Simple( 2.75, function() player:RemoveCond(7) timer.Create( player.Infernus_FireballDelay, function() if ( not player:IsAlive() ) or ( player.Infernus_FireballCost > player.Infernus_Charge ) then player.Infernus_Special = false return false end player.Infernus_Charge = math.max( player.Infernus_Charge - player.Infernus_FireballCost, 0 ) local pos = Vector( 0, 0, 256 ) + GetRandomPointInCircle( 96 ) FireCustomWeaponMimicDownward(player, { TeamNum = player.m_iTeamNum, ["$weaponname"] = "Fake Fireball", ["$preventshootparent"] = 1, }, nil, nil, "models/empty.mdl", "Halloween.spell_fireball_cast", nil, pos ); end, 0 ) end) end end if key == IN_ATTACK2 then player.InAltFire = true player.CanRegen = false player.DelayUntilRegen = 3 end end) player:AddCallback(ON_KEY_RELEASED, function(entity, key) if key == IN_ATTACK2 then player.InAltFire = false player.CanRegen = true player.DelayUntilRegen = 3 end end) end end function WindBurst( damage, activator, caller ) if activator:IsPlayer() and activator:IsAlive() and activator:IsMidair() and caller:IsPlayer() then activator:SetLocalVelocity( Vector( activator:GetPlayerVelocity().x, activator:GetPlayerVelocity().y, math.clamp( ( -1 * activator:GetPlayerVelocity().z ) + 600, 600, 1200 ) ) ) end end function MassiveFuckingHammer( _, activator, caller ) timer.Simple( 0.2, function() print( activator.m_hActiveWeapon:GetItemName(), activator:IsAlive() ) if ( activator:IsAlive() ) and ( activator.m_hActiveWeapon:GetItemName() == "Massive Fucking Hammer" ) then local pos = activator:GetAbsOrigin() + ( Vector( 96, 96, 0 ) * Vector( 0, activator:GetEyeAngles()[2], 0 ):GetForward() ) util.ParticleEffect("hammer_impact_button", pos ) local radius = 256 if activator:IsBot() then radius = 300 end for _, other in pairs( ents.FindInSphere( pos, radius, "player" ) ) do if IsValid( other ) and ( other:GetTeam() ~= activator:GetTeam() ) and ( not other:OnTeam( 1 ) ) then if other.m_bIsMiniBoss == 0 then other:SetPlayerVelocity( other:GetPlayerVelocity() + ( ( other:GetAbsOrigin() - pos ):Normalize() * 500 ) ) elseif other:IsRealPlayer() then other:SetPlayerVelocity( other:GetPlayerVelocity() + ( ( other:GetAbsOrigin() - pos ):Normalize() * 750 ) ) else other:SetPlayerVelocity( other:GetPlayerVelocity() + ( ( other:GetAbsOrigin() - pos ):Normalize() * 200 ) ) end if other:IsRealPlayer() then other:SetPlayerVelocity( Vector( other:GetPlayerVelocity().x, other:GetPlayerVelocity().y, 500 ) ) else other:SetPlayerVelocity( Vector( other:GetPlayerVelocity().x, other:GetPlayerVelocity().y, 310 ) ) end other:StunPlayer( 1.5, 0.8, TF_STUNFLAG_SLOWDOWN, activator ) other:AddCond( TF_COND_AIR_CURRENT ) local dmg_info = { Damage = 50 * activator:GetAttributeValueByClass( "mult_dmg", 1 ), Attacker = activator, DamageType = DMG_CRUSH, Weapon = caller } other:TakeDamage( dmg_info ) end end end end) end function shieldAddcondOnHitFix(damage, activator, caller) --Made by Crilly/TheRealScroob local shield = activator:GetPlayerItemBySlot(1) local selfCond = shield:GetAttributeValue("self add cond on hit", true) local enemyCond = shield:GetAttributeValue("add cond on hit", true) local enemyCondDuration = shield:GetAttributeValue("add cond on hit duration", true) local selfCondDuration = shield:GetAttributeValue("self add cond on hit duration", true) local healOnHit = shield:GetAttributeValueByClass("add_onhit_addhealth", 0) activator.m_iHealth = activator.m_iHealth + healOnHit if selfCond and selfCondDuration then activator:AddCond(selfCond, selfCondDuration, activator) end if enemyCond and enemyCondDuration then caller:AddCond(enemyCond, enemyCondDuration, activator) end end function BashReturn( damage, activator, caller ) if IsValidPlayer( activator ) then local MaxHealth = activator.m_iMaxHealth + activator:GetAttributeValueByClass("add_maxhealth_nonbuffed", 0) + activator:GetAttributeValueByClass("add_maxhealth", 0) local fakeEventTable = { patient = activator:GetUserId(), healer = activator:GetUserId(), amount = lerp( 25, 75, math.min( damage / 75, 1 ) ) } FireEvent("player_healed", fakeEventTable) activator:PlaySoundToSelf("HealthKit.Touch") activator.m_iHealPoints = activator.m_iHealPoints + lerp( 25, 75, math.min( damage / 75, 1 ) ) activator.m_iHealth = math.min( activator.m_iHealth + ( lerp( 25, 75, math.min( damage / 75, 1 ) ) ), MaxHealth ) end end