//vscript by stardustspy //do not use without my credit PLEASE!!!!!!!!! ::TEAM_RED <- 2 ::TEAM_BLU <- 3 ::TF_NAV_SPAWN_ROOM_RED <- 2 ::TF_NAV_SPAWN_ROOM_BLUE <- 4 ::TF_BOT_FAKE_CLIENT <- 1337 ::MAX_COUNT_WEAPON_EQUPPED <- 8 ::TEAM_SPECTATOR <- 1 ::SOLID_NONE <- 0 ::CONTENTS_SOLID <- 1 ::CONTENTS_WINDOW <- 2 ::CONTENTS_GRATE <- 8 ::CONTENTS_MOVEABLE <- 16384 ::CONTENTS_PLAYERCLIP <- 65536 ::MASK_NPCWORLDSTATIC <- 131083 ::MASK_PLAYERSOLID <- 33636363 ::MASK_NPCSOLID <- 33701899 ::MASK_SOLID <- 33570827 ::MASK_SHOT <- 1174421507 ::MASK_SHOT_HULL <- 100679691 ::IN_ATTACK2 <- 2048 ::PI <- 3.14159265359 ::PRIMARY_FIRE <- Constants.FButtons.IN_ATTACK ::SECONDARY_FIRE <- Constants.FButtons.IN_ATTACK2 ::gamerules <- Entities.FindByClassname(null, "tf_gamerules") ::player_manager <- Entities.FindByClassname(null, "tf_player_manager") ::WORLD_SPAWN <- Entities.FindByClassname(null, "worldspawn") ::MAX_COUNT_PLAYERS <- MaxClients().tointeger() ::MASK_VISIBLE_AND_NPCS <- 33579137 ::DMG_CRITICAL <- 1048576 ::TF_DMG_CUSTOM_HEADSHOT <- 1 ::TF_DMG_CUSTOM_BACKSTAB <- 2 ::TF_DMG_CRITICAL <- 1048576 ::SND_NOFLAGS <- 0 ::SND_CHANGE_VOL <- 1 ::SND_CHANGE_PITCH <- 2 ::SND_STOP <- 4 ::SND_SPAWNING <- 8 ::SND_DELAY <- 16 ::SND_STOP_LOOPING <- 32 ::SND_SPEAKER <- 64 ::SND_SHOULDPAUSE <- 128 ::SND_IGNORE_PHONEMES <- 256 ::SND_IGNORE_NAME <- 512 ::SND_DO_NOT_OVERWRITE_EXISTING_ON_CHANNEL <- 1024 ::IGNORE_ENEMIES <- 1024 const STRING_NETPROP_ITEMDEF = "m_AttributeManager.m_Item.m_iItemDefinitionIndex" const SLOT_COUNT = 7 const EFL_USER = 1048576 // EFL_IS_BEING_LIFTED_BY_BARNACLE const EFL_USER2 = 1073741824 //EFL_NO_PHYSCANNON_INTERACTION const SINGLE_TICK = 0.015 const DMG_NO_BULLET_FALLOFF = 2097152 PrecacheSound("ambient/energy/weld1.wav") PrecacheSound("ambient/energy/weld2.wav") PrecacheSound("player/recharged.wav") PrecacheSound("npc/assassin/ball_zap1.wav") PrecacheSound("weapons/drg_wrench_teleport.wav") PrecacheSound("misc/halloween/spell_lightning_ball_cast.wav") PrecacheSound("misc/halloween/spell_meteor_impact.wav") PrecacheSound("misc/halloween/spell_spawn_boss.wav") //fold ::ROOT <- getroottable(); if (!("ConstantNamingConvention" in ROOT)) // make sure folding is only done once { foreach (a,b in Constants) foreach (k,v in b) ROOT[k] <- v != null ? v : 0; } function GetItemInSlot(player, slot) { local item for (local i = 0; i < SLOT_COUNT; i++) { local wep = NetProps.GetPropEntityArray(player, "m_hMyWeapons", i) if ( wep == null || wep.GetSlot() != slot) continue item = wep break } return item } ::MinigunTaunter <- { Cleanup = function() { // keep this at the end delete ::MinigunTaunter } // mandatory events OnGameEvent_recalculate_holidays = function(_) { if (GetRoundState() == 3) { Cleanup() } } OnGameEvent_mvm_wave_complete = function(_) { Cleanup() } function PrintTable(table) { if (table == null) return; this.DoPrintTable(table, 0) } function DoPrintTable(table, indent) { local line = "" for (local i = 0; i < indent; i++) { line += " " } line += typeof table == "array" ? "[" : "{"; ClientPrint(null, 2, line) indent += 2 foreach(k, v in table) { line = "" for (local i = 0; i < indent; i++) { line += " " } line += k.tostring() line += " = " if (typeof v == "table" || typeof v == "array") { ClientPrint(null, 2, line) this.DoPrintTable(v, indent) } else { try { line += v.tostring() } catch (e) { line += typeof v } ClientPrint(null, 2, line) } } indent -= 2 line = "" for (local i = 0; i < indent; i++) { line += " " } line += typeof table == "array" ? "]" : "}"; ClientPrint(null, 2, line) } function CalculateCritFactor(attacker, victim) { if (victim.GetClassname() != "player") { victim = null } function IsMiniCritAttacker(entity) { local CritArray = [16, 19, 31] foreach(crit in CritArray) { if (entity.InCond(crit)) { return true } } return false } function IsMiniCritVictim(entity) { if (victim == null) return false local CritArray = [24, 30] foreach(crit in CritArray) { if (entity.InCond(crit)) { return true } } return false } function IsCritAttacker(entity) { local CritArray = [11, 34, 37, 39, 40, 44, 56] foreach(crit in CritArray) { if (entity.InCond(crit)) { return true } } return false } // Initialize the damage factor to 1.0 local factor = 1.0; // Check if the attacker is a crit attacker local isCritAttacker = IsCritAttacker(attacker); // Check if the attacker is a mini-crit attacker local isMiniCritAttacker = IsMiniCritAttacker(attacker); // Check if the victim is a mini-crit victim local isMiniCritVictim = IsMiniCritVictim(victim); // Determine the factor based on crit and mini-crit conditions if (isCritAttacker && isMiniCritVictim) { // If the attacker is a crit attacker and the victim is a mini-crit victim, crit overrides factor = 3.0; } else if (isCritAttacker) { // If the attacker is a crit attacker, crit factor factor = 3.0; } else if (isMiniCritAttacker) { // If the attacker is a mini-crit attacker, mini-crit factor factor = 1.35; } return factor; } LookAt = function(bot, target_pos, min_rate, max_rate) { function VectorAngles(forward) { local yaw, pitch if ( forward.y == 0.0 && forward.x == 0.0 ) { yaw = 0.0 if (forward.z > 0.0) pitch = 270.0 else pitch = 90.0 } else { yaw = (atan2(forward.y, forward.x) * 180.0 / Pi) if (yaw < 0.0) yaw += 360.0 pitch = (atan2(-forward.z, forward.Length2D()) * 180.0 / Pi) if (pitch < 0.0) pitch += 360.0 } return QAngle(pitch, yaw, 0.0) } function NormalizeAngle(target) { target %= 360.0 if (target > 180.0) target -= 360.0 else if (target < -180.0) target += 360.0 return target } function ApproachAngle(target, value, speed) { target = this.NormalizeAngle(target) value = this.NormalizeAngle(value) local delta = this.NormalizeAngle(target - value) if (delta > speed) return value + speed else if (delta < -speed) return value - speed return target } function NormalizeAngle(target) { target %= 360.0 if (target > 180.0) target -= 360.0 else if (target < -180.0) target += 360.0 return target } function RemapValClamped(v, A, B, C, D) { if (A == B) { if (v >= B) return D return C } local cv = (v - A) / (B - A) if (cv <= 0.0) return C if (cv >= 1.0) return D return C + (D - C) * cv } local cur_eye_pos = bot.EyePosition() local cur_eye_fwd = bot.EyeAngles().Forward() local cur_eye_ang = bot.EyeAngles() local dt = FrameTime() local dir = target_pos - cur_eye_pos dir.Norm() local dot = cur_eye_fwd.Dot(dir) local desired_angles = VectorAngles(dir) local rate_x = RemapValClamped(fabs(NormalizeAngle(cur_eye_ang.x) - NormalizeAngle(desired_angles.x)), 0.0, 180.0, min_rate, max_rate) local rate_y = RemapValClamped(fabs(NormalizeAngle(cur_eye_ang.y) - NormalizeAngle(desired_angles.y)), 0.0, 180.0, min_rate, max_rate) if (dot > 0.7) { local t = RemapValClamped(dot, 0.7, 1.0, 1.0, 0.05) local d = sin(1.57 * t) // pi/2 rate_x *= d rate_y *= d } cur_eye_ang.x = NormalizeAngle(ApproachAngle(desired_angles.x, cur_eye_ang.x, rate_x * dt)) cur_eye_ang.y = NormalizeAngle(ApproachAngle(desired_angles.y, cur_eye_ang.y, rate_y * dt)) bot.SnapEyeAngles(cur_eye_ang) } GetItemInSlot = function(player, slot) { local item for (local i = 0; i < SLOT_COUNT; i++) { local wep = NetProps.GetPropEntityArray(player, "m_hMyWeapons", i) if ( wep == null || wep.GetSlot() != slot) continue item = wep break } return item } MinigunTauntSetup = function(ent) { local primary = GetItemInSlot(ent, 0) ent.ValidateScriptScope() local scope = ent.GetScriptScope() ::MinigunTauntThink <- function() { //self is the weapon here local buttons = NetProps.GetPropInt(self, "m_nButtons") local buttons_changed = buttons_last ^ buttons local buttons_pressed = buttons_changed & buttons local buttons_released = buttons_changed & (~buttons) local eyepos_start = self.EyePosition() + self.EyeAngles().Forward() local eyepos_end = self.EyePosition() + self.EyeAngles().Forward() * 99999 local origin = self.GetOrigin() local primary = GetItemInSlot(self, 0) local server_time_cur = Time() if (typeof(look_at_time) == "null") { look_at_time = 0; // Initialize last attack time } if (self.IsRageDraining() == true) { printl("rage drain") for (local player; player = FindByClassname(player, "player");) { if (self.GetTeam() != player.GetTeam() && player.GetTeam() != TEAM_SPECTATOR) { printl("currently distracting: "+player) if ((look_at_time + 2) <= server_time_cur) { look_at_time = server_time_cur; LookAt(player, origin, 950, 950) } if (!player.HasBotAttribute(IGNORE_ENEMIES)) { player.AddBotAttribute(IGNORE_ENEMIES) printl("fixed now ignores enemies") } else { printl("bot ignores enemies") } } } } buttons_last = buttons; return -1; } // Initial setup scope.buttons_last <- 0 scope.look_at_time <- 0 scope.Damagable_Entities_List <- { "player" : 1 "obj_teleporter" : 1 "obj_sentrygun" : 1 "obj_dispenser" : 1 "tank_boss" : 1 } // Initialize the global attack tables list scope.global_attack_tables <- [] scope.PrintTable <- PrintTable scope.DoPrintTable <- DoPrintTable scope.GetItemInSlot <- GetItemInSlot scope.LookAt <- LookAt scope.ent_index <- primary.entindex() AddThinkToEnt(ent, "MinigunTauntThink") } OnGameEvent_player_spawn = function(params) { local player = GetPlayerFromUserID(params.userid) player.ValidateScriptScope() local playerscope = player.GetScriptScope() local primary = GetItemInSlot(player, 0) local weapon_id = NetProps.GetPropInt(primary, STRING_NETPROP_ITEMDEF) //printl(primary) } OnGameEvent_post_inventory_application = function(params) { local player = GetPlayerFromUserID(params.userid) player.ValidateScriptScope() local playerscope = player.GetScriptScope() local primary = GetItemInSlot(player, 0) //printl(primary) } OnScriptHook_OnTakeDamage = function(params) { local victim = params.const_entity local weapon = params.weapon local attacker = params.attacker local entity = params.inflictor local damage = params.damage local dmgtype = params.damage_type local dmg_special = params.damage_stats local weapon_id = NetProps.GetPropInt(weapon, STRING_NETPROP_ITEMDEF) } }; __CollectGameEventCallbacks(MinigunTaunter)