diff --git a/2001/ze_resident_evil_3/boss_move_tar_akuma.js b/2001/ze_resident_evil_3/boss_move_tar_akuma.js new file mode 100644 index 0000000..164b060 --- /dev/null +++ b/2001/ze_resident_evil_3/boss_move_tar_akuma.js @@ -0,0 +1,293 @@ + +import { Instance } from "cs_script/point_script"; + + +const TICKRATE = 0.1; +const TARGET_DISTANCE = 3000; +let SPEED_FORWARD = 220; +const RETARGET_TIME = 8.00; + +const boss_model = "Nemesis_Model"; +const boss_move_physbox = "Nemesis_Phys"; +const boss_script_ent = "nemesis_akuma_script"; + +let p = null; +// let boss_id = ""; +// let boss_script_ent = null; +let bmphy = null; +let bmdl = null; +let ttime = 0.00; +let ticking = false; + +let speed_turning = 350; +let ang_rot_limit = 10; +let b_MaxDistToPl = 32; + +let lastTime = null; + +Instance.OnRoundStart(() => { + p = null; + ttime = 0.00; + bmdl = null; + bmphy = null; + ticking = false; + lastTime = null; + SPEED_FORWARD = 220; +}); + +Instance.OnScriptInput("SetSpeedX2", ({ caller, activator }) => { + SPEED_FORWARD *= 2; +}); + +Instance.OnScriptInput("SetSpeedX1.5", ({ caller, activator }) => { + SPEED_FORWARD *= 1.5; +}); + +Instance.OnScriptInput("AttackSpeed", ({ caller, activator }) => { + SPEED_FORWARD -= 100; + +}); + +Instance.OnScriptInput("SetSpeedX1.7", ({ caller, activator }) => { + SPEED_FORWARD *= 1.7; +}); + +Instance.OnScriptInput("ResetSpeed", ({ caller, activator }) => { + SPEED_FORWARD = 220; +}); + +Instance.OnScriptInput("SetSpeedX240", ({ caller, activator }) => { + SPEED_FORWARD += 20; +}); + +function SetEntities() +{ + if(ticking) + { + return; + } + if(!bmdl?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_model); + if(boss_phys?.IsValid()) + { + bmdl = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_model); + } + } + if(!bmphy?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_move_physbox); + if(boss_phys?.IsValid()) + { + bmphy = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_move_physbox); + } + } +} + +Instance.OnScriptInput("Start", () => { + if(!ticking) + { + // AutoDetectEntities(); + SetEntities(); + ticking = true; + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } +}); + +Instance.OnScriptInput("Stop", () => { + if(ticking) + { + ticking = false; + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } +}); + +Instance.OnScriptInput("Tick", () => { + if (!bmdl?.IsValid() || !bmphy?.IsValid()) + { + return; + } + let currentTime = Instance.GetGameTime(); + if(lastTime === null) + { + lastTime = currentTime; + } + + let deltaTime = currentTime - lastTime; + lastTime = currentTime; + + if(ticking) + { + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + return; + } + + if(p == null || !p?.IsValid() || p?.GetHealth() <= 0.00 || p?.GetTeamNumber() != 3 || ttime >= RETARGET_TIME) + { + p = null; + return SearchTarget(); + } + ttime += deltaTime; + let gto = p.GetAbsOrigin(); + let npc_m_gto = bmdl.GetAbsOrigin(); + let tm_ang = GetYawFVect2D(gto, npc_m_gto); + let setg_rangd = SetGraduallyAng(tm_ang, bmdl); + if(setg_rangd > 0 && setg_rangd <= ang_rot_limit || setg_rangd < 0 && setg_rangd >= -ang_rot_limit) + { + let dist_pb = GetDistance(npc_m_gto, gto); + if(dist_pb > b_MaxDistToPl) + { + let direction = VectorSubtract(gto, npc_m_gto); + let normalizedDirection = NormalizeVector(direction); + let pushVelocity = MultiplyVectorByScalar(normalizedDirection, SPEED_FORWARD); + bmphy.Teleport({velocity: {x: pushVelocity.x, y: pushVelocity.y, z: bmphy.GetAbsVelocity().z}}); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + +}); + +function SearchTarget() +{ + ttime = 0.00; + if(bmdl?.IsValid()) + { + let candidates = []; + let players = Instance.FindEntitiesByClass("player"); + for(let i = 0; i < players.length; i++) + { + if(players[i]?.IsValid() && players[i].GetTeamNumber() == 3 && players[i].GetHealth() > 0 && GetDistance(players[i].GetAbsOrigin(), bmdl.GetAbsOrigin()) <= TARGET_DISTANCE) + { + candidates.push(players[i]); + } + } + if(candidates.length > 0) + { + let rnd_player = candidates[GetRandomInt(0, candidates.length - 1)] + p = rnd_player; + //Instance.Msg(`TARGET: ${p?.GetPlayerController()?.GetPlayerName()}`); + return; + } + else + { + //Instance.Msg("No alive players found"); + return null; + } + } + //Instance.Msg("Physbox not valid"); + return null; +} + +function SetGraduallyAng(ang_t, ent) +{ + let ang_y = ent.GetAbsAngles().yaw + let ang_dif = AngleDiff( ang_t, ang_y ); + if(speed_turning > 1000) + { + speed_turning = 1000; + } + else if(speed_turning < 100) + { + speed_turning = 100; + } + let add_gs = speed_turning * TICKRATE; + while (ang_y < -180) + { + ang_y = ang_y + 360; + } + while (ang_y > 180) + { + ang_y = ang_y - 360; + } + if(ang_dif > add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y + add_gs), roll: ent.GetAbsAngles().roll} }); + } + else if(ang_dif < -add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y - add_gs), roll: ent.GetAbsAngles().roll} }); + } + return ang_dif +} + +function GetYawFVect2D(a, b) { + const deltaX = a.x - b.x; + const deltaY = a.y - b.y; + const yaw = (Math.atan2(deltaY, deltaX) * 180) / Math.PI; + return yaw; +} + +function AngleDiff(angle1, angle2) +{ + let diff = angle1 - angle2; + + while (diff > 180) diff -= 360; + while (diff < -180) diff += 360; + + return diff; +} +function GetDistance(v1, v2) { + return Math.sqrt( + (v1.x - v2.x) * (v1.x - v2.x) + + (v1.y - v2.y) * (v1.y - v2.y) + + (v1.z - v2.z) * (v1.z - v2.z) + ); +} + +function VectorSubtract(v1, v2) +{ + return { + x: v1.x - v2.x, + y: v1.y - v2.y, + z: v1.z - v2.z + }; +} + +function VectorLength(v) +{ + return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +function NormalizeVector(v) +{ + let length = VectorLength(v); + if (length === 0) return { x: 0, y: 0, z: 0 }; + return { + x: v.x / length, + y: v.y / length, + z: v.z / length + }; +} + +function MultiplyVectorByScalar(v, scalar) +{ + return { + x: v.x * scalar, + y: v.y * scalar, + z: v.z * scalar + }; +} + +function GetRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/2001/ze_resident_evil_3/boss_move_tar_hard.js b/2001/ze_resident_evil_3/boss_move_tar_hard.js new file mode 100644 index 0000000..3534c3a --- /dev/null +++ b/2001/ze_resident_evil_3/boss_move_tar_hard.js @@ -0,0 +1,289 @@ + +import { Instance } from "cs_script/point_script"; + + +const TICKRATE = 0.1; +const TARGET_DISTANCE = 3000; +let SPEED_FORWARD = 200; +const RETARGET_TIME = 8.00; + +const boss_model = "Nemesis_Model"; +const boss_move_physbox = "Nemesis_Phys"; +const boss_script_ent = "nemesis_hard_script"; + +let p = null; +// let boss_id = ""; +// let boss_script_ent = null; +let bmphy = null; +let bmdl = null; +let ttime = 0.00; +let ticking = false; + +let speed_turning = 350; +let ang_rot_limit = 10; +let b_MaxDistToPl = 32; + +let lastTime = null; + +Instance.OnRoundStart(() => { + p = null; + ttime = 0.00; + bmdl = null; + bmphy = null; + ticking = false; + lastTime = null; + SPEED_FORWARD = 200; +}); + +Instance.OnScriptInput("SetSpeedX2", ({ caller, activator }) => { + SPEED_FORWARD *= 2; +}); + +Instance.OnScriptInput("AttackSpeed", ({ caller, activator }) => { + SPEED_FORWARD -= 100; + //Instance.Msg("SOSAL?"); +}); + +Instance.OnScriptInput("SetSpeedX220", ({ caller, activator }) => { + SPEED_FORWARD += 10; +}); + +Instance.OnScriptInput("SetSpeedX1.5", ({ caller, activator }) => { + SPEED_FORWARD *= 1.5; +}); + +Instance.OnScriptInput("ResetSpeed", ({ caller, activator }) => { + SPEED_FORWARD = 200; +}); + +function SetEntities() +{ + if(ticking) + { + return; + } + if(!bmdl?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_model); + if(boss_phys?.IsValid()) + { + bmdl = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_model); + } + } + if(!bmphy?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_move_physbox); + if(boss_phys?.IsValid()) + { + bmphy = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_move_physbox); + } + } +} + +Instance.OnScriptInput("Start", () => { + if(!ticking) + { + // AutoDetectEntities(); + SetEntities(); + ticking = true; + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } +}); + +Instance.OnScriptInput("Stop", () => { + if(ticking) + { + ticking = false; + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } +}); + +Instance.OnScriptInput("Tick", () => { + if (!bmdl?.IsValid() || !bmphy?.IsValid()) + { + return; + } + let currentTime = Instance.GetGameTime(); + if(lastTime === null) + { + lastTime = currentTime; + } + + let deltaTime = currentTime - lastTime; + lastTime = currentTime; + + if(ticking) + { + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + return; + } + + if(p == null || !p?.IsValid() || p?.GetHealth() <= 0.00 || p?.GetTeamNumber() != 3 || ttime >= RETARGET_TIME) + { + p = null; + return SearchTarget(); + } + ttime += deltaTime; + let gto = p.GetAbsOrigin(); + let npc_m_gto = bmdl.GetAbsOrigin(); + let tm_ang = GetYawFVect2D(gto, npc_m_gto); + let setg_rangd = SetGraduallyAng(tm_ang, bmdl); + if(setg_rangd > 0 && setg_rangd <= ang_rot_limit || setg_rangd < 0 && setg_rangd >= -ang_rot_limit) + { + let dist_pb = GetDistance(npc_m_gto, gto); + if(dist_pb > b_MaxDistToPl) + { + let direction = VectorSubtract(gto, npc_m_gto); + let normalizedDirection = NormalizeVector(direction); + let pushVelocity = MultiplyVectorByScalar(normalizedDirection, SPEED_FORWARD); + bmphy.Teleport({velocity: {x: pushVelocity.x, y: pushVelocity.y, z: bmphy.GetAbsVelocity().z}}); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + +}); + +function SearchTarget() +{ + ttime = 0.00; + if(bmdl?.IsValid()) + { + let candidates = []; + let players = Instance.FindEntitiesByClass("player"); + for(let i = 0; i < players.length; i++) + { + if(players[i]?.IsValid() && players[i].GetTeamNumber() == 3 && players[i].GetHealth() > 0 && GetDistance(players[i].GetAbsOrigin(), bmdl.GetAbsOrigin()) <= TARGET_DISTANCE) + { + candidates.push(players[i]); + } + } + if(candidates.length > 0) + { + let rnd_player = candidates[GetRandomInt(0, candidates.length - 1)] + p = rnd_player; + //Instance.Msg(`TARGET: ${p?.GetPlayerController()?.GetPlayerName()}`); + return; + } + else + { + //Instance.Msg("No alive players found"); + return null; + } + } + //Instance.Msg("Physbox not valid"); + return null; +} + +function SetGraduallyAng(ang_t, ent) +{ + let ang_y = ent.GetAbsAngles().yaw + let ang_dif = AngleDiff( ang_t, ang_y ); + if(speed_turning > 1000) + { + speed_turning = 1000; + } + else if(speed_turning < 100) + { + speed_turning = 100; + } + let add_gs = speed_turning * TICKRATE; + while (ang_y < -180) + { + ang_y = ang_y + 360; + } + while (ang_y > 180) + { + ang_y = ang_y - 360; + } + if(ang_dif > add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y + add_gs), roll: ent.GetAbsAngles().roll} }); + } + else if(ang_dif < -add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y - add_gs), roll: ent.GetAbsAngles().roll} }); + } + return ang_dif +} + +function GetYawFVect2D(a, b) { + const deltaX = a.x - b.x; + const deltaY = a.y - b.y; + const yaw = (Math.atan2(deltaY, deltaX) * 180) / Math.PI; + return yaw; +} + +function AngleDiff(angle1, angle2) +{ + let diff = angle1 - angle2; + + while (diff > 180) diff -= 360; + while (diff < -180) diff += 360; + + return diff; +} +function GetDistance(v1, v2) { + return Math.sqrt( + (v1.x - v2.x) * (v1.x - v2.x) + + (v1.y - v2.y) * (v1.y - v2.y) + + (v1.z - v2.z) * (v1.z - v2.z) + ); +} + +function VectorSubtract(v1, v2) +{ + return { + x: v1.x - v2.x, + y: v1.y - v2.y, + z: v1.z - v2.z + }; +} + +function VectorLength(v) +{ + return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +function NormalizeVector(v) +{ + let length = VectorLength(v); + if (length === 0) return { x: 0, y: 0, z: 0 }; + return { + x: v.x / length, + y: v.y / length, + z: v.z / length + }; +} + +function MultiplyVectorByScalar(v, scalar) +{ + return { + x: v.x * scalar, + y: v.y * scalar, + z: v.z * scalar + }; +} + +function GetRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/2001/ze_resident_evil_3/boss_move_tar_normal.js b/2001/ze_resident_evil_3/boss_move_tar_normal.js new file mode 100644 index 0000000..71e2485 --- /dev/null +++ b/2001/ze_resident_evil_3/boss_move_tar_normal.js @@ -0,0 +1,280 @@ + +import { Instance } from "cs_script/point_script"; + + +const TICKRATE = 0.1; +const TARGET_DISTANCE = 3000; +let SPEED_FORWARD = 200; +const RETARGET_TIME = 5.00; + +const boss_model = "Nemesis_Model"; +const boss_move_physbox = "Nemesis_Phys"; +const boss_script_ent = "nemesis_normal_script"; + +let p = null; +// let boss_id = ""; +// let boss_script_ent = null; +let bmphy = null; +let bmdl = null; +let ttime = 0.00; +let ticking = false; + +let speed_turning = 350; +let ang_rot_limit = 10; +let b_MaxDistToPl = 32; + +let lastTime = null; + +Instance.OnRoundStart(() => { + p = null; + ttime = 0.00; + bmdl = null; + bmphy = null; + ticking = false; + lastTime = null; + SPEED_FORWARD = 200; +}); + +Instance.OnScriptInput("SetSpeedX2", ({ caller, activator }) => { + SPEED_FORWARD *= 2; +}); + +Instance.OnScriptInput("SetSpeedX1.5", ({ caller, activator }) => { + SPEED_FORWARD *= 1.5; +}); + +Instance.OnScriptInput("ResetSpeed", ({ caller, activator }) => { + SPEED_FORWARD = 200; +}); + +function SetEntities() +{ + if(ticking) + { + return; + } + if(!bmdl?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_model); + if(boss_phys?.IsValid()) + { + bmdl = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_model); + } + } + if(!bmphy?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_move_physbox); + if(boss_phys?.IsValid()) + { + bmphy = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_move_physbox); + } + } +} + +Instance.OnScriptInput("Start", () => { + if(!ticking) + { + // AutoDetectEntities(); + SetEntities(); + ticking = true; + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } +}); + +Instance.OnScriptInput("Stop", () => { + if(ticking) + { + ticking = false; + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } +}); + +Instance.OnScriptInput("Tick", () => { + if (!bmdl?.IsValid() || !bmphy?.IsValid()) + { + return; + } + let currentTime = Instance.GetGameTime(); + if(lastTime === null) + { + lastTime = currentTime; + } + + let deltaTime = currentTime - lastTime; + lastTime = currentTime; + + if(ticking) + { + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + return; + } + + if(p == null || !p?.IsValid() || p?.GetHealth() <= 0.00 || p?.GetTeamNumber() != 3 || ttime >= RETARGET_TIME) + { + p = null; + return SearchTarget(); + } + ttime += deltaTime; + let gto = p.GetAbsOrigin(); + let npc_m_gto = bmdl.GetAbsOrigin(); + let tm_ang = GetYawFVect2D(gto, npc_m_gto); + let setg_rangd = SetGraduallyAng(tm_ang, bmdl); + if(setg_rangd > 0 && setg_rangd <= ang_rot_limit || setg_rangd < 0 && setg_rangd >= -ang_rot_limit) + { + let dist_pb = GetDistance(npc_m_gto, gto); + if(dist_pb > b_MaxDistToPl) + { + let direction = VectorSubtract(gto, npc_m_gto); + let normalizedDirection = NormalizeVector(direction); + let pushVelocity = MultiplyVectorByScalar(normalizedDirection, SPEED_FORWARD); + bmphy.Teleport({velocity: {x: pushVelocity.x, y: pushVelocity.y, z: bmphy.GetAbsVelocity().z}}); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + +}); + +function SearchTarget() +{ + ttime = 0.00; + if(bmdl?.IsValid()) + { + let candidates = []; + let players = Instance.FindEntitiesByClass("player"); + for(let i = 0; i < players.length; i++) + { + if(players[i]?.IsValid() && players[i].GetTeamNumber() == 3 && players[i].GetHealth() > 0 && GetDistance(players[i].GetAbsOrigin(), bmdl.GetAbsOrigin()) <= TARGET_DISTANCE) + { + candidates.push(players[i]); + } + } + if(candidates.length > 0) + { + let rnd_player = candidates[GetRandomInt(0, candidates.length - 1)] + p = rnd_player; + //Instance.Msg(`TARGET: ${p?.GetPlayerController()?.GetPlayerName()}`); + return; + } + else + { + //Instance.Msg("No alive players found"); + return null; + } + } + //Instance.Msg("Physbox not valid"); + return null; +} + +function SetGraduallyAng(ang_t, ent) +{ + let ang_y = ent.GetAbsAngles().yaw + let ang_dif = AngleDiff( ang_t, ang_y ); + if(speed_turning > 1000) + { + speed_turning = 1000; + } + else if(speed_turning < 100) + { + speed_turning = 100; + } + let add_gs = speed_turning * TICKRATE; + while (ang_y < -180) + { + ang_y = ang_y + 360; + } + while (ang_y > 180) + { + ang_y = ang_y - 360; + } + if(ang_dif > add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y + add_gs), roll: ent.GetAbsAngles().roll} }); + } + else if(ang_dif < -add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y - add_gs), roll: ent.GetAbsAngles().roll} }); + } + return ang_dif +} + +function GetYawFVect2D(a, b) { + const deltaX = a.x - b.x; + const deltaY = a.y - b.y; + const yaw = (Math.atan2(deltaY, deltaX) * 180) / Math.PI; + return yaw; +} + +function AngleDiff(angle1, angle2) +{ + let diff = angle1 - angle2; + + while (diff > 180) diff -= 360; + while (diff < -180) diff += 360; + + return diff; +} +function GetDistance(v1, v2) { + return Math.sqrt( + (v1.x - v2.x) * (v1.x - v2.x) + + (v1.y - v2.y) * (v1.y - v2.y) + + (v1.z - v2.z) * (v1.z - v2.z) + ); +} + +function VectorSubtract(v1, v2) +{ + return { + x: v1.x - v2.x, + y: v1.y - v2.y, + z: v1.z - v2.z + }; +} + +function VectorLength(v) +{ + return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +function NormalizeVector(v) +{ + let length = VectorLength(v); + if (length === 0) return { x: 0, y: 0, z: 0 }; + return { + x: v.x / length, + y: v.y / length, + z: v.z / length + }; +} + +function MultiplyVectorByScalar(v, scalar) +{ + return { + x: v.x * scalar, + y: v.y * scalar, + z: v.z * scalar + }; +} + +function GetRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/2001/ze_resident_evil_3/boss_move_tar_stars.js b/2001/ze_resident_evil_3/boss_move_tar_stars.js new file mode 100644 index 0000000..3cf9ca9 --- /dev/null +++ b/2001/ze_resident_evil_3/boss_move_tar_stars.js @@ -0,0 +1,292 @@ + +import { Instance } from "cs_script/point_script"; + + +const TICKRATE = 0.1; +const TARGET_DISTANCE = 3000; +let SPEED_FORWARD = 220; +const RETARGET_TIME = 8.00; + +const boss_model = "Nemesis_Model"; +const boss_move_physbox = "Nemesis_Phys"; +const boss_script_ent = "nemesis_stars_script"; + +let p = null; +// let boss_id = ""; +// let boss_script_ent = null; +let bmphy = null; +let bmdl = null; +let ttime = 0.00; +let ticking = false; + +let speed_turning = 350; +let ang_rot_limit = 10; +let b_MaxDistToPl = 32; + +let lastTime = null; + +Instance.OnRoundStart(() => { + p = null; + ttime = 0.00; + bmdl = null; + bmphy = null; + ticking = false; + lastTime = null; + SPEED_FORWARD = 220; +}); + +Instance.OnScriptInput("SetSpeedX2", ({ caller, activator }) => { + SPEED_FORWARD *= 2; +}); + +Instance.OnScriptInput("AttackSpeed", ({ caller, activator }) => { + SPEED_FORWARD -= 100; +}); + +Instance.OnScriptInput("SetSpeedX240", ({ caller, activator }) => { + SPEED_FORWARD += 20; +}); + +Instance.OnScriptInput("SetSpeedX1.7", ({ caller, activator }) => { + SPEED_FORWARD *= 1.7; +}); + +Instance.OnScriptInput("ResetSpeed", ({ caller, activator }) => { + SPEED_FORWARD = 220; +}); + +Instance.OnScriptInput("SetSpeedX0.5", ({ caller, activator }) => { + SPEED_FORWARD = 110; +}); + +function SetEntities() +{ + if(ticking) + { + return; + } + if(!bmdl?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_model); + if(boss_phys?.IsValid()) + { + bmdl = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_model); + } + } + if(!bmphy?.IsValid() ) + { + let boss_phys = Instance.FindEntityByName(boss_move_physbox); + if(boss_phys?.IsValid()) + { + bmphy = boss_phys; + } + else + { + //Instance.Msg("Can't Find: "+boss_move_physbox); + } + } +} + +Instance.OnScriptInput("Start", () => { + if(!ticking) + { + // AutoDetectEntities(); + SetEntities(); + ticking = true; + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } +}); + +Instance.OnScriptInput("Stop", () => { + if(ticking) + { + ticking = false; + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } +}); + +Instance.OnScriptInput("Tick", () => { + if (!bmdl?.IsValid() || !bmphy?.IsValid()) + { + return; + } + let currentTime = Instance.GetGameTime(); + if(lastTime === null) + { + lastTime = currentTime; + } + + let deltaTime = currentTime - lastTime; + lastTime = currentTime; + + if(ticking) + { + Instance.EntFireAtName({ name: boss_script_ent, input: "runscriptinput", value: "Tick", delay: TICKRATE }); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + return; + } + + if(p == null || !p?.IsValid() || p?.GetHealth() <= 0.00 || p?.GetTeamNumber() != 3 || ttime >= RETARGET_TIME) + { + p = null; + return SearchTarget(); + } + ttime += deltaTime; + let gto = p.GetAbsOrigin(); + let npc_m_gto = bmdl.GetAbsOrigin(); + let tm_ang = GetYawFVect2D(gto, npc_m_gto); + let setg_rangd = SetGraduallyAng(tm_ang, bmdl); + if(setg_rangd > 0 && setg_rangd <= ang_rot_limit || setg_rangd < 0 && setg_rangd >= -ang_rot_limit) + { + let dist_pb = GetDistance(npc_m_gto, gto); + if(dist_pb > b_MaxDistToPl) + { + let direction = VectorSubtract(gto, npc_m_gto); + let normalizedDirection = NormalizeVector(direction); + let pushVelocity = MultiplyVectorByScalar(normalizedDirection, SPEED_FORWARD); + bmphy.Teleport({velocity: {x: pushVelocity.x, y: pushVelocity.y, z: bmphy.GetAbsVelocity().z}}); + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + } + else + { + bmphy.Teleport({velocity: {x: 0, y: 0, z: 0}}); + } + +}); + +function SearchTarget() +{ + ttime = 0.00; + if(bmdl?.IsValid()) + { + let candidates = []; + let players = Instance.FindEntitiesByClass("player"); + for(let i = 0; i < players.length; i++) + { + if(players[i]?.IsValid() && players[i].GetTeamNumber() == 3 && players[i].GetHealth() > 0 && GetDistance(players[i].GetAbsOrigin(), bmdl.GetAbsOrigin()) <= TARGET_DISTANCE) + { + candidates.push(players[i]); + } + } + if(candidates.length > 0) + { + let rnd_player = candidates[GetRandomInt(0, candidates.length - 1)] + p = rnd_player; + //Instance.Msg(`TARGET: ${p?.GetPlayerController()?.GetPlayerName()}`); + return; + } + else + { + //Instance.Msg("No alive players found"); + return null; + } + } + //Instance.Msg("Physbox not valid"); + return null; +} + +function SetGraduallyAng(ang_t, ent) +{ + let ang_y = ent.GetAbsAngles().yaw + let ang_dif = AngleDiff( ang_t, ang_y ); + if(speed_turning > 1000) + { + speed_turning = 1000; + } + else if(speed_turning < 100) + { + speed_turning = 100; + } + let add_gs = speed_turning * TICKRATE; + while (ang_y < -180) + { + ang_y = ang_y + 360; + } + while (ang_y > 180) + { + ang_y = ang_y - 360; + } + if(ang_dif > add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y + add_gs), roll: ent.GetAbsAngles().roll} }); + } + else if(ang_dif < -add_gs) + { + ent.Teleport({ angles: {pitch: ent.GetAbsAngles().pitch, yaw: Math.round(ang_y - add_gs), roll: ent.GetAbsAngles().roll} }); + } + return ang_dif +} + +function GetYawFVect2D(a, b) { + const deltaX = a.x - b.x; + const deltaY = a.y - b.y; + const yaw = (Math.atan2(deltaY, deltaX) * 180) / Math.PI; + return yaw; +} + +function AngleDiff(angle1, angle2) +{ + let diff = angle1 - angle2; + + while (diff > 180) diff -= 360; + while (diff < -180) diff += 360; + + return diff; +} +function GetDistance(v1, v2) { + return Math.sqrt( + (v1.x - v2.x) * (v1.x - v2.x) + + (v1.y - v2.y) * (v1.y - v2.y) + + (v1.z - v2.z) * (v1.z - v2.z) + ); +} + +function VectorSubtract(v1, v2) +{ + return { + x: v1.x - v2.x, + y: v1.y - v2.y, + z: v1.z - v2.z + }; +} + +function VectorLength(v) +{ + return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z); +} + + +function NormalizeVector(v) +{ + let length = VectorLength(v); + if (length === 0) return { x: 0, y: 0, z: 0 }; + return { + x: v.x / length, + y: v.y / length, + z: v.z / length + }; +} + +function MultiplyVectorByScalar(v, scalar) +{ + return { + x: v.x * scalar, + y: v.y * scalar, + z: v.z * scalar + }; +} + +function GetRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} diff --git a/2001/ze_resident_evil_3/game_score.js b/2001/ze_resident_evil_3/game_score.js new file mode 100644 index 0000000..58b31c4 --- /dev/null +++ b/2001/ze_resident_evil_3/game_score.js @@ -0,0 +1,41 @@ +import { Instance, CSPlayerPawn } from "cs_script/point_script"; + +Instance.OnScriptInput("CT_Add100", (x) => { + const pawn = x.activator; + if (pawn.GetTeamNumber() === 3) { + const controller = pawn.GetPlayerController(); + controller?.AddScore(100); + } +}); + +Instance.OnScriptInput("CT_Add200", (x) => { + const pawn = x.activator; + if (pawn.GetTeamNumber() === 3) { + const controller = pawn.GetPlayerController(); + controller?.AddScore(200); + } +}); + +Instance.OnScriptInput("CT_Add300", (x) => { + const pawn = x.activator; + if (pawn.GetTeamNumber() === 3) { + const controller = pawn.GetPlayerController(); + controller?.AddScore(300); + } +}); + +Instance.OnScriptInput("CT_Add400", (x) => { + const pawn = x.activator; + if (pawn.GetTeamNumber() === 3) { + const controller = pawn.GetPlayerController(); + controller?.AddScore(400); + } +}); + +Instance.OnScriptInput("T_Remove1", (x) => { + const pawn = x.activator; + if (pawn.GetTeamNumber() === 2) { + const controller = pawn.GetPlayerController(); + controller?.AddScore(-1); + } +}); diff --git a/2001/ze_resident_evil_3/item_drop.js b/2001/ze_resident_evil_3/item_drop.js new file mode 100644 index 0000000..3d621df --- /dev/null +++ b/2001/ze_resident_evil_3/item_drop.js @@ -0,0 +1,117 @@ +import { Instance } from 'cs_script/point_script'; + +let idPool = 0; +let tasks = []; + +function setTimeout(callback, ms) { + const id = idPool++; + tasks.unshift({ + id, + atSeconds: Instance.GetGameTime() + ms / 1000, + callback, + }); + return id; +} +function setInterval(callback, ms) { + const id = idPool++; + tasks.unshift({ + id, + everyNSeconds: ms / 1000, + atSeconds: Instance.GetGameTime() + ms / 1000, + callback, + }); + return id; +} +//sad +function clearTimeout(id) { + tasks = tasks.filter((task) => task.id !== id); +} +const clearInterval = clearTimeout; +function clearTasks() { + tasks = []; +} + +function runSchedulerTick() { + for (let i = tasks.length - 1; i >= 0; i--) { + const task = tasks[i]; + if (Instance.GetGameTime() < task.atSeconds) + continue; + if (task.everyNSeconds === undefined) + tasks.splice(i, 1); + else + task.atSeconds = Instance.GetGameTime() + task.everyNSeconds; + try { + task.callback(); + } + catch (err) { + //Instance.Msg('An error occurred inside a scheduler task'); + if (err instanceof Error) { + //Instance.Msg(err.message); + //Instance.Msg(err.stack ?? ''); + } + } + } +} + + +let CLEAR_ALL_INTERVAL = false; + + +let Kar_Owner = null; +let Kar_Weapon = null; + +Instance.OnScriptInput("PickUp_Kar", (Activator_Caller_Data) => { + Kar_Weapon = Activator_Caller_Data.caller + + if (IsValidAlive(Kar_Owner)) + { + Kar_Owner.SetEntityName("player") + } + + Kar_Owner = Activator_Caller_Data.activator; + Kar_Owner.SetEntityName("Kar_Owner") + + Instance.EntFireAtName({name: "kar_mm", input: "SetMeasureTarget", value: "Kar_Owner", delay: 0.02}); + + const hTimer = setInterval(() => + { + const hOwner = Kar_Weapon.GetOwner(); + const bDrop = (hOwner != Kar_Owner || hOwner == undefined) + if (CLEAR_ALL_INTERVAL || bDrop) + { + clearInterval(hTimer); + Instance.EntFireAtName({name: "kar_mm", input: "SetMeasureTarget", value: "kar_weapon_parent", delay: 0}); + if (IsValidAlive(Kar_Owner)) + { + Kar_Owner.SetEntityName("player") + } + + return; + } + }, 0.1 * 1000); +}) + +function IsValidAlive(player) +{ + return (player != null && player.IsValid() && player.IsAlive()) +} + +Instance.OnRoundStart(() => {OnRoundStart()}); +function OnRoundStart() +{ + clearTasks(); + CLEAR_ALL_INTERVAL = false; +} +Instance.OnScriptReload({ after: (undefined$1) => { + CLEAR_ALL_INTERVAL = false; +}}); + +Instance.OnRoundEnd((stuff) => { + CLEAR_ALL_INTERVAL = true; +}); +Instance.SetThink(() => { + // Drive scheduled tasks at the minimum accepted interval. + Instance.SetNextThink(Instance.GetGameTime() + 0.1); + runSchedulerTick(); +}); +Instance.SetNextThink(Instance.GetGameTime() + 0.1); diff --git a/2001/ze_resident_evil_3/licker.js b/2001/ze_resident_evil_3/licker.js new file mode 100644 index 0000000..50a08ac --- /dev/null +++ b/2001/ze_resident_evil_3/licker.js @@ -0,0 +1,848 @@ +import { Instance, CSPlayerPawn, CSGearSlot, CSInputs } from 'cs_script/point_script'; + +// SCRIPT BY TILGEP (hi) +// STUFF THAT MIGHT NEED CHANGING FOR BALANCE +let BLOCK_INFECTION = true; // Whether to block infection, licker can only use its abilities to kill +// Lick Ability +const LICK_COOLDOWN = 25; // Cooldown of lick ability (+use) +const TONGUE_LENGTH = 1500; // Max range of lick +const TONGUE_SPEED = 2500; // Speed of tongue going out +const TONGUE_SPEED_RETRACT = 4000; // Tongue missed, speed as it goes back +const TONGUE_SPEED_PULL = 75; // Tongue HIT, speed as it pulls a CT +const TONGUE_RADIUS = 8; // Radius of the tongue +const TONGUE_PHYSBOX_HP_BASE = 1000; // Base HP of grabbed CT physbox +const TONGUE_PHYSBOX_HP_PER_CT = 25; // HP added per alive CT to grabbed physbox +// Jump Ability +const JUMP_COOLDOWN = 8; // Cooldown of jump ability (right click) +const JUMP_FORCE = { + forward: 800, // Force applied forward + right: 0, // Force applied right + up: 500 // Force applied up +}; +// Swipe Attack +const SWIPE_COOLDOWN = 10; // Cooldown of swipe attack (left click) +// Knockback options +const KB_SCALE = 3; // Global knockback scale +const ABILTY_KB_MODIFIER = { + lick: 0, // Knockback scale during ability + jump: 0.1, + swipe: 0.2 +}; +///////////////////////////////////// +///////////////////////////////////// +///////////////////////////////////// +// UTIL FUNCS +const RAD_TO_DEG = 180 / Math.PI; +const CS_TEAM_T = 2; +const CS_TEAM_CT = 3; +// VECTOR UTILS +function vec(_x, _y, _z) { return { x: _x, y: _y, z: _z }; } +const VEC0 = { x: 0, y: 0, z: 0 }; +function vecScale(vec1, scale) { return vec(vec1.x * scale, vec1.y * scale, vec1.z * scale); } +function vecAdd(a, b) { return vec(a.x + b.x, a.y + b.y, a.z + b.z); } +function vecSubtract(a, b) { return vec(a.x - b.x, a.y - b.y, a.z - b.z); } +function vecLengthSquared(vector) { return (vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); } +function vecLength(vector) { return Math.sqrt(vecLengthSquared(vector)); } +function vecLength2D(vector) { return Math.sqrt(vecLength2DSquared(vector)); } +function vecLength2DSquared(vector) { return (vector.x * vector.x + vector.y * vector.y); } +function vecDot(a, b) { return a.x * b.x + a.y * b.y + a.z * b.z; } +function vecAngles(vector) { + let yaw = 0; + let pitch = 0; + if (!vector.y && !vector.x) { + if (vector.z > 0) + pitch = -90; + else + pitch = 90; + } + else { + yaw = Math.atan2(vector.y, vector.x) * RAD_TO_DEG; + pitch = Math.atan2(-vector.z, vecLength2D(vector)) * RAD_TO_DEG; + } + return ang(pitch, yaw, 0); +} +// END VECTOR +// ANGLE UTILS +function ang(_p, _y, _r) { return { pitch: _p, yaw: _y, roll: _r }; } +function getForward(angles) { + const pitchRadians = (angles.pitch * Math.PI) / 180; + const yawRadians = (angles.yaw * Math.PI) / 180; + const hScale = Math.cos(pitchRadians); + return vec(Math.cos(yawRadians) * hScale, Math.sin(yawRadians) * hScale, -Math.sin(pitchRadians)); +} +function getRight(angle) { + const pitchInRad = (angle.pitch / 180) * Math.PI; + const yawInRad = (angle.yaw / 180) * Math.PI; + const rollInRad = (angle.roll / 180) * Math.PI; + const sinPitch = Math.sin(pitchInRad); + const sinYaw = Math.sin(yawInRad); + const sinRoll = Math.sin(rollInRad); + const cosPitch = Math.cos(pitchInRad); + const cosYaw = Math.cos(yawInRad); + const cosRoll = Math.cos(rollInRad); + return vec(-1 * sinRoll * sinPitch * cosYaw + -1 * cosRoll * -sinYaw, -1 * sinRoll * sinPitch * sinYaw + -1 * cosRoll * cosYaw, -1 * sinRoll * cosPitch); +} +function getUp(angle) { + const pitchInRad = (angle.pitch / 180) * Math.PI; + const yawInRad = (angle.yaw / 180) * Math.PI; + const rollInRad = (angle.roll / 180) * Math.PI; + const sinPitch = Math.sin(pitchInRad); + const sinYaw = Math.sin(yawInRad); + const sinRoll = Math.sin(rollInRad); + const cosPitch = Math.cos(pitchInRad); + const cosYaw = Math.cos(yawInRad); + const cosRoll = Math.cos(rollInRad); + return vec(cosRoll * sinPitch * cosYaw + -sinRoll * -sinYaw, cosRoll * sinPitch * sinYaw + -sinRoll * cosYaw, cosRoll * cosPitch); +} +function angWithP(a, p) { return ang(p, a.yaw, a.roll); } +function angleDiff(a, b) { + let diff = (b - a + 180) % 360 - 180; + return diff < -180 ? diff + 360 : diff; +} +function approachAngle(current, target, speed, delta) { + const diff = angleDiff(current, target); + const step = speed * delta; + if (Math.abs(diff) <= step) + return target; + return current + Math.sign(diff) * step; +} +// END ANGLE +function clamp(val, min, max) { + return Math.min(Math.max(val, min), max); +} +function col(red, green, blue, alpha = 255) { return { r: red, g: green, b: blue, a: alpha }; } +function time() { return Instance.GetGameTime(); } +function closestPointOnAABB(p, box) { + return { + x: clamp(p.x, box.min.x, box.max.x), + y: clamp(p.y, box.min.y, box.max.y), + z: clamp(p.z, box.min.z, box.max.z), + }; +} +function getPlayerMins(origin) { + return vecAdd(origin, vec(-16, -16, 0)); +} +function getPlayerMaxs(origin, ducking) { + if (ducking) + return vecAdd(origin, vec(16, 16, 54)); + return vecAdd(origin, vec(16, 16, 72)); +} +function capsuleIntersectsAABB(capsule, box) { + const ab = vecSubtract(capsule.b, capsule.a); + // project box center onto segment + const boxCenter = { + x: (box.min.x + box.max.x) * 0.5, + y: (box.min.y + box.max.y) * 0.5, + z: (box.min.z + box.max.z) * 0.5 + }; + const t = clamp(vecDot(vecSubtract(boxCenter, capsule.a), ab) / vecDot(ab, ab), 0, 1); + const p = vecAdd(capsule.a, vecScale(ab, t)); + const q = closestPointOnAABB(p, box); + const dx = p.x - q.x; + const dy = p.y - q.y; + const dz = p.z - q.z; + const distSq = dx * dx + dy * dy + dz * dz; + return distSq <= capsule.radius * capsule.radius; +} +function shuffle(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +} +function GetPlayerCenter(pawn) { return vecAdd(pawn.GetAbsOrigin(), vec(0, 0, 36)); } +function RemapValClamped(val, in_min, in_max, out_min, out_max) { + let cval = (val - in_min) / (in_max - in_min); + cval = clamp(cval, 0.0, 1.0); + return (out_min + (out_max - out_min) * cval); +} +// END UTIL +Instance.Msg("Licker Script Started"); +var LickerState; +(function (LickerState) { + LickerState[LickerState["NOTHING"] = 0] = "NOTHING"; + LickerState[LickerState["LICKING"] = 1] = "LICKING"; + LickerState[LickerState["JUMPING"] = 2] = "JUMPING"; + LickerState[LickerState["SWIPING"] = 3] = "SWIPING"; +})(LickerState || (LickerState = {})); +var TongueState; +(function (TongueState) { + TongueState[TongueState["IDLE"] = 0] = "IDLE"; + TongueState[TongueState["EXTENDING"] = 1] = "EXTENDING"; + TongueState[TongueState["RETRACTING"] = 2] = "RETRACTING"; + TongueState[TongueState["PULLING"] = 3] = "PULLING"; // Tongue hit a CT and is going back +})(TongueState || (TongueState = {})); +var JumpState; +(function (JumpState) { + JumpState[JumpState["CHILLING"] = 0] = "CHILLING"; + JumpState[JumpState["CHARGING"] = 1] = "CHARGING"; + JumpState[JumpState["FLYING"] = 2] = "FLYING"; +})(JumpState || (JumpState = {})); +var SwipeState; +(function (SwipeState) { + SwipeState[SwipeState["NONE"] = 0] = "NONE"; + SwipeState[SwipeState["SWING"] = 1] = "SWING"; + SwipeState[SwipeState["HIT"] = 2] = "HIT"; +})(SwipeState || (SwipeState = {})); +const TONGUE_OFFSET = { + forward: 0, + right: 0, + up: 0 +}; +const ANIMATIONS = { + idle: "idle", + walk_start: "walk_f_start", + walk_loop: "walk_f_loop", + walk_end: "walk_f_end", + tongue_attack: "attack_tongue", + jump_attack: "attack_tongue_jump_F", + attack2: "attack_l", + die: "dead", + die_static: "dead_static" +}; +const JUMP_DELAY = 1.02; +const SWIPE_DELAY = 1.18; +const SWIPE_HIT_DONE = 1.27; +let ticking = false; +let licker = { + player: undefined, + pawn: undefined, + state: LickerState.NOTHING, + model: { name: "licker_model", entity: undefined }, + pbox: { name: "licker_pbox", entity: undefined }, + dead: false, +}; +let tongue = { + state: TongueState.IDLE, + timeUsed: -1, + firedAt: VEC0, + basePos: VEC0, + tipPos: VEC0, + angles: ang(0, 0, 0), + forward: VEC0, + velocity: VEC0, + distanceTravelled: 0, + capsule: { a: VEC0, b: VEC0, radius: TONGUE_RADIUS }, + particle: { name: "licker_tongue_particle", entity: undefined }, + target: { name: "licker_tongue_target", entity: undefined }, +}; +let targets = []; +let pullTarget = { + pawn: undefined, + glow: { name: "licker_target_glow_2", entity: undefined }, + relay: { name: "licker_target_glow_1", entity: undefined }, + pbox_template: { name: "licker_target_pbox_temp", entity: undefined }, + pbox: undefined, +}; +let jump = { + timeUsed: -1, + jumpTime: -1, + firedAt: VEC0, + state: JumpState.CHILLING, + connection: undefined, +}; +let swipe = { + timeUsed: -1, + swipeTime: -1, + state: SwipeState.NONE, + connection: undefined, + hurt: { name: "licker_swipe_hurt", entity: undefined }, +}; +Instance.OnRoundStart(() => { + let dumb = BLOCK_INFECTION; + BLOCK_INFECTION = !BLOCK_INFECTION; + BLOCK_INFECTION = dumb; + ticking = false; + licker.dead = false; + licker.player = undefined; + licker.pawn = undefined; + licker.state = LickerState.NOTHING; + licker.model.entity = Instance.FindEntityByName(licker.model.name); + licker.pbox.entity = Instance.FindEntityByName(licker.pbox.name); + tongue.state = TongueState.IDLE; + tongue.timeUsed = -1; + tongue.particle.entity = Instance.FindEntityByName(tongue.particle.name); + tongue.target.entity = Instance.FindEntityByName(tongue.target.name); + jump.timeUsed = -1; + jump.state = JumpState.CHILLING; + if (jump.connection != undefined) { + Instance.DisconnectOutput(jump.connection); + jump.connection = undefined; + } + swipe.timeUsed = -1; + swipe.state = SwipeState.NONE; + if (swipe.connection != undefined) { + Instance.DisconnectOutput(swipe.connection); + swipe.connection = undefined; + } + swipe.hurt.entity = Instance.FindEntityByName(swipe.hurt.name); + pullTarget.glow.entity = undefined; + pullTarget.relay.entity = undefined; + /* + pullTarget.relay.entity = I.FindEntityByName(pullTarget.relay.name); + pullTarget.glow.entity = I.FindEntityByName(pullTarget.glow.name); + if (pullTarget.glow.entity) + { + pullTarget.glow.entity.SetColor(col(255,255,255,1)); + if(pullTarget.glow.entity.IsGlowing()) + pullTarget.glow.entity.Unglow(); + }*/ + pullTarget.pbox_template.entity = Instance.FindEntityByName(pullTarget.pbox_template.name); +}); +Instance.OnRoundEnd(() => { + if (licker.pawn && licker.pawn.IsValid()) { + licker.pawn.SetColor(col(255, 255, 255, 255)); + } +}); +Instance.OnScriptInput("LickerPickup", ({ caller, activator }) => { + if (activator instanceof CSPlayerPawn) { + let knife = activator.FindWeaponBySlot(CSGearSlot.KNIFE); + if (knife) + activator.DestroyWeapon(knife); + let controller = activator.GetPlayerController(); + if (controller) + SetLicker(controller, activator); + } +}); +Instance.OnScriptInput("TargetFreed", ({ caller, activator }) => { + LickPullInterrupted(); +}); +Instance.OnScriptInput("TongueAttack", ({ caller, activator }) => { + LickInit(); +}); +Instance.OnScriptInput("JumpAttack", ({ caller, activator }) => { + JumpInit(); +}); +Instance.OnScriptInput("SwipeAttack", ({ caller, activator }) => { + SwipeInit(); +}); +// Licker physbox OnBreak +Instance.OnScriptInput("LickerKilled", ({ caller, activator }) => { + LickerDeath(); +}); +Instance.OnPlayerKill((event) => { + if (event.player === licker.pawn) { + LickerDeath(); + } +}); +function LickerDeath() { + if (licker.dead) + return; + if (licker.state == LickerState.LICKING && tongue.state == TongueState.PULLING) { + if (pullTarget.pbox?.IsValid()) { + pullTarget.pbox.Remove(); + pullTarget.pbox = undefined; + } + if (pullTarget.glow.entity?.IsValid() && pullTarget.glow.entity.IsGlowing()) + pullTarget.glow.entity.Unglow(); + if (tongue.particle.entity?.IsValid()) { + Instance.EntFireAtTarget({ target: tongue.particle.entity, input: "DestroyImmediately", delay: 0.1 }); + } + } + licker.state = LickerState.NOTHING; + licker.dead = true; + licker.model.entity.SetParent(undefined); + licker.player = undefined; + if (licker.pawn?.IsValid() && licker.pawn.IsAlive()) { + licker.pawn.Kill(); + } + licker.pawn = undefined; + ticking = false; + SetAnimPlaybackRate(1.0); + PlayAnimation(ANIMATIONS.die); + SetIdleAnimation(ANIMATIONS.die_static); + licker.pbox.entity?.Remove(); +} +/* DEBUG +I.OnPlayerChat(({player, text}) => { + if(!player) + return; + + if (text === "lick") { + //Give licker to you + + let pawn = player.GetPlayerPawn(); + if (pawn == undefined) + return; + + SetLicker(player, pawn); + } + else if (text === "lickk") + { + // Give licker to someone else + let players : CSPlayerController[] = I.FindEntitiesByClass(player.GetClassName()); + if (players.length <= 1) + { + scrtext("1 or less players",540,5); + return; + } + + for(let i = 0; i < players.length; i++) + { + if (players[i]&&players[i].IsValid()&&players[i]!==player) + { + let pawn = players[i].GetPlayerPawn(); + if (pawn != undefined) + { + SetLicker(players[i], pawn); + break; + } + } + } + } +}); +*/ +function SetLicker(controller, pawn) { + licker.player = controller; + licker.pawn = pawn; + licker.pawn.SetColor(col(255, 255, 255, 0)); + let ang = angWithP(licker.pawn.GetAbsAngles(), 0); + let fwd = getForward(ang); + licker.model.entity.Teleport({ position: vecAdd(licker.pawn?.GetAbsOrigin(), vecScale(fwd, -20)), angles: ang }); + licker.model.entity.SetParent(licker.pawn); + ticking = true; + Instance.SetNextThink(Instance.GetGameTime() + 0.1); +} +let lastTick = 0; +Instance.SetThink(() => { + if (ticking) + Instance.SetNextThink(Instance.GetGameTime() + 0.1); + else + return; + if (!licker.player || !licker.player.IsValid() || !licker.pawn || !licker.pawn.IsValid() || lastTick == 0) { + lastTick = Instance.GetGameTime(); + return; + } + if (licker.pawn.GetTeamNumber() < CS_TEAM_T || !licker.pawn.IsAlive()) { + LickerDeath(); + return; + } + let now = time(); + let delta = now - lastTick; + if (licker.state == LickerState.NOTHING) { + let canlick = (now - tongue.timeUsed) > LICK_COOLDOWN || tongue.timeUsed == -1; + let canjump = (now - jump.timeUsed) > JUMP_COOLDOWN || (jump.timeUsed == -1); + let canswipe = (now - swipe.timeUsed) > SWIPE_COOLDOWN || (swipe.timeUsed == -1); + if (canlick && licker.pawn.IsInputPressed(CSInputs.USE)) { + tongue.timeUsed = now; + licker.state = LickerState.LICKING; + // Trigger a relay so entwatch can track it + Instance.EntFireAtName({ name: "licker_tongue_attack", input: "Trigger" }); + } + else if (canjump && licker.pawn.IsInputPressed(CSInputs.ATTACK2) && licker.pawn.GetGroundEntity() != undefined) { + jump.timeUsed = now; + licker.state = LickerState.JUMPING; + Instance.EntFireAtName({ name: "licker_jump_attack", input: "Trigger" }); + } + else if (canswipe && licker.pawn.IsInputPressed(CSInputs.ATTACK)) { + swipe.timeUsed = now; + licker.state = LickerState.SWIPING; + Instance.EntFireAtName({ name: "licker_swipe_attack", input: "Trigger" }); + } + else { + LickerMovement(delta, now); + } + } + else if (licker.state == LickerState.LICKING) { + if (tongue.state == TongueState.EXTENDING) { + LickTick(delta); + } + else if (tongue.state == TongueState.RETRACTING) { + LickRetract(delta); + } + else if (tongue.state == TongueState.PULLING) { + LickPull(delta); + } + } + else if (licker.state == LickerState.JUMPING) { + JumpTick(now); + } + else if (licker.state == LickerState.SWIPING) { + SwipeTick(now); + } + lastTick = now; +}); +function LickInit() { + let eyepos = licker.pawn.GetEyePosition(); + let eyeang = licker.pawn.GetEyeAngles(); + let fwd = getForward(eyeang); + let fwdOffset = vecScale(fwd, TONGUE_OFFSET.forward); + let rightOffset = vecScale(getRight(eyeang), TONGUE_OFFSET.right); + let upOffset = vecScale(getUp(eyeang), TONGUE_OFFSET.up); + let offset = vecAdd(fwdOffset, vecAdd(rightOffset, upOffset)); + let startpos = vecAdd(eyepos, offset); + let endpos = vecAdd(eyepos, vecScale(fwd, TONGUE_LENGTH)); + // Trace from player eyes so its intuitive for them + // Tongue just goes to there + let tr = Instance.TraceLine({ start: startpos, end: endpos, ignorePlayers: true, ignoreEntity: licker.pbox.entity }); + endpos = tr.end; + if (licker.model.entity != undefined) { + licker.model.entity.SetParent(undefined); + licker.model.entity.Teleport({ angles: ang(0, eyeang.yaw, 0) }); + SetAnimPlaybackRate(1); + PlayAnimation(ANIMATIONS.tongue_attack); + SetIdleAnimation(ANIMATIONS.idle); + } + tongue.firedAt = licker.pawn.GetAbsOrigin(); + tongue.basePos = tongue.particle.entity.GetAbsOrigin(); + tongue.tipPos = tongue.basePos; + tongue.angles = vecAngles(vecSubtract(endpos, tongue.basePos)); + tongue.forward = getForward(tongue.angles); + tongue.velocity = vecScale(tongue.forward, TONGUE_SPEED); + tongue.distanceTravelled = 0; + tongue.capsule.a = tongue.basePos; + tongue.capsule.b = tongue.tipPos; + if (tongue.particle.entity != undefined && tongue.target.entity != undefined) { + Instance.EntFireAtTarget({ target: tongue.particle.entity, input: "Start" }); + tongue.target.entity.Teleport({ position: tongue.basePos, angles: tongue.angles }); + } + targets = []; + let pawns = Instance.FindEntitiesByClass("player"); + for (let i = 0; i < pawns.length; i++) { + if (pawns[i] && pawns[i].IsValid() && pawns[i].GetTeamNumber() == CS_TEAM_CT && pawns[i] !== licker.pawn) { + targets.push(pawns[i]); + } + } + // shuffle for random targetting + shuffle(targets); + tongue.state = TongueState.EXTENDING; + //I.DebugLine({start:startpos, end:endpos, duration:9,color:col(255,128,0)}); +} +// Tongue going out +function LickTick(delta) { + licker.pawn?.Teleport({ position: tongue.firedAt, velocity: VEC0, angularVelocity: VEC0 }); + let move = vecScale(tongue.velocity, delta); + let endpos = vecAdd(tongue.tipPos, move); + let distance = vecLength(vecSubtract(endpos, tongue.tipPos)); + tongue.distanceTravelled += distance; + let tr = Instance.TraceLine({ start: tongue.tipPos, end: endpos, ignorePlayers: true, ignoreEntity: licker.pbox.entity }); + tongue.tipPos = tr.end; + tongue.capsule.b = tongue.tipPos; + //I.DebugLine({start:tongue.basePos, end:tongue.tipPos, duration:delta,color:col(255,128,0)}); + let shortestDist = TONGUE_LENGTH + 1; + let closestPlayer = undefined; + for (let i = targets.length - 1; i >= 0; i--) { + if (!targets[i] || + !targets[i].IsValid() || + targets[i].GetTeamNumber() != CS_TEAM_CT || + !targets[i].IsAlive()) { + targets.splice(i, 1); + continue; + } + let origin = targets[i].GetAbsOrigin(); + let playeraabb = { min: getPlayerMins(origin), max: getPlayerMaxs(origin, targets[i].IsDucked()) }; + if (capsuleIntersectsAABB(tongue.capsule, playeraabb)) { + let distToPlayer = vecLength(vecSubtract(tongue.basePos, vecAdd(origin, vec(0, 0, 36)))); + if (distToPlayer < shortestDist) { + shortestDist = distToPlayer; + closestPlayer = targets[i]; + } + } + } + // Tongue hit a player + if (closestPlayer != undefined && closestPlayer.IsValid()) { + LickPullStart(closestPlayer); + return; + } + // Tongue hit wall or has gone to full distance + if (tr.didHit || tongue.distanceTravelled >= TONGUE_LENGTH) { + tongue.state = TongueState.RETRACTING; + //I.DebugSphere({center:tongue.tipPos, radius:10, duration:2, color:col(255,0,0)}); + tongue.angles = vecAngles(vecSubtract(tongue.basePos, tongue.tipPos)); + tongue.forward = getForward(tongue.angles); + tongue.velocity = vecScale(tongue.forward, TONGUE_SPEED_RETRACT); + return; + } + tongue.target.entity.Teleport({ position: tongue.tipPos }); + //I.DebugSphere({center:tongue.tipPos, radius:tongue.capsule.radius, duration:delta, color:col(255,128,0)}); +} +function LickRetract(delta) { + licker.pawn?.Teleport({ position: tongue.firedAt, velocity: VEC0, angularVelocity: VEC0 }); + let move = vecScale(tongue.velocity, delta); + let endpos = vecAdd(tongue.tipPos, move); + let distance = vecLength(vecSubtract(endpos, tongue.tipPos)); + tongue.distanceTravelled -= distance; + tongue.tipPos = endpos; + tongue.target.entity.Teleport({ position: tongue.tipPos }); + //I.DebugSphere({center:tongue.tipPos, radius:6, duration:delta, color:col(255,128,0)}); + if (tongue.distanceTravelled <= 0) { + LickFinish(); + } +} +function LickPullStart(player) { + tongue.state = TongueState.PULLING; + tongue.tipPos = GetPlayerCenter(player); + tongue.angles = vecAngles(vecSubtract(tongue.basePos, tongue.tipPos)); + tongue.target.entity?.Teleport({ angles: tongue.angles }); + tongue.forward = getForward(tongue.angles); + tongue.velocity = vecScale(tongue.forward, TONGUE_SPEED_PULL); + pullTarget.pawn = player; + // Physbox + pullTarget.pbox = pullTarget.pbox_template.entity.ForceSpawn(tongue.tipPos, ang(0, tongue.angles.yaw, 0))[0]; + let hp = TONGUE_PHYSBOX_HP_BASE + (targets.length * TONGUE_PHYSBOX_HP_PER_CT); + pullTarget.pbox.SetMaxHealth(hp); + pullTarget.pbox.SetHealth(hp); + // Glow stuff + let model = pullTarget.pawn.GetModelName(); + if (!pullTarget.relay.entity || !pullTarget.relay.entity.IsValid()) + pullTarget.relay.entity = Instance.FindEntityByName(pullTarget.relay.name); + if (!pullTarget.glow.entity || !pullTarget.glow.entity.IsValid()) + pullTarget.glow.entity = Instance.FindEntityByName(pullTarget.glow.name); + pullTarget.relay.entity?.SetModel(model); + pullTarget.glow.entity?.SetModel(model); + Instance.EntFireAtTarget({ target: pullTarget.relay.entity, input: "FollowEntity", value: "!activator", activator: pullTarget.pawn }); + Instance.EntFireAtTarget({ target: pullTarget.glow.entity, input: "FollowEntity", value: "!activator", activator: pullTarget.relay.entity }); + // Trigger relay for other map stuff + Instance.EntFireAtName({ name: "licker_hit_player", input: "Trigger", activator: pullTarget.pawn }); +} +function LickPullInterrupted() { + tongue.state = TongueState.RETRACTING; + tongue.velocity = vecScale(tongue.forward, TONGUE_SPEED_RETRACT); + pullTarget.pawn = undefined; + if (pullTarget.glow.entity && pullTarget.glow.entity.IsGlowing()) + pullTarget.glow.entity.Unglow(); +} +function LickPull(delta) { + if (!pullTarget.pawn || !pullTarget.pawn.IsValid() || + pullTarget.pawn.GetTeamNumber() != CS_TEAM_CT || !pullTarget.pawn.IsAlive()) { + if (pullTarget.pbox && pullTarget.pbox.IsValid()) { + pullTarget.pbox.Remove(); + pullTarget.pbox = undefined; + } + LickPullInterrupted(); + return; + } + licker.pawn?.Teleport({ position: tongue.firedAt, velocity: VEC0, angularVelocity: VEC0 }); + let move = vecScale(tongue.velocity, delta); + let endpos = vecAdd(tongue.tipPos, move); + let distance = vecLength(vecSubtract(endpos, tongue.tipPos)); + tongue.distanceTravelled -= distance; + tongue.tipPos = endpos; + let targetKnife = pullTarget.pawn.FindWeaponBySlot(CSGearSlot.KNIFE); + if (targetKnife != undefined) { + pullTarget.pawn.SwitchToWeapon(targetKnife); + } + let pos = pullTarget.pawn.GetEyePosition(); + let min = vec(-16, -16, -8); + let max = vec(16, 16, 0); + // Teleport target to ground or air if tip is above their center + let tr = Instance.TraceBox({ mins: min, maxs: max, start: tongue.tipPos, end: vecAdd(pos, vec(0, 0, -16e3)), ignorePlayers: true, ignoreEntity: pullTarget.pbox }); + //I.DebugLine({start:tongue.tipPos,end:tongue.basePos,duration:delta,color:col(0,0,255)}); + let floorPos = tr.end; + let distToFloor = vecLength(vecSubtract(floorPos, tongue.tipPos)); + //I.Msg("frac:"+tr.fraction+" didHit:"+tr.didHit+" solid:"+tr.startedInSolid+""); + if (distToFloor < 37) { + pullTarget.pawn.Teleport({ position: floorPos, velocity: VEC0 }); + } + else { + let targetpos = vecSubtract(tongue.tipPos, vec(0, 0, 36)); + pullTarget.pawn.Teleport({ position: targetpos, velocity: VEC0 }); + } + let center = GetPlayerCenter(pullTarget.pawn); + tongue.target.entity.Teleport({ position: center }); + pullTarget.pbox?.Teleport({ position: center }); + if (pullTarget.glow.entity && pullTarget.glow.entity.IsValid() && !pullTarget.glow.entity.IsGlowing()) + pullTarget.glow.entity.Glow(col(255, 0, 0)); + //I.DebugSphere({center:tongue.tipPos, radius:tongue.capsule.radius, duration:delta, color:col(255,128,0)}); + if (tongue.distanceTravelled <= 0) { + // Teleport target to where the licker was so they won't be stuck + pullTarget.pawn.Teleport({ position: tongue.firedAt }); + LickFinish(); + } +} +function LickFinish() { + tongue.state = TongueState.IDLE; + if (pullTarget.pbox && pullTarget.pbox.IsValid()) { + pullTarget.pbox.Remove(); + pullTarget.pbox = undefined; + } + if (pullTarget.glow.entity && pullTarget.glow.entity.IsValid() && pullTarget.glow.entity.IsGlowing()) + pullTarget.glow.entity.Unglow(); + if (tongue.particle.entity != undefined) { + Instance.EntFireAtTarget({ target: tongue.particle.entity, input: "DestroyImmediately", delay: 0.1 }); + } + let ang = angWithP(licker.pawn.GetAbsAngles(), 0); + let fwd = getForward(ang); + licker.model.entity.Teleport({ position: vecAdd(licker.pawn.GetAbsOrigin(), vecScale(fwd, -20)), angles: ang }); + licker.model.entity.SetParent(licker.pawn); + licker.state = LickerState.NOTHING; +} +let lastmovetime = -1; +let wasMovingLastCheck = false; +function LickerMovement(delta, timenow) { + let baseAng = licker.pawn.GetEyeAngles(); + baseAng.pitch = 0; + baseAng.roll = 0; + let fwd = getForward(baseAng); + let right = getRight(baseAng); + let fwdDir = 0; + let rightDir = 0; + let isMoving = false; + if (licker.pawn.IsInputPressed(CSInputs.FORWARD)) { + fwdDir += 1; + isMoving = true; + } + if (licker.pawn.IsInputPressed(CSInputs.BACK)) { + fwdDir -= 1; + isMoving = true; + } + if (licker.pawn.IsInputPressed(CSInputs.LEFT)) { + rightDir -= 1; + isMoving = true; + } + if (licker.pawn.IsInputPressed(CSInputs.RIGHT)) { + rightDir += 1; + isMoving = true; + } + if (fwdDir == 0 && rightDir == 0) + fwdDir = 1; + let velocity = licker.pawn.GetAbsVelocity(); + let speed = vecLength(velocity); + // face direction of travel if too fast + if (speed > 251) { + let targetAng = vecAngles(velocity); + let lerped = approachAngle(licker.model.entity.GetAbsAngles().yaw, targetAng.yaw, 180, delta); + licker.model.entity.Teleport({ angles: ang(0, lerped, 0) }); + } + else if (isMoving) { + let targetAng = vecAngles(vecAdd(vecScale(fwd, fwdDir), vecScale(right, rightDir))); + let lerped = approachAngle(licker.model.entity.GetAbsAngles().yaw, targetAng.yaw, 180, delta); + licker.model.entity.Teleport({ angles: ang(0, lerped, 0) }); + } + else if (timenow - lastmovetime > .2) { + let targetAng = vecAngles(vecAdd(vecScale(fwd, fwdDir), vecScale(right, rightDir))); + let lerped = approachAngle(licker.model.entity.GetAbsAngles().yaw, targetAng.yaw, 360, delta); + licker.model.entity.Teleport({ angles: ang(0, lerped, 0) }); + } + if (isMoving) { + lastmovetime = timenow; + let playspeed = RemapValClamped(speed, 100, 300, 1, 2); + SetAnimPlaybackRate(playspeed); + if (!wasMovingLastCheck) { + PlayAnimation(ANIMATIONS.walk_start); + SetIdleAnimation(ANIMATIONS.walk_loop); + } + } + else { + SetAnimPlaybackRate(1); + if (wasMovingLastCheck) { + PlayAnimation(ANIMATIONS.walk_end); + SetIdleAnimation(ANIMATIONS.idle); + } + } + wasMovingLastCheck = isMoving; +} +function PlayAnimation(animName) { + Instance.EntFireAtTarget({ target: licker.model.entity, input: "SetAnimationNotLooping", value: animName }); +} +function SetIdleAnimation(animName) { + Instance.EntFireAtTarget({ target: licker.model.entity, input: "SetIdleAnimationLooping", value: animName }); +} +function SetAnimPlaybackRate(rate) { + Instance.EntFireAtTarget({ target: licker.model.entity, input: "SetPlaybackRate", value: rate.toFixed(2) }); +} +function JumpInit() { + jump.firedAt = licker.pawn.GetAbsOrigin(); + jump.jumpTime = time() + JUMP_DELAY; + jump.state = JumpState.CHARGING; + if (licker.model.entity != undefined) { + SetAnimPlaybackRate(1); + PlayAnimation(ANIMATIONS.jump_attack); + } +} +function JumpTick(timenow) { + if (jump.state == JumpState.FLYING || licker.pawn == undefined) + return; + if (timenow < jump.jumpTime) { + licker.pawn.Teleport({ position: jump.firedAt, velocity: VEC0, angularVelocity: VEC0 }); + return; + } + let jumpdir = ang(0, licker.pawn.GetEyeAngles().yaw, 0); + let fwd = vecScale(getForward(jumpdir), JUMP_FORCE.forward); + let right = vecScale(getRight(jumpdir), JUMP_FORCE.right); + let up = vecScale(getUp(jumpdir), JUMP_FORCE.up); + let jumpforce = vecAdd(fwd, vecAdd(right, up)); + licker.pawn.Teleport({ velocity: jumpforce }); + jump.state = JumpState.FLYING; + if (licker.model.entity != undefined) { + jump.connection = Instance.ConnectOutput(licker.model.entity, "OnAnimationReachedEnd", () => { + if (jump.connection != undefined) + Instance.DisconnectOutput(jump.connection); + jump.connection = undefined; + jump.state = JumpState.CHILLING; + licker.state = LickerState.NOTHING; + }); + } +} +function SwipeInit() { + swipe.swipeTime = time() + SWIPE_DELAY; + swipe.state = SwipeState.SWING; + if (licker.model.entity != undefined) { + SetAnimPlaybackRate(1); + PlayAnimation(ANIMATIONS.attack2); + } +} +function SwipeTick(timenow) { + if (licker.pawn == undefined) + return; + // Clamp speed to half max (125) + let vel = licker.pawn.GetAbsVelocity(); + let speed = vecLength(vel); + if (speed > 125) + licker.pawn.Teleport({ velocity: vecScale(vel, 125 / speed) }); + if (swipe.state == SwipeState.HIT) + return; + if (timenow < swipe.swipeTime) { + return; + } + if (swipe.hurt.entity != undefined && swipe.hurt.entity.IsValid()) { + Instance.EntFireAtTarget({ target: swipe.hurt.entity, input: "Enable" }); + Instance.EntFireAtTarget({ target: swipe.hurt.entity, input: "Disable", delay: SWIPE_HIT_DONE - SWIPE_DELAY }); + } + swipe.state = SwipeState.HIT; + if (licker.model.entity != undefined) { + swipe.connection = Instance.ConnectOutput(licker.model.entity, "OnAnimationReachedEnd", () => { + if (swipe.connection != undefined) + Instance.DisconnectOutput(swipe.connection); + swipe.connection = undefined; + swipe.state = SwipeState.NONE; + licker.state = LickerState.NOTHING; + }); + } +} +Instance.OnModifyPlayerDamage((event) => { + if (!licker.pawn || !licker.pawn.IsValid()) + return; + // Block licker infecting CTs + if (BLOCK_INFECTION && event.attacker && event.attacker === licker.pawn) { + return { abort: true }; + } + // Block CT damage to licker zombie + if (event.player === licker.pawn && event.attacker && event.attacker.GetTeamNumber() == CS_TEAM_CT) + return { abort: true }; +}); +Instance.OnBulletImpact((event) => { + if (!licker.pbox.entity || !licker.pbox.entity.IsValid() || event.hitEntity !== licker.pbox.entity) + return; + if (!licker.pawn || !licker.pawn.IsValid()) + return; + let shooter = event.weapon.GetOwner(); + if (!shooter || !shooter.IsValid() || shooter.GetTeamNumber() != CS_TEAM_CT) + return; + let distance = vecLength(vecSubtract(event.position, shooter.GetEyePosition())); + let data = event.weapon.GetData(); + let kb = data.GetDamage() * Math.pow(data.GetRangeModifier(), (distance * 0.002)); + kb = kb * KB_SCALE; + if (licker.state == LickerState.LICKING) + kb = kb * ABILTY_KB_MODIFIER.lick; + else if (licker.state == LickerState.JUMPING) + kb = kb * ABILTY_KB_MODIFIER.jump; + else if (licker.state == LickerState.SWIPING) + kb = kb * ABILTY_KB_MODIFIER.swipe; + if (kb == 0) + return; + let pushdir = getForward(shooter.GetEyeAngles()); + let kbpush = vecScale(pushdir, kb); + licker.pawn.Teleport({ velocity: vecAdd(licker.pawn.GetAbsVelocity(), kbpush) }); +}); diff --git a/2001/ze_resident_evil_3/npc_root.js b/2001/ze_resident_evil_3/npc_root.js new file mode 100644 index 0000000..38745b9 --- /dev/null +++ b/2001/ze_resident_evil_3/npc_root.js @@ -0,0 +1,1872 @@ +import { Instance } from 'cs_script/point_script'; + +class MathUtils { + static clamp(value, min, max) { + return Math.min(Math.max(value, min), max); + } +} + +const RAD_TO_DEG = 180 / Math.PI; + +class Vector3Utils { + static equals(a, b) { + return a.x === b.x && a.y === b.y && a.z === b.z; + } + static add(a, b) { + return new Vec3(a.x + b.x, a.y + b.y, a.z + b.z); + } + static subtract(a, b) { + return new Vec3(a.x - b.x, a.y - b.y, a.z - b.z); + } + static scale(vector, scale) { + return new Vec3(vector.x * scale, vector.y * scale, vector.z * scale); + } + static multiply(a, b) { + return new Vec3(a.x * b.x, a.y * b.y, a.z * b.z); + } + static divide(vector, divider) { + if (typeof divider === 'number') { + if (divider === 0) + throw Error('Division by zero'); + return new Vec3(vector.x / divider, vector.y / divider, vector.z / divider); + } + else { + if (divider.x === 0 || divider.y === 0 || divider.z === 0) + throw Error('Division by zero'); + return new Vec3(vector.x / divider.x, vector.y / divider.y, vector.z / divider.z); + } + } + static length(vector) { + return Math.sqrt(Vector3Utils.lengthSquared(vector)); + } + static lengthSquared(vector) { + return vector.x ** 2 + vector.y ** 2 + vector.z ** 2; + } + static length2D(vector) { + return Math.sqrt(Vector3Utils.length2DSquared(vector)); + } + static length2DSquared(vector) { + return vector.x ** 2 + vector.y ** 2; + } + static normalize(vector) { + const length = Vector3Utils.length(vector); + return length ? Vector3Utils.divide(vector, length) : Vec3.Zero; + } + static dot(a, b) { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + static cross(a, b) { + return new Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); + } + static inverse(vector) { + return new Vec3(-vector.x, -vector.y, -vector.z); + } + static distance(a, b) { + return Vector3Utils.subtract(a, b).length; + } + static distanceSquared(a, b) { + return Vector3Utils.subtract(a, b).lengthSquared; + } + static floor(vector) { + return new Vec3(Math.floor(vector.x), Math.floor(vector.y), Math.floor(vector.z)); + } + static vectorAngles(vector) { + let yaw = 0; + let pitch = 0; + if (!vector.y && !vector.x) { + if (vector.z > 0) + pitch = -90; + else + pitch = 90; + } + else { + yaw = Math.atan2(vector.y, vector.x) * RAD_TO_DEG; + pitch = Math.atan2(-vector.z, Vector3Utils.length2D(vector)) * RAD_TO_DEG; + } + return new Euler({ + pitch, + yaw, + roll: 0, + }); + } + static lerp(a, b, fraction, clamp = true) { + let t = fraction; + if (clamp) { + t = MathUtils.clamp(t, 0, 1); + } + // a + (b - a) * t + return new Vec3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t); + } + static directionTowards(a, b) { + return Vector3Utils.subtract(b, a).normal; + } + static lookAt(a, b) { + return Vector3Utils.directionTowards(a, b).eulerAngles; + } + static withX(vector, x) { + return new Vec3(x, vector.y, vector.z); + } + static withY(vector, y) { + return new Vec3(vector.x, y, vector.z); + } + static withZ(vector, z) { + return new Vec3(vector.x, vector.y, z); + } +} +class Vec3 { + x; + y; + z; + static Zero = new Vec3(0, 0, 0); + constructor(xOrVector, y, z) { + if (typeof xOrVector === 'object') { + this.x = xOrVector.x === 0 ? 0 : xOrVector.x; + this.y = xOrVector.y === 0 ? 0 : xOrVector.y; + this.z = xOrVector.z === 0 ? 0 : xOrVector.z; + } + else { + this.x = xOrVector === 0 ? 0 : xOrVector; + this.y = y === 0 ? 0 : y; + this.z = z === 0 ? 0 : z; + } + } + get length() { + return Vector3Utils.length(this); + } + get lengthSquared() { + return Vector3Utils.lengthSquared(this); + } + get length2D() { + return Vector3Utils.length2D(this); + } + get length2DSquared() { + return Vector3Utils.length2DSquared(this); + } + /** + * Normalizes the vector (Dividing the vector by its length to have the length be equal to 1 e.g. [0.0, 0.666, 0.333]) + */ + get normal() { + return Vector3Utils.normalize(this); + } + get inverse() { + return Vector3Utils.inverse(this); + } + /** + * Floor (Round down) each vector component + */ + get floored() { + return Vector3Utils.floor(this); + } + /** + * Calculates the angles from a forward vector + */ + get eulerAngles() { + return Vector3Utils.vectorAngles(this); + } + toString() { + return `Vec3: [${this.x}, ${this.y}, ${this.z}]`; + } + equals(vector) { + return Vector3Utils.equals(this, vector); + } + add(vector) { + return Vector3Utils.add(this, vector); + } + subtract(vector) { + return Vector3Utils.subtract(this, vector); + } + divide(vector) { + return Vector3Utils.divide(this, vector); + } + scale(scaleOrVector) { + return typeof scaleOrVector === 'number' + ? Vector3Utils.scale(this, scaleOrVector) + : Vector3Utils.multiply(this, scaleOrVector); + } + multiply(scaleOrVector) { + return typeof scaleOrVector === 'number' + ? Vector3Utils.scale(this, scaleOrVector) + : Vector3Utils.multiply(this, scaleOrVector); + } + dot(vector) { + return Vector3Utils.dot(this, vector); + } + cross(vector) { + return Vector3Utils.cross(this, vector); + } + distance(vector) { + return Vector3Utils.distance(this, vector); + } + distanceSquared(vector) { + return Vector3Utils.distanceSquared(this, vector); + } + /** + * Linearly interpolates the vector to a point based on a 0.0-1.0 fraction + * Clamp limits the fraction to [0,1] + */ + lerpTo(vector, fraction, clamp = true) { + return Vector3Utils.lerp(this, vector, fraction, clamp); + } + /** + * Gets the normalized direction vector pointing towards specified point (subtracting two vectors) + */ + directionTowards(vector) { + return Vector3Utils.directionTowards(this, vector); + } + /** + * Returns an angle pointing towards a point from the current vector + */ + lookAt(vector) { + return Vector3Utils.lookAt(this, vector); + } + /** + * Returns the same vector but with a supplied X component + */ + withX(x) { + return Vector3Utils.withX(this, x); + } + /** + * Returns the same vector but with a supplied Y component + */ + withY(y) { + return Vector3Utils.withY(this, y); + } + /** + * Returns the same vector but with a supplied Z component + */ + withZ(z) { + return Vector3Utils.withZ(this, z); + } +} + +class EulerUtils { + static equals(a, b) { + return a.pitch === b.pitch && a.yaw === b.yaw && a.roll === b.roll; + } + static normalize(angle) { + const normalizeAngle = (angle) => { + angle = angle % 360; + if (angle > 180) + return angle - 360; + if (angle < -180) + return angle + 360; + return angle; + }; + return new Euler(normalizeAngle(angle.pitch), normalizeAngle(angle.yaw), normalizeAngle(angle.roll)); + } + static forward(angle) { + const pitchInRad = (angle.pitch / 180) * Math.PI; + const yawInRad = (angle.yaw / 180) * Math.PI; + const cosPitch = Math.cos(pitchInRad); + return new Vec3(cosPitch * Math.cos(yawInRad), cosPitch * Math.sin(yawInRad), -Math.sin(pitchInRad)); + } + static right(angle) { + const pitchInRad = (angle.pitch / 180) * Math.PI; + const yawInRad = (angle.yaw / 180) * Math.PI; + const rollInRad = (angle.roll / 180) * Math.PI; + const sinPitch = Math.sin(pitchInRad); + const sinYaw = Math.sin(yawInRad); + const sinRoll = Math.sin(rollInRad); + const cosPitch = Math.cos(pitchInRad); + const cosYaw = Math.cos(yawInRad); + const cosRoll = Math.cos(rollInRad); + return new Vec3(-1 * sinRoll * sinPitch * cosYaw + -1 * cosRoll * -sinYaw, -1 * sinRoll * sinPitch * sinYaw + -1 * cosRoll * cosYaw, -1 * sinRoll * cosPitch); + } + static up(angle) { + const pitchInRad = (angle.pitch / 180) * Math.PI; + const yawInRad = (angle.yaw / 180) * Math.PI; + const rollInRad = (angle.roll / 180) * Math.PI; + const sinPitch = Math.sin(pitchInRad); + const sinYaw = Math.sin(yawInRad); + const sinRoll = Math.sin(rollInRad); + const cosPitch = Math.cos(pitchInRad); + const cosYaw = Math.cos(yawInRad); + const cosRoll = Math.cos(rollInRad); + return new Vec3(cosRoll * sinPitch * cosYaw + -sinRoll * -sinYaw, cosRoll * sinPitch * sinYaw + -sinRoll * cosYaw, cosRoll * cosPitch); + } + static lerp(a, b, fraction, clamp = true) { + let t = fraction; + if (clamp) { + t = MathUtils.clamp(t, 0, 1); + } + const lerpComponent = (start, end, t) => { + // Calculate the shortest angular distance + let delta = end - start; + // Normalize delta to [-180, 180] range to find shortest path + if (delta > 180) { + delta -= 360; + } + else if (delta < -180) { + delta += 360; + } + // Interpolate using the shortest path + return start + delta * t; + }; + // a + (b - a) * t + return new Euler(lerpComponent(a.pitch, b.pitch, t), lerpComponent(a.yaw, b.yaw, t), lerpComponent(a.roll, b.roll, t)); + } + static withPitch(angle, pitch) { + return new Euler(pitch, angle.yaw, angle.roll); + } + static withYaw(angle, yaw) { + return new Euler(angle.pitch, yaw, angle.roll); + } + static withRoll(angle, roll) { + return new Euler(angle.pitch, angle.yaw, roll); + } + static rotateTowards(current, target, maxStep) { + const rotateComponent = (current, target, step) => { + let delta = target - current; + if (delta > 180) { + delta -= 360; + } + else if (delta < -180) { + delta += 360; + } + if (Math.abs(delta) <= step) { + return target; + } + else { + return current + Math.sign(delta) * step; + } + }; + return new Euler(rotateComponent(current.pitch, target.pitch, maxStep), rotateComponent(current.yaw, target.yaw, maxStep), rotateComponent(current.roll, target.roll, maxStep)); + } + static clamp(angle, min, max) { + return new Euler(MathUtils.clamp(angle.pitch, min.pitch, max.pitch), MathUtils.clamp(angle.yaw, min.yaw, max.yaw), MathUtils.clamp(angle.roll, min.roll, max.roll)); + } +} +class Euler { + pitch; + yaw; + roll; + static Zero = new Euler(0, 0, 0); + constructor(pitchOrAngle, yaw, roll) { + if (typeof pitchOrAngle === 'object') { + this.pitch = pitchOrAngle.pitch === 0 ? 0 : pitchOrAngle.pitch; + this.yaw = pitchOrAngle.yaw === 0 ? 0 : pitchOrAngle.yaw; + this.roll = pitchOrAngle.roll === 0 ? 0 : pitchOrAngle.roll; + } + else { + this.pitch = pitchOrAngle === 0 ? pitchOrAngle : pitchOrAngle; + this.yaw = yaw === 0 ? 0 : yaw; + this.roll = roll === 0 ? 0 : roll; + } + } + /** + * Returns angle with every componented clamped from -180 to 180 + */ + get normal() { + return EulerUtils.normalize(this); + } + /** + * Returns a normalized forward direction vector + */ + get forward() { + return EulerUtils.forward(this); + } + /** + * Returns a normalized backward direction vector + */ + get backward() { + return this.forward.inverse; + } + /** + * Returns a normalized right direction vector + */ + get right() { + return EulerUtils.right(this); + } + /** + * Returns a normalized left direction vector + */ + get left() { + return this.right.inverse; + } + /** + * Returns a normalized up direction vector + */ + get up() { + return EulerUtils.up(this); + } + /** + * Returns a normalized down direction vector + */ + get down() { + return this.up.inverse; + } + toString() { + return `Euler: [${this.pitch}, ${this.yaw}, ${this.roll}]`; + } + equals(angle) { + return EulerUtils.equals(this, angle); + } + /** + * Linearly interpolates the angle to an angle based on a 0.0-1.0 fraction + * Clamp limits the fraction to [0,1] + * ! Euler angles are not suited for interpolation, prefer to use quarternions instead + */ + lerp(angle, fraction, clamp = true) { + return EulerUtils.lerp(this, angle, fraction, clamp); + } + /** + * Returns the same angle but with a supplied pitch component + */ + withPitch(pitch) { + return EulerUtils.withPitch(this, pitch); + } + /** + * Returns the same angle but with a supplied yaw component + */ + withYaw(yaw) { + return EulerUtils.withYaw(this, yaw); + } + /** + * Returns the same angle but with a supplied roll component + */ + withRoll(roll) { + return EulerUtils.withRoll(this, roll); + } + /** + * Rotates an angle towards another angle by a specific step + * ! Euler angles are not suited for interpolation, prefer to use quarternions instead + */ + rotateTowards(angle, maxStep) { + return EulerUtils.rotateTowards(this, angle, maxStep); + } + /** + * Clamps each component (pitch, yaw, roll) between the corresponding min and max values + */ + clamp(min, max) { + return EulerUtils.clamp(this, min, max); + } +} + +let idPool = 0; +let tasks = []; +function setTimeout(callback, ms) { + const id = idPool++; + tasks.unshift({ + id, + atSeconds: Instance.GetGameTime() + ms / 1000, + callback, + }); + return id; +} +function setInterval(callback, ms) { + const id = idPool++; + tasks.unshift({ + id, + everyNSeconds: ms / 1000, + atSeconds: Instance.GetGameTime() + ms / 1000, + callback, + }); + return id; +} +function clearTimeout(id) { + tasks = tasks.filter((task) => task.id !== id); +} +const clearInterval = clearTimeout; +function clearTasks() { + tasks = []; +} +function runSchedulerTick() { + for (let i = tasks.length - 1; i >= 0; i--) { + const task = tasks[i]; + if (Instance.GetGameTime() < task.atSeconds) + continue; + if (task.everyNSeconds === undefined) + tasks.splice(i, 1); + else + task.atSeconds = Instance.GetGameTime() + task.everyNSeconds; + try { + task.callback(); + } + catch (err) { + //Instance.Msg('An error occurred inside a scheduler task'); + if (err instanceof Error) { + //Instance.Msg(err.message); + //Instance.Msg(err.stack ?? ''); + } + } + } +} +Instance.SetThink(() => { + // Drive scheduled tasks at the minimum accepted interval. + Instance.SetNextThink(Instance.GetGameTime() + 0.1); + runSchedulerTick(); +}); +Instance.SetNextThink(Instance.GetGameTime() + 0.1); +Instance.OnScriptReload({ after: (undefined$1) => { + CLEAR_ALL_INTERVAL = false; +}}); +Instance.OnRoundEnd((stuff) => { + CLEAR_ALL_INTERVAL = true; +}); + + +let CLEAR_ALL_INTERVAL = false; + + +let NPC_EFFECT_HEAD_BROKE; +let NPC_EFFECT_FIRE; +let NPC_EFFECT_BLOOD_HIT; +let NPC_LIST = [] +let NPC_PRESET_TO_SPAWN = [] +const NPC_ANIM_STATUS = { + NONE: 0, + MOVE: 1, + ATTACK: 2, + IDLE: 3, +} + +const NPC_ZOMBIE_TYPE = { + WOMAN: 0, + FAT: 1, + POLICEMAN: 2, +} + +const NPC_ZOMBIE_START_ANIM = { + STAND: undefined, + CRAWLS_A: {szStartAnim: "deaf", bIsStartAnimLoop: false, szPostStartAnim: "standup2", fPostStartAnimDelay: 4.85}, + CRAWLS_B: {szStartAnim: "dead", bIsStartAnimLoop: false, szPostStartAnim: "standup1", fPostStartAnimDelay: 3.75}, + CRAWLS_MOVE: {szStartAnim: "fakedeath", bIsStartAnimLoop: false, szPostStartAnim: "standup1", fPostStartAnimDelay: 3.75}, + DOOR: {szStartAnim: "door", bIsStartAnimLoop: true}, + EAT_A: {szStartAnim: "eda", bIsStartAnimLoop: true}, + EAT_B: {szStartAnim: "eda2", bIsStartAnimLoop: true}, +} + + +Instance.OnRoundStart(() => {OnRoundStart()}); +function OnRoundStart() +{ + clearTasks(); + CLEAR_ALL_INTERVAL = false; + NPC_LIST = [] + NPC_PRESET_TO_SPAWN = [] + + Start_Ticks() +} + +function Start_Ticks() +{ + // const interval = setInterval(() => { + // if (CLEAR_ALL_INTERVAL) { + // clearInterval(interval); + // return; + // } + + // // Tick_Text() + + // }, 0.25 * 1000); + + setTimeout(() => { + // SpawnNPC({origin: new Vec3(118, 250, 64), type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.EAT_A}); + // SpawnNPC({origin: new Vec3(-50, 272, 64), type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_B}); + // SpawnNPC({origin: new Vec3(118, 300, 32), type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_MOVE}); + // SpawnNPC({origin: new Vec3(118, 200, 128), type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.DOOR}); + const PLAYERS = Instance.FindEntitiesByClass("player"); + for (const player of PLAYERS) + { + InitPlayer(player); + } + + }, 1500); + NPC_EFFECT_HEAD_BROKE = Instance.FindEntityByName("temp_effect_00"); + NPC_EFFECT_FIRE = Instance.FindEntityByName("temp_effect_01"); + // Instance.EntFireAtName({name: "npc_00_*", input: "Kill"}) +} +Start_Ticks() + + +function Tick_Text() +{ + let szText = ""; + if (NPC_LIST.length > 0) + { + for (const NPC of NPC_LIST) + { + if (NPC.aHitbox_Base != undefined && NPC.aHitbox_Base[0].IsValid()) + { + szText += `${NPC.iHP_Base} ${NPC.iHP_Head} ` + } + szText += `${NPC.szNamePref}: ${NPC.DebugMsg}\n` + } + } + else + { + szText = "Empty" + } + // const PLAYERS = Instance.FindEntitiesByClass("player"); + + // let vVel = PLAYERS[1].GetAbsVelocity() + // szText += `${vVel.x} ${vVel.y} ${vVel.z} ${Vector3Utils.length(vVel)} ` + + let x = 350 + let y = 400 + let color = { r: 255, g: 0, b: 0, a: 255 }; + + Instance.DebugScreenText(szText, x, y, 0.2, color) +} + +const g_PLAYERS = new Map(); +class class_player +{ + player; + player_controller; + player_slot; + player_name; + + aZombieGrab; + + constructor(_player, _player_controller, _player_slot, _player_name) + { + this.player = _player; + this.player_controller = _player_controller; + this.player_slot = _player_slot; + this.player_name = _player_name; + + this.ResetRound() + } + + ResetRound() + { + this.aZombieGrab = []; + Instance.EntFireAtTarget({target: this.player, input: "KeyValues", value: "movetype 2" }); + } + + GrabZombieStart(szPref) + { + if (this.aZombieGrab.length < 1) + { + Instance.EntFireAtTarget({target: this.player, input: "KeyValues", value: "movetype 1" }); + } + + const ZombieGrabIndex = GetIndexInArray(szPref, this.aZombieGrab); + + if (ZombieGrabIndex == -1) + { + this.aZombieGrab.push(szPref); + } + } + + UnGrabZombieStart(szPref) + { + const ZombieGrabIndex = GetIndexInArray(szPref, this.aZombieGrab); + if (ZombieGrabIndex != -1) + { + this.aZombieGrab.splice(ZombieGrabIndex, 1); + } + + if (this.aZombieGrab.length < 1) + { + Instance.EntFireAtTarget({target: this.player, input: "KeyValues", value: "movetype 2"}); + } + } +} + +class class_npc_zombie +{ + szNamePref; + + lMover; + lKeep; + + aHitbox_Base; + aHitbox_Head; + + iHP_Base; + iHP_Head; + + lModel; + szBodyGroupHeadBreak; + szBodyGroupHead; + + bHasHead; + + lTarget; + lLastTarget; + fTargetTime; + fRetargetTime = 4; + // fDistanceSetTarget = 1500; + fDistanceSetTarget = 250; + iDamageGrab = 1 + fDistanceSetTarget_Min = 350; + fDistanceSetTarget_Max = 500 + + fLifeWithoutHead = 4.0 + iHP_Base = 5; + iHP_Head = 2; + fSpeed = 250.0; + fChargeSpeed = 350.0; + fChargeTriggerDistance = 150.0; + fAnimRateCharge = 1.0; + fAnimRateWalk = 1.0; + + lLastDamager; + Ticking; + bDeath; + bStun + + iNPCStatus; + fLastAttack; + fLastCharge; + bCharge; + + DebugMsg = ''; + + StartAnim; + + npc_items_data = new Map([ + ["flame_detect_npc", {damage: 5}], + ["kar98_detect_npc", {damage: 100}], + ["shotgun_detect_npc", {damage: 80}], + ["misil_detect_npc", {damage: 1000}], + ["saw_detect_npc", {damage: 30}], + ["exp_barrel_detect_npc", {damage: 1000}] + ]); + + constructor(_szNamePref) + { + this.fDistanceSetTarget = GetRandomInt(this.fDistanceSetTarget_Min, this.fDistanceSetTarget_Max); + this.szNamePref = _szNamePref; + this.fLastAttack = 0.0; + this.fLastCharge = 0.0; + + this.aHitbox_Base = []; + this.aHitbox_Head = []; + + this.szBodyGroupHeadBreak = null; + this.bHasHead = true; + this.bCharge = false; + this.bDeath = false; + this.iNPCStatus = NPC_ANIM_STATUS.NONE; + + this.SetTarget(null); + this.lLastTarget = null; + this.fTargetTime = 0.0; + this.lLastDamager = null; + + this.StartAnim = undefined; + + this.triggerCooldowns = new Map(); + + this.Ticking = setInterval(() => { + if (CLEAR_ALL_INTERVAL) { + clearInterval(this.Ticking); + return; + } + this.Tick(); + }, 0.1 * 1000); + } + + PostSpawn() + { + + } + + Tick() + { + if (this.bDeath) + { + return + } + + this.Tick_Target(); + this.Tick_Attack(); + this.Tick_Movement(); + this.Tick_Anim(); + } + + Tick_Target() + { + if (this.iNPCStatus == NPC_ANIM_STATUS.ATTACK || + (Instance.GetGameTime() < this.fTargetTime && + this.TargetValid())) + { + return; + } + + const me_Origin = Vector3Utils.add(this.lMover.GetAbsOrigin(), new Vec3(0, 0, 32)); + const fDistanceSetTarget = this.fDistanceSetTarget; + const NPCSearchFunction = function (player){ + const target_Origin = GetPlayerAbsOriginCenter(player) + if (!IsValidAliveCT(player)) + { + return false; + } + + const fDistance = Vector3Utils.distance(me_Origin, target_Origin); + + if (fDistance > fDistanceSetTarget) + { + return false; + } + + const trace_ignore = [] + const aPhys00 = Instance.FindEntitiesByClass("prop_physics_multiplayer*"); + const aPhys01 = Instance.FindEntitiesByClass("func*"); + for (const ent of aPhys00) {trace_ignore.push(ent)} + for (const ent of aPhys01) {trace_ignore.push(ent)} + const trace = TraceLine(me_Origin, target_Origin, trace_ignore, true); + + if (trace.didHit && + trace.hitEntity != player) + { + return false; + } + + return true; + } + let aTargets = Instance.FindEntitiesByClass("player").filter(player => NPCSearchFunction(player, this)); + if (aTargets.length == 0) + { + this.SetTarget(null); + return; + } + + aTargets = aTargets.sort( function (a, b) { + const a_Origin = a.GetAbsOrigin(); + const distance_a = Vector3Utils.distance(me_Origin, a_Origin); + + const b_Origin = b.GetAbsOrigin(); + const distance_b = Vector3Utils.distance(me_Origin, b_Origin); + + if (distance_a < distance_b) + { + return -1; + } + + if (distance_a > distance_b) + { + return 1; + } + + return 0 + }) + + if (aTargets.length > 1) + { + if (aTargets[0] == this.lLastTarget) + { + aTargets[0] = aTargets[1]; + } + } + + this.SetTarget(aTargets[0]); + } + + SetTarget(lTarget) + { + if (lTarget != null) + { + this.fDistanceSetTarget = GetRandomInt(this.fDistanceSetTarget_Min, this.fDistanceSetTarget_Max); + } + + this.lLastTarget = this.lTarget; + this.lTarget = lTarget; + this.fTargetTime = Instance.GetGameTime() + this.fRetargetTime; + } + + Tick_Attack() + { + if (!this.TargetValid() || + (this.fLastAttack > Instance.GetGameTime()) || + this.bCharge || + (this.iNPCStatus != NPC_ANIM_STATUS.NONE && this.iNPCStatus != NPC_ANIM_STATUS.MOVE)) + { + return; + } + + let me_Origin = this.lMover.GetAbsOrigin() + let target_Origin = this.lTarget.GetAbsOrigin() + + let fDistance = Vector3Utils.distance(me_Origin, target_Origin) + if (fDistance <= 20) + { + this.Tick_Attack_Grab() + return; + } + + if (this.fLastCharge <= Instance.GetGameTime() && + fDistance <= this.fChargeTriggerDistance) + { + this.Tick_Attack_Charge() + return; + } + } + + Tick_Attack_Charge() + { + this.SetAnimation("closehuman", 0.0, this.fAnimRateCharge, false); + + this.fLastCharge = Instance.GetGameTime() + 1.0; + this.iNPCStatus = NPC_ANIM_STATUS.ATTACK; + this.bCharge = true; + + const lTarget = this.lTarget; + const fTickrate = ConvertTimeFromPlayBack(0.25, this.fAnimRateCharge); + let fDelay = ConvertTimeFromPlayBack(1.25, this.fAnimRateCharge); + + const TimerCharge = setInterval(() => { + if (CLEAR_ALL_INTERVAL || + fDelay <= 0.0 || + !this.TargetValid(lTarget) || + this.bDeath || + this.bStun || + !this.bCharge) + { + clearInterval(TimerCharge); + this.bCharge = false; + + if (!CLEAR_ALL_INTERVAL) + { + const DelayStun = setTimeout(() => { + if (CLEAR_ALL_INTERVAL) { + clearInterval(DelayStun); + return; + } + + this.iNPCStatus = NPC_ANIM_STATUS.NONE; + this.fLastAttack = Instance.GetGameTime() + 2.0; + if (this.bHasHead) + { + this.fLastCharge = Instance.GetGameTime() + 2.0; + } + else + { + this.fLastAttack = Instance.GetGameTime() + 9999.0; + } + + }, 1500); + } + + return; + } + + let me_Origin = this.lMover.GetAbsOrigin() + let target_Origin = this.lTarget.GetAbsOrigin() + + let fDistance = Vector3Utils.distance(me_Origin, target_Origin) + + if (fDistance <= 40) + { + clearInterval(TimerCharge); + this.bCharge = false; + + this.Tick_Attack_Grab() + return; + } + fDelay -= fTickrate; + + }, fTickrate * 1000); + } + + Tick_Attack_Grab() + { + this.iNPCStatus = NPC_ANIM_STATUS.ATTACK; + this.SetAnimation("chaval1", 0.0, 1.0, true); + + const lTarget = this.lTarget; + const szPref = this.szNamePref; + + const fTickrate = 0.5; + let fDelay = 3.00; + + const player_class = GetPlayerClassByPlayer(lTarget); + if (player_class != null) + { + player_class.GrabZombieStart(szPref) + } + + const TimerCharge = setInterval(() => { + if (CLEAR_ALL_INTERVAL || + fDelay <= 0.0 || + !this.TargetValid(lTarget) || + this.bDeath || + this.bStun) + { + clearInterval(TimerCharge); + if (!this.bStun) + { + this.iNPCStatus = NPC_ANIM_STATUS.NONE; + this.fLastAttack = Instance.GetGameTime() + 1.0; + } + + if (IsValidPlayer(lTarget)) + { + const player_class_new = GetPlayerClassByPlayer(lTarget); + if (player_class_new != null) + { + player_class_new.UnGrabZombieStart(szPref) + } + } + + return; + } + + NPC_EFFECT_HEAD_BROKE.ForceSpawn(GetPlayerAbsOriginCenter(lTarget)); + + let iHP = lTarget.GetHealth() - this.iDamageGrab; + Instance.EntFireAtTarget({target: lTarget, input: "SetHealth", value: iHP }); + fDelay -= fTickrate; + + }, fTickrate * 1000); + } + + Tick_Anim() + { + if (this.iNPCStatus == NPC_ANIM_STATUS.ATTACK) + { + return; + } + + if (this.TargetValid()) //Move + { + if (this.StartAnim != undefined) + { + if (this.StartAnim.szPostStartAnim != undefined) + { + this.iNPCStatus = NPC_ANIM_STATUS.ATTACK; + this.SetAnimation(this.StartAnim.szPostStartAnim, 0.0, 1.0, false); + + const DelayFade = setTimeout(() => { + if (CLEAR_ALL_INTERVAL) + { + clearInterval(DelayFade); + return; + } + this.iNPCStatus = NPC_ANIM_STATUS.NONE; + this.StartAnim = undefined; + + }, this.StartAnim.fPostStartAnimDelay * 1000); + + return; + } + + this.StartAnim = undefined; + } + + if (this.iNPCStatus != NPC_ANIM_STATUS.MOVE) + { + const szMove = ["walk1", "move"] + const iValue = GetRandomInt(0, szMove.length-1); + + this.iNPCStatus = NPC_ANIM_STATUS.MOVE; + this.SetAnimation(szMove[iValue], 0.0, this.fAnimRateWalk, true); + } + + } + else //Idle + { + if (this.iNPCStatus != NPC_ANIM_STATUS.IDLE) + { + this.iNPCStatus = NPC_ANIM_STATUS.IDLE; + if (this.StartAnim != undefined) + { + this.SetAnimation(this.StartAnim.szStartAnim, 0.0, 1.0, this.StartAnim.bIsStartAnimLoop); + } + else + { + const szMove = ["idle5", "idl2", "idle3", "idle4", "idle"] + const iValue = GetRandomInt(0, szMove.length-1); + this.SetAnimation(szMove[iValue], 0.0, 1.0, true); + } + } + } + } + + Tick_Movement() + { + if (!this.TargetValid()) + { + return; + } + + if (!this.bCharge && + this.iNPCStatus != NPC_ANIM_STATUS.MOVE) + { + return; + } + + let me_Origin = this.lMover.GetAbsOrigin() + let me_Angles = this.lMover.GetAbsAngles() + let target_Origin = this.lTarget.GetAbsOrigin() + + let target_Angles = Vector3Utils.lookAt(me_Origin, target_Origin); + target_Angles.roll = 0 + target_Angles.pitch = 0 + + let Step = 10; + let qAngles = EulerUtils.rotateTowards(me_Angles, target_Angles, Step) + + target_Angles.pitch = -15 + + let fDistance = Vector3Utils.distance(me_Origin, target_Origin) + let fDistance_Limit = 10; + let vVelocity = {x: 0, y: 0, z: 0} + if (fDistance > fDistance_Limit) + { + let fSpeed = 100; + let fLimit = this.fSpeed; + if (this.bCharge) + { + fLimit = this.fChargeSpeed; + } + + let me_Velocity = this.lMover.GetAbsVelocity(); + vVelocity = Vector3Utils.add(me_Velocity, (Vector3Utils.scale(EulerUtils.forward(target_Angles), fSpeed))) + if (Vector3Utils.length(vVelocity) > fLimit) + { + vVelocity = {x: 0, y: 0, z: 0} + } + } + + if (Vector3Utils.equals({x: 0, y: 0, z: 0}, vVelocity)) + { + this.lMover.Teleport({angles: qAngles}) + } + else + { + this.lMover.Teleport({angles: qAngles, velocity: vVelocity}) + } + } + + TargetValid() + { + if (!IsValidAliveCT(this.lTarget)) + { + this.SetTarget(null); + return false; + } + + return true + } + + DamageBullet(aData) + { + let bHead = false + if (aData.caller.GetEntityName().search("_b_") != -1) + { + bHead = true + } + + let iDamage = 1 + + this.lLastDamager = aData.activator + if (this.iNPCStatus == NPC_ANIM_STATUS.IDLE) + { + if (!this.TargetValid()) + { + this.SetTarget(this.lLastDamager); + } + } + + this.HP_Checks(bHead, iDamage, aData.caller, aData.activator) + } + + ItemDamage(aData) + { + if(!aData.activator?.IsValid() || !aData.caller?.IsValid()) return; + + const item_name = aData.activator.GetEntityName(); + let result = item_name.substring(0, item_name.lastIndexOf("_")); + + let item = null; + + if(this.npc_items_data.has(item_name)) + { + item = this.npc_items_data.get(item_name); + } + else if(this.npc_items_data.has(result)) + { + item = this.npc_items_data.get(result); + } + + if(item) + { + this.iHP_Base -= item.damage; + const isFlame = (item_name === "flame_detect_npc" || result === "flame_detect_npc"); + + if(isFlame) + { + const trigger = aData.caller; + const currentTime = Instance.GetGameTime(); + let lastTime = this.triggerCooldowns.get(trigger) || 0; + + if(currentTime - lastTime >= 5.0) + { + this.triggerCooldowns.set(trigger, currentTime); + + let vec_body = this.lModel.GetAbsOrigin(); + const pos_f = { + x: vec_body.x, + y: vec_body.y, + z: vec_body.z + 32 + }; + + const spawn_ent = NPC_EFFECT_FIRE.ForceSpawn(pos_f); + let particle = null; + for(let i = 0; i < spawn_ent.length; i++) + { + let ent = spawn_ent[i]; + if(ent?.IsValid() && ent.GetClassName() === "info_particle_system") + { + particle = ent; + } + } + + if(particle?.IsValid()) + { + particle.SetParent(this.lModel); + } + } + } + + if(this.iHP_Base < 1) + { + this.BreakBase() + } + + //Instance.Msg(`${aData.activator?.GetEntityName()} Damaged Npc ${aData.caller?.GetEntityName()}, Damage: ${item.damage} | Previous Hp: ${this.iHP_Base + item.damage} | Current Hp ${this.iHP_Base}`); + } + } + // + HP_Checks(bHead, iDamage, lHitbox, lDamager) + { + if (iDamage == -1) + { + iDamage = this.iHP_Base; + } + + if (bHead) + { + this.iHP_Head -= iDamage + + iDamage *= 1.3 + + if (this.iHP_Head < 1) + { + this.BreakHead(lHitbox) + } + } + + this.iHP_Base -= iDamage + if (this.iHP_Base < 1) + { + this.BreakBase() + } + } + + GetDeathAnim() + { + const szDeath = [ "deaf", + "dead2", + "dead",] + const iValue = GetRandomInt(0, szDeath.length-1); + + this.SetAnimation(szDeath[iValue]); + this.SetDefaultAnimation(szDeath[iValue], 0.00, false); + + return undefined; + } + + + SetAnimation(szName, fDelay = 0.00, fRate = 1.00, bLoop = false) + { + if (bLoop) + { + Instance.EntFireAtTarget({target: this.lModel, input: "SetAnimationLooping", value: szName, delay: fDelay}); + } + else + { + Instance.EntFireAtTarget({target: this.lModel, input: "SetAnimationNotLooping", value: szName, delay: fDelay}); + } + Instance.EntFireAtTarget({target: this.lModel, input: "SetPlayBackRate", value: fRate, delay: fDelay}); + } + + SetDefaultAnimation(szName, fDelay = 0.00, bLoop = true) + { + if (bLoop) + { + Instance.EntFireAtTarget({target: this.lModel, input: "SetIdleAnimationLooping", value: szName, delay: fDelay}); + } + else + { + Instance.EntFireAtTarget({target: this.lModel, input: "SetIdleAnimationNotLooping", value: szName, delay: fDelay}); + } + } + + + KillBase() + { + clearTimeout(this.Ticking) + RemoveNPC(this.szNamePref) + this.bDeath = true; + + for (const Hitbox of this.aHitbox_Base) + { + Instance.EntFireAtTarget({target: Hitbox, input: "Kill"}) + } + + for (const Hitbox of this.aHitbox_Head) + { + Instance.EntFireAtTarget({target: Hitbox, input: "Kill"}) + } + } + + KillBaseFull() + { + Instance.EntFireAtTarget({target: this.lKeep, input: "Kill"}) + Instance.EntFireAtTarget({target: this.lMover, input: "Kill"}) + Instance.EntFireAtTarget({target: this.lModel, input: "Kill"}) + } + + Kill() + { + if (this.bDeath) + { + return + } + this.KillBase() + this.KillBaseFull() + } + + KillFade() + { + if (this.bDeath) + { + return + } + this.KillBase() + + let fDelay = this.GetDeathAnim(); + if (fDelay == undefined) + { + fDelay = 5.0; + } + + const DelayFade = setTimeout(() => { + if (CLEAR_ALL_INTERVAL) { + clearInterval(DelayFade); + return; + } + + let iAlpha = 255 + const TimerAlpha = setInterval(() => { + + if (CLEAR_ALL_INTERVAL || + iAlpha < 50) + { + clearInterval(TimerAlpha); + + this.KillBaseFull(); + return; + } + iAlpha -= 6; + Instance.EntFireAtTarget({target: this.lModel, input: "Alpha", value: "" + iAlpha}) + }, 0.1 * 1000); + + }, fDelay * 1000); + } + + BreakBase() + { + let vec_body = this.lModel.GetAbsOrigin(); + const pos_f = { + x: vec_body.x, + y: vec_body.y, + z: vec_body.z + 32 + } + const spawn_ent = NPC_EFFECT_HEAD_BROKE.ForceSpawn(pos_f); + this.KillFade() + } + + BreakHead(lHead) + { + let vecHead = lHead.GetAbsOrigin(); + NPC_EFFECT_HEAD_BROKE.ForceSpawn(vecHead); + Instance.EntFireAtTarget({target: lHead, input: "Kill"}) + + if (this.szBodyGroupHeadBreak != null) + { + Instance.EntFireAtTarget({target: this.lModel, input: "SetBodyGroup", value: this.szBodyGroupHeadBreak}) + } + this.SetAnimation("headshoot"); + + this.aHitbox_Head = [] + + this.bHasHead = false; + this.bStun = true; + this.iNPCStatus = NPC_ANIM_STATUS.ATTACK; + + const lLastDamager = this.lLastDamager; + + const DelayStun = setTimeout(() => { + if (CLEAR_ALL_INTERVAL) { + clearInterval(DelayStun); + return; + } + this.bStun = false; + this.iNPCStatus = NPC_ANIM_STATUS.NONE; + this.fLastAttack = Instance.GetGameTime() + 1.0; + + }, 1750); + + const DelayDeath = setTimeout(() => { + if (CLEAR_ALL_INTERVAL) { + clearInterval(DelayDeath); + return; + } + this.HP_Checks(false, -1, lHead, lLastDamager) + }, this.fLifeWithoutHead * 1000); + } +} + + +class class_npc_zombie_woman extends class_npc_zombie +{ + fAnimRateWalk = 1.75; + fChargeSpeed = 250.0; + fChargeTriggerDistance = 100; + fAnimRateCharge = 0.8; + iDamageGrab = 5 + iHP_Base = 100; + iHP_Head = 50; + fSpeed = 210; + iDamageGrab = 4; + constructor(_szNamePref) + { + super(_szNamePref); + } + + PostSpawn() + { + this.aHitbox_Head[0].SetEntityName("Amber_Laura_Heard_b_"); + this.aHitbox_Base[0].SetEntityName("Amber_Laura_Heard") + this.lModel.SetModel("models/zombie/woman/woman.vmdl"); + Instance.EntFireAtTarget({target: this.lModel, input: "SetBodyGroup", value: this.szBodyGroupHead}) + } +} +class class_npc_zombie_fat extends class_npc_zombie +{ + fAnimRateWalk = 1.5; + fChargeSpeed = 350.0; + fChargeTriggerDistance = 250; + fAnimRateCharge = 1.2; + iHP_Base = 150; + iHP_Head = 75; + fSpeed = 125; + iDamageGrab = 7; + constructor(_szNamePref) + { + super(_szNamePref); + } + + PostSpawn() + { + this.aHitbox_Head[0].SetEntityName("George_Perry_Floyd_b_"); + this.aHitbox_Base[0].SetEntityName("George_Perry_Floyd") + this.lModel.SetModel("models/zombie/woman/gooberman.vmdl"); + Instance.EntFireAtTarget({target: this.lModel, input: "SetBodyGroup", value: this.szBodyGroupHead}) + } +} +class class_npc_zombie_policeman extends class_npc_zombie +{ + fAnimRateWalk = 1.5; + fChargeSpeed = 280.0; + fChargeTriggerDistance = 200; + fAnimRateCharge = 0.9; + iHP_Base = 125; + iHP_Head = 60; + fSpeed = 165; + iDamageGrab = 6; + constructor(_szNamePref) + { + super(_szNamePref); + } + + PostSpawn() + { + this.aHitbox_Head[0].SetEntityName("Derek_Michael_Chauvin_b_") + this.aHitbox_Base[0].SetEntityName("Derek_Michael_Chauvin") + this.lModel.SetModel("models/zombie/woman/policeman.vmdl"); + Instance.EntFireAtTarget({target: this.lModel, input: "SetBodyGroup", value: this.szBodyGroupHead}) + } +} + + +function SpawnNPC(kv) +{ + // kv = {origin: vec, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.STAND} + + NPC_PRESET_TO_SPAWN.unshift(kv) + + let Template = Instance.FindEntityByName("npc_00"); + Template.ForceSpawn(kv.origin, kv.angle); +} + +function RemoveNPC(szNamePref) +{ + for (let i = 0; i < NPC_LIST.length; i++) + { + if (NPC_LIST[i].szNamePref == szNamePref) + { + NPC_LIST.splice(i, 1); + return + } + } +} +Instance.OnPlayerDisconnect((hEvent) => { + g_PLAYERS.delete(hEvent.playerSlot); +}); + +Instance.OnPlayerReset((hEvent) => { + const player = hEvent.player; + if (!player?.IsValid()) + { + return; + } + + InitPlayer(player); +}) + +function InitPlayer(player) +{ + const player_controller = player.GetPlayerController(); + const player_name = player_controller?.GetPlayerName(); + const player_slot = player_controller?.GetPlayerSlot(); + if (!g_PLAYERS.has(player_slot)) + { + g_PLAYERS.set(player_slot, new class_player(player, player_controller, player_slot, player_name)); + return; + } + + const player_class = g_PLAYERS.get(player_slot); + player_class.player = player; + player_class.player_controller = player_controller; + player_class.player_slot = player_slot; + player_class.player_name = player_name; + + player_class.ResetRound(); +} + +Instance.OnScriptInput("Tes", (Activator_Caller_Data) => { + let player_class = GetPlayerClassByPlayer(Activator_Caller_Data.activator); + if (player_class == null) + { + return; + } +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Stand", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.STAND}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Stand", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.STAND}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Stand", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.STAND}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Crawls_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Crawls_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Crawls_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Crawls_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_B}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Crawls_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_B}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Crawls_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_B}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Crawls_C", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_MOVE}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Crawls_C", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_MOVE}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Crawls_C", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.CRAWLS_MOVE}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Door", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.DOOR}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Door", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.DOOR}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Door", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.DOOR}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Eat_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.EAT_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Eat_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.EAT_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Eat_A", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.EAT_A}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Woman_Eat_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.WOMAN, startanim: NPC_ZOMBIE_START_ANIM.EAT_B}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Policeman_Eat_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.POLICEMAN, startanim: NPC_ZOMBIE_START_ANIM.EAT_B}); +}) + +Instance.OnScriptInput("Spawn_NPC_Zombie_Fat_Eat_B", (Activator_Caller_Data) => { + const vOrigin = Activator_Caller_Data.caller.GetAbsOrigin(); + const vAngle = Activator_Caller_Data.caller.GetAbsAngles(); + SpawnNPC({origin: vOrigin, angle: vAngle, type: NPC_ZOMBIE_TYPE.FAT, startanim: NPC_ZOMBIE_START_ANIM.EAT_B}); +}) + + +Instance.OnScriptInput("Input_Connect_NPC_00", (Activator_Caller_Data) => { + let KV = NPC_PRESET_TO_SPAWN[0]; + NPC_PRESET_TO_SPAWN.splice(0, 1); + + let szNamePref = Activator_Caller_Data.caller.GetEntityName().replace("npc_00_connect_relay", "") + + let NPC; + if (KV.type == NPC_ZOMBIE_TYPE.WOMAN) + { + NPC = new class_npc_zombie_woman(szNamePref); + } + else if (KV.type == NPC_ZOMBIE_TYPE.FAT) + { + NPC = new class_npc_zombie_fat(szNamePref); + } + else if (KV.type == NPC_ZOMBIE_TYPE.POLICEMAN) + { + NPC = new class_npc_zombie_policeman(szNamePref); + } + + if (NPC == undefined) + { + return; + } + + let lMover = Instance.FindEntityByName("npc_00_phys" + szNamePref) + + let lHitBox_Base = Instance.FindEntityByName("npc_00_hitbox_a" + szNamePref) + let lHitBox_Head = Instance.FindEntityByName("npc_00_hitbox_b" + szNamePref) + let lModel = Instance.FindEntityByName("npc_00_model" + szNamePref) + let lKeep = Instance.FindEntityByName("npc_00_keep" + szNamePref) + + NPC.lMover = lMover; + NPC.lKeep = lKeep; + NPC.lModel = lModel; + NPC.szBodyGroupHeadBreak = "normal, 0"; + NPC.szBodyGroupHead = "normal, 1"; + + NPC.aHitbox_Base.push(lHitBox_Base); + NPC.aHitbox_Head.push(lHitBox_Head); + + Instance.ConnectOutput(lHitBox_Base, "OnHealthChanged", (Activator_Caller_Data) => { + Input_Item_Damage_NPC(Activator_Caller_Data); + }); + Instance.ConnectOutput(lHitBox_Base, "OnHealthChanged", (Activator_Caller_Data) => { + Input_Damage_NPC(Activator_Caller_Data); + }); + Instance.ConnectOutput(lHitBox_Head, "OnHealthChanged", (Activator_Caller_Data) => { + Input_Damage_NPC(Activator_Caller_Data); + }); + + if (KV.startanim != undefined) + { + NPC.StartAnim = KV.startanim; + } + + NPC.PostSpawn(); + + NPC_LIST.push(NPC); +}) + +function Input_Damage_NPC(aData) +{ + let class_NPC = GetNPCClassByPhysBox(aData.caller); + if (class_NPC == null) + { + return; + } + class_NPC.DamageBullet(aData) +} + +function Input_Item_Damage_NPC(aData) +{ + let class_NPC = GetNPCClassByPhysBox(aData.caller); + if (class_NPC == null) + { + return; + } + //Instance.Msg(`PhysBox GetDamage From ${aData.activator?.GetEntityName()}`); + class_NPC.ItemDamage(aData) +} + +function GetPlayerClassByPlayer(player) +{ + const player_controller = player?.GetPlayerController(); + if (player_controller?.IsValid()) + { + const player_slot = player_controller.GetPlayerSlot(); + if (g_PLAYERS.has(player_slot)) + { + return g_PLAYERS.get(player_slot); + } + } + return null; +} + +function GetIndexInArray(value, array) +{ + for (let i = 0; i < array.length; i++) + { + if (array[i] == value) + { + return i; + } + } + + return -1; +} + +function GetNPCClassByPhysBox(Phys) +{ + for (let i = 0; i < NPC_LIST.length; i++) + { + for (let a = 0; a < NPC_LIST[i].aHitbox_Head.length; a++) + { + if (NPC_LIST[i].aHitbox_Head[a] == Phys) + { + return NPC_LIST[i]; + } + } + + for (let a = 0; a < NPC_LIST[i].aHitbox_Base.length; a++) + { + if (NPC_LIST[i].aHitbox_Base[a] == Phys) + { + return NPC_LIST[i]; + } + } + } + + return null; +} + +function ConvertTimeFromPlayBack(fTime, fSetPlayBackRate = -1) +{ + if (fSetPlayBackRate == -1) + { + return fTime / g_fPlayBackRate; + } + else + { + return fTime / fSetPlayBackRate; + } +} + +function IsValidAliveCT(player) +{ + return (player != null && player.IsValid() && player.IsAlive() && player.GetTeamNumber() == 3) +} + +function IsValidPlayer(player) +{ + return (player != null && player.IsValid() && player.IsAlive()) +} + +function GetValidPlayers() +{ + return Instance.FindEntitiesByClass("player").filter(p => IsValidPlayer(p)); +} + +function GetPlayerAbsOriginCenter(player) +{ + return Vector3Utils.add(player.GetAbsOrigin(), new Vec3(0, 0, 32)); +} + +function TraceLine(vec1, vec2, ignore, bignoreplayer = false) +{ + return Instance.TraceLine({start: vec1, end: vec2, ignoreEntity: ignore, ignorePlayers: bignoreplayer}); +} + +function GetRandomInt(min, max) +{ + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +function getPosKey(vec) +{ + return `${Math.floor(vec.x)}_${Math.floor(vec.y)}_${Math.floor(vec.z)}`; +} + +//Instance.Msg("Script Loaded!"); +OnRoundStart() diff --git a/2001/ze_resident_evil_3/shq_00.js b/2001/ze_resident_evil_3/shq_00.js new file mode 100644 index 0000000..789975d --- /dev/null +++ b/2001/ze_resident_evil_3/shq_00.js @@ -0,0 +1,203 @@ +import { Instance } from 'cs_script/point_script'; +//674 + +// 1 Тит Андроник (1591–1592) — самая кровавая и ранняя проба пера. +// 2 Ромео и Джульетта (1595–1596) — лирическая трагедия. +// 3 Гамлет (1599–1601) +// 4 Отелло (1603–1604) +// 5 Король Лир (1605–1606) +// 6 Макбет (1606) +// 8 Антоний и Клеопатра (1606) +// 9 Кориолан (1607–1608) +// 0 Тимон Афинский (1607–1608) +////Instance.Msg(`asd`) +class Vec3 { + x; + y; + z; + static Zero = new Vec3(0, 0, 0); + constructor(xOrVector, y, z) { + if (typeof xOrVector === 'object') { + this.x = xOrVector.x === 0 ? 0 : xOrVector.x; + this.y = xOrVector.y === 0 ? 0 : xOrVector.y; + this.z = xOrVector.z === 0 ? 0 : xOrVector.z; + } + else { + this.x = xOrVector === 0 ? 0 : xOrVector; + this.y = y === 0 ? 0 : y; + this.z = z === 0 ? 0 : z; + } + } +} + +////Instance.Msg(`45`) +let g_hButtons = []; +let g_iCode = ""; +let g_iPressCode = ""; +let g_vecButtonsSpawn = new Vec3(927, -3452, 78.625); +let g_Dir_x = 1; +let g_Dir_y = 0; +let g_Size = 8.40; + +////Instance.Msg(`IzxcT`) + +function OnRoundStart() +{ + Instance.EntFireAtName({name: "shq_script", input: "RunScriptInput", value: "Init", delay: 0.02}) +} + +Instance.OnScriptInput("Init", () => {Init()}) + +function Init() +{ + ////Instance.Msg(`INIT SCRIPT`) + g_hButtons = []; + let aButtons = ["00", "01", "02", "03", "04", "05", "06", "07", "08", "09"]; + ////Instance.Msg(`322`) + g_iCode = ""; + g_iPressCode = ""; + + if (aButtons.length === 0) { + ////Instance.Msg(`ERROR: aButtons is empty!`); + return; + } + + for (let i = 0; i < 6; i++) + { + if (aButtons.length === 0) { + ////Instance.Msg(`ERROR: Not enough buttons! Only ${i} generated.`); + break; + } + + const iRandomValue = GetRandomInt(0, aButtons.length - 1); + const szName = "shq_block_" + aButtons[iRandomValue]; + const Ent = Instance.FindEntityByName(szName); + + if (!Ent) { + ////Instance.Msg(`ERROR: Entity not found: ${szName}`); + continue; + } + + const buttonValue = aButtons[iRandomValue]; + if (buttonValue && buttonValue[1]) { + g_iCode += buttonValue[1]; + } else { + ////Instance.Msg(`ERROR: Invalid button value: ${buttonValue}`); + g_iCode += "?"; + } + + ////Instance.Msg(`INIT SCRIPT`) + + aButtons.splice(iRandomValue, 1); + const vecSet = new Vec3(g_vecButtonsSpawn.x + g_hButtons.length * g_Dir_x * g_Size, + g_vecButtonsSpawn.y + g_hButtons.length * g_Dir_y * g_Size, + g_vecButtonsSpawn.z) + + Instance.EntFireAtTarget({ target: Ent, input: "KeyValue", value: `origin ${vecSet.x} ${vecSet.y} ${vecSet.z}`}); + + ////Instance.Msg(`520 ${g_vecButtonsSpawn.y + g_hButtons.length * g_Dir_y * g_Size}`) + g_hButtons.push(Ent); + ////Instance.Msg(`INIT SCRIPT ${vecSet.x} ${vecSet.y} ${vecSet.z} `) + } + + ////Instance.Msg(`123`) + //Instance.EntFireAtName({name: "shq_original", input: "SetMessage", value: g_iCode}) + ////Instance.Msg(`zxc`) + ////Instance.Msg(`${g_iCode}`); +} +function PressButton(ID) +{ + if (ID == -1) //RESET + { + g_iPressCode = "" + Instance.EntFireAtName({name: "shq_pass", input: "SetMessage", value: g_iPressCode}) + Instance.EntFireAtName({name: "shq_pass", input: "FireUser3"}) + return; + } + + if (ID == -2) //ENTER + { + if (g_iPressCode == g_iCode) + { + g_iPressCode = "" + Instance.EntFireAtName({name: "shq_pass", input: "FireUser1"}) + } + else + { + g_iPressCode = "" + Instance.EntFireAtName({name: "shq_pass", input: "SetMessage", value: g_iPressCode}) + Instance.EntFireAtName({name: "shq_pass", input: "FireUser2"}) + } + return; + } + + g_iPressCode += ID; + + if (g_iPressCode.length > 6) + { + let arr = g_iPressCode.split(''); // Convert to array + arr.splice(0, 1); // Now splice works + g_iPressCode = arr.join(''); // Convert back to string: "234567" + } + + if (g_iPressCode.length == 6) + { + if (g_iPressCode == g_iCode) + { + g_iPressCode = "" + Instance.EntFireAtName({name: "shq_pass", input: "FireUser1"}) + } + else + { + g_iPressCode = "" + Instance.EntFireAtName({name: "shq_pass", input: "SetMessage", value: g_iPressCode}) + Instance.EntFireAtName({name: "shq_pass", input: "FireUser2"}) + } + } + Instance.EntFireAtName({name: "shq_pass", input: "SetMessage", value: "" + g_iPressCode}) +} + +Instance.OnScriptInput("Button_00", (Activator_Caller_Data) => { + PressButton(0); +}) +Instance.OnScriptInput("Button_01", (Activator_Caller_Data) => { + PressButton(1); +}) +Instance.OnScriptInput("Button_02", (Activator_Caller_Data) => { + PressButton(2); +}) +Instance.OnScriptInput("Button_03", (Activator_Caller_Data) => { + PressButton(3); +}) +Instance.OnScriptInput("Button_04", (Activator_Caller_Data) => { + PressButton(4); +}) +Instance.OnScriptInput("Button_05", (Activator_Caller_Data) => { + PressButton(5); +}) +Instance.OnScriptInput("Button_06", (Activator_Caller_Data) => { + PressButton(6); +}) +Instance.OnScriptInput("Button_07", (Activator_Caller_Data) => { + PressButton(7); +}) +Instance.OnScriptInput("Button_08", (Activator_Caller_Data) => { + PressButton(8); +}) +Instance.OnScriptInput("Button_09", (Activator_Caller_Data) => { + PressButton(9); +}) +Instance.OnScriptInput("Button_R", (Activator_Caller_Data) => { + PressButton(-1); +}) + +function GetRandomInt(min, max) +{ + min = Math.ceil(min); + max = Math.floor(max); + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +Instance.OnRoundStart(() => { + OnRoundStart(); +}); diff --git a/2001/ze_resident_evil_3/skins.js b/2001/ze_resident_evil_3/skins.js new file mode 100644 index 0000000..ec32c74 --- /dev/null +++ b/2001/ze_resident_evil_3/skins.js @@ -0,0 +1,14 @@ +import { Instance } from "cs_script/point_script"; + +const model_skin = "jill"; +Instance.OnScriptInput("ChangeSkin", ({activator}) => { + + if(activator?.IsValid()) + { + const player = activator; + const player_c = player?.GetPlayerController(); + const player_p = player_c?.GetPlayerPawn(); + player_p?.SetModel("characters/models/microrost/jill_valentine.vmdl"); + } +}); +