ClientPrint(null,3,"start reanimator setup") // ///////////////////// Debug /////////////////// //Setting a error handler allows us to view vscript error messages, even if we are not testing locally i.e. on potato testing server DynamicReanimators.DebugSteamIds <- {} DynamicReanimators.DebugSteamIds["[U:1:66915592]"] <- 1 seterrorhandler(function(e) { for (local player; player = Entities.FindByClassname(player, "player");) { if (DynamicReanimators.DebugSteamIds.rawin(NetProps.GetPropString(player, "m_szNetworkIDString"))) { local Chat = @(m) (printl(m), ClientPrint(player, 2, m)) ClientPrint(player, 3, format("\x07FF0000AN ERROR HAS OCCURRED [%s].\nCheck console for details", e)) Chat(format("\n====== TIMESTAMP: %g ======\nAN ERROR HAS OCCURRED [%s]", Time(), e)) Chat("CALLSTACK") local s, l = 2 while (s = getstackinfos(l++)) Chat(format("*FUNCTION [%s()] %s line [%d]", s.func, s.src, s.line)) Chat("LOCALS") if (s = getstackinfos(2)) { foreach (n, v in s.locals) { local t = type(v) t == "null" ? Chat(format("[%s] NULL" , n)) : t == "integer" ? Chat(format("[%s] %d" , n, v)) : t == "float" ? Chat(format("[%s] %.14g" , n, v)) : t == "string" ? Chat(format("[%s] \"%s\"", n, v)) : Chat(format("[%s] %s %s" , n, t, v.tostring())) } } return } } }) //PrecacheSound("mvm/mvm_revive.wav") //PrecacheSoundScript("MVM.PlayerRevived") //if("DynamicReanimators" in getroottable()) return ::DynamicReanimators <- { Cleanup = function() { // cleanup any persistent changes here // keep this at the end delete ::DynamicReanimators } OnGameEvent_recalculate_holidays = function(_) { if (GetRoundState() == 3) Cleanup() } numRevives = {} OnGameEvent_mvm_begin_wave = function(_) { numRevives = {} } /* { damageamount = 160 health = 0 weaponid = 76 attacker_player = 693 crit = 0 entindex = 456 } */ OnGameEvent_npc_hurt = function(params) { local ent = EntIndexToHScript(params.entindex) if(ent.GetClassname() == "$bot_npc") { //CzUtil.PrintTable(params) local scope = ent.GetScriptScope() if(("player" in scope) && scope.player.IsValid() && NetProps.GetPropInt(player, "m_lifeState") != 0) { local attacker = EntIndexToHScript(params.attacker_player) Reanimate(player, attacker, params.damageamount) ent.SetHealth(9999) } else if (("player" in scope) && scope.player.IsValid()) { EntFire("activator", "kill", null, 0, ent) } } } OnGameEvent_player_death = function(params) { local player = GetPlayerFromUserID(params.userid); ClientPrint(player, 3, "player died") EntFire("dynamicReanimatorMaker", "ForceSpawnAtEntityOrigin", "!activator", 0, player) } OnGameEvent_player_spawn = function(params) { local player = GetPlayerFromUserID(params.userid); player.ValidateScriptScope() if (player != null && player.IsValid() && !player.IsBotOfType(TF_BOT_TYPE)) //&& player.GetTeam() == 2 { } } SetupReanimator = function (player, hitEnt) { player.ValidateScriptScope(); player.GetScriptScope().reanimatorHitbox <- hitEnt; local reanimatorEnt = Entities.FindByClassnameNearest("entity_revive_marker", player.GetOrigin(), 150) if(reanimatorEnt == null) { // idk, I should throw an error or something ClientPrint(player,3,"no revive marker found") } else { player.GetScriptScope().reanimator <- reanimatorEnt local networkId = NetProps.GetPropString(player, "m_szNetworkIDString") if(networkId in numRevives) { // I can't figure out how to access the player level stats that track number of revives // so I will do it manually // according to the TF2 code, this is how much more health to add reanimatorEnt.SetMaxHealth(reanimatorEnt.GetMaxHealth() + (numRevives[networkId]*10.0) ) } } } Reanimate = function(deadplayer, healer, amount) { local playerscope = deadplayer.GetScriptScope() if("reanimator" in playerscope) { local reanimator = playerscope.reanimator if(reanimator.GetHealth() > reanimator.GetMaxHealth()) { EntFireByHandle(playerscope.reanimatorHitbox, "kill", null, 0.0, null, null) ManualRespawnPlayer(deadplayer, healer) return } local healAmt = amount //scale heal amount by distance local dist = (reanimator.GetOrigin() - healer.GetOrigin()).Length() dist = dist > 1500 ? 1500.0 : dist * 1.0 local ratio = dist/1500.0 < 0.3 ? 0.3 : dist/1500.0 healAmt *= ratio ClientPrint(null,3,reanimator.GetHealth()) reanimator.SetHealth(reanimator.GetHealth() + floor(healAmt)) if(NetProps.GetPropInt(deadplayer, "m_iObserverMode") > 2) { //m_iObserverMode > 2 (OBS_MODE_FREEZECAM) //m_hObserverTarget set to reviver NetProps.SetPropEntity(deadplayer, "m_hObserverTarget", healer) } } //TODO: prompt owner to cancel revive } ManualRespawnPlayer = function(player, reviver) { player.ForceRegenerateAndRespawn() player.Teleport(true, reviver.GetOrigin(),false,QAngle(0,0,0),false,Vector(0,0,0)) player.EmitSound("MVM.PlayerRevived") reviver.EmitSound("MVM.PlayerRevived") player.AddCondEx(51, 2, null) EntFire("!activator", "SpeakResponseConcept", "TLK_RESURRECTED", 0, player) ScreenFade(player, 50, 50, 50, 200, 0.5, 0.4, 1) local networkId = NetProps.GetPropString(player, "m_szNetworkIDString") numRevives[networkId] <- networkId in numRevives ? numRevives[networkId] + 1 : 1 } }; __CollectGameEventCallbacks(DynamicReanimators) ClientPrint(null,3,"script main run end" + DynamicReanimators.tostring())