mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 21:53:46 +03:00
351 lines
9.3 KiB
Lua
351 lines
9.3 KiB
Lua
--[[
|
|
| This file was obtained through the combined efforts
|
|
| of Madbluntz & Plymouth Antiquarian Society.
|
|
|
|
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
|
| Maloy, DrPepper10 @ RIP, Atle!
|
|
|
|
|
| Visit for more: https://plymouth.thetwilightzone.ru/
|
|
--]]
|
|
|
|
-- traitor equipment: teleporter
|
|
|
|
AddCSLuaFile()
|
|
|
|
SWEP.HoldType = "normal"
|
|
|
|
if CLIENT then
|
|
SWEP.PrintName = "tele_name"
|
|
SWEP.Slot = 7
|
|
|
|
SWEP.ViewModelFlip = false
|
|
SWEP.ViewModelFOV = 10
|
|
SWEP.DrawCrosshair = false
|
|
SWEP.CSMuzzleFlashes = false
|
|
|
|
SWEP.EquipMenuData = {
|
|
type = "item_weapon",
|
|
desc = "tele_desc"
|
|
};
|
|
|
|
SWEP.Icon = "vgui/ttt/icon_tport"
|
|
end
|
|
|
|
SWEP.Base = "weapon_tttbase"
|
|
|
|
SWEP.ViewModel = "models/weapons/v_crowbar.mdl"
|
|
SWEP.WorldModel = "models/weapons/w_slam.mdl"
|
|
|
|
SWEP.Primary.ClipSize = 16
|
|
SWEP.Primary.DefaultClip = 16
|
|
SWEP.Primary.ClipMax = 16
|
|
SWEP.Primary.Automatic = false
|
|
SWEP.Primary.Ammo = "GaussEnergy"
|
|
SWEP.Primary.Delay = 0.5
|
|
|
|
SWEP.Secondary.Automatic = false
|
|
SWEP.Secondary.Ammo = "none"
|
|
SWEP.Secondary.Delay = 1.0
|
|
|
|
SWEP.Kind = WEAPON_EQUIP2
|
|
SWEP.CanBuy = {ROLE_TRAITOR, ROLE_DETECTIVE}
|
|
SWEP.WeaponID = AMMO_TELEPORT
|
|
|
|
SWEP.AllowDrop = true
|
|
SWEP.NoSights = true
|
|
|
|
local delay_beamup = 1
|
|
local delay_beamdown = 1
|
|
|
|
local ttt_telefrags = CreateConVar("ttt_teleport_telefrags", "1")
|
|
|
|
function SWEP:SetTeleportMark(pos, ang)
|
|
self.teleport = {pos = pos, ang = ang}
|
|
end
|
|
|
|
function SWEP:GetTeleportMark() return self.teleport end
|
|
|
|
function SWEP:PrimaryAttack()
|
|
self:SetNextPrimaryFire( CurTime() + self.Primary.Delay )
|
|
|
|
if self:Clip1() <= 0 then
|
|
self:DryFire(self.SetNextSecondaryFire)
|
|
return
|
|
end
|
|
|
|
-- Disallow initiating teleports during post, as it will occur across the
|
|
-- restart and allow the user an advantage during prep
|
|
if GetRoundState() == ROUND_POST then return end
|
|
|
|
if SERVER then
|
|
self:TeleportRecall()
|
|
else
|
|
surface.PlaySound("buttons/combine_button7.wav")
|
|
end
|
|
end
|
|
function SWEP:SecondaryAttack()
|
|
self:SetNextSecondaryFire( CurTime() + self.Secondary.Delay )
|
|
|
|
if SERVER then
|
|
self:TeleportStore()
|
|
else
|
|
surface.PlaySound("ui/buttonrollover.wav")
|
|
end
|
|
end
|
|
|
|
local zap = Sound("ambient/levels/labs/electric_explosion4.wav")
|
|
local unzap = Sound("ambient/levels/labs/electric_explosion2.wav")
|
|
|
|
local function Telefrag(victim, attacker, weapon)
|
|
if not IsValid(victim) then return end
|
|
|
|
local dmginfo = DamageInfo()
|
|
dmginfo:SetDamage(5000)
|
|
dmginfo:SetDamageType(DMG_SONIC)
|
|
dmginfo:SetAttacker(attacker)
|
|
dmginfo:SetInflictor(weapon)
|
|
dmginfo:SetDamageForce(Vector(0,0,10))
|
|
dmginfo:SetDamagePosition(attacker:GetPos())
|
|
|
|
victim:TakeDamageInfo(dmginfo)
|
|
end
|
|
|
|
|
|
local function ShouldCollide(ent)
|
|
local g = ent:GetCollisionGroup()
|
|
return (g != COLLISION_GROUP_WEAPON and
|
|
g != COLLISION_GROUP_DEBRIS and
|
|
g != COLLISION_GROUP_DEBRIS_TRIGGER and
|
|
g != COLLISION_GROUP_INTERACTIVE_DEBRIS)
|
|
end
|
|
|
|
-- Teleport a player to a {pos, ang}
|
|
local function TeleportPlayer(ply, teleport)
|
|
local oldpos = ply:GetPos()
|
|
local pos = teleport.pos
|
|
local ang = teleport.ang
|
|
|
|
-- print decal on destination
|
|
util.PaintDown(pos + Vector(0,0,25), "GlassBreak", ply)
|
|
|
|
-- perform teleport
|
|
ply:SetPos(pos)
|
|
ply:SetEyeAngles(ang) -- ineffective due to freeze...
|
|
|
|
timer.Simple(delay_beamdown, function ()
|
|
if IsValid(ply) then
|
|
ply:Freeze(false)
|
|
end
|
|
end)
|
|
|
|
sound.Play(zap, oldpos, 65, 100)
|
|
sound.Play(unzap, pos, 55, 100)
|
|
|
|
-- print decal on source now that we're gone, because else it will refuse
|
|
-- to draw for some reason
|
|
util.PaintDown(oldpos + Vector(0,0,25), "GlassBreak", ply)
|
|
end
|
|
|
|
-- Checks teleport destination. Returns bool and table, if bool is true then
|
|
-- location is blocked by world or prop. If table is non-nil it contains a list
|
|
-- of blocking players.
|
|
local function CanTeleportToPos(ply, pos)
|
|
-- first check if we can teleport here at all, because any solid object or
|
|
-- brush will make us stuck and therefore kills/blocks us instead, so the
|
|
-- trace checks for anything solid to players that isn't a player
|
|
local tr = nil
|
|
local tres = {start=pos, endpos=pos, mask=MASK_PLAYERSOLID, filter=player.GetAll()}
|
|
local collide = false
|
|
|
|
-- This thing is unnecessary if we can supply a collision group to trace
|
|
-- functions, like we can in source and sanity suggests we should be able
|
|
-- to do so, but I have not found a way to do so yet. Until then, re-trace
|
|
-- while extending our filter whenever we hit something we don't want to
|
|
-- hit (like weapons or ragdolls).
|
|
repeat
|
|
tr = util.TraceEntity(tres, ply)
|
|
|
|
if tr.HitWorld then
|
|
collide = true
|
|
elseif IsValid(tr.Entity) then
|
|
if ShouldCollide(tr.Entity) then
|
|
collide = true
|
|
else
|
|
table.insert(tres.filter, tr.Entity)
|
|
end
|
|
end
|
|
until (not tr.Hit) or collide
|
|
|
|
if collide then
|
|
--Telefrag(ply, ply)
|
|
return true, nil
|
|
else
|
|
|
|
-- find all players in the place where we will be and telefrag them
|
|
local blockers = ents.FindInBox(pos + Vector(-16, -16, 0),
|
|
pos + Vector(16, 16, 64))
|
|
|
|
local blocking_plys = {}
|
|
|
|
for _, block in ipairs(blockers) do
|
|
if IsValid(block) then
|
|
if block:IsPlayer() and block != ply then
|
|
if block:IsTerror() and block:Alive() then
|
|
table.insert(blocking_plys, block)
|
|
-- telefrag blocker
|
|
--Telefrag(block, ply)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return false, blocking_plys
|
|
end
|
|
|
|
return false, nil
|
|
end
|
|
|
|
local function DoTeleport(ply, teleport, weapon)
|
|
if IsValid(ply) and ply:IsTerror() and teleport then
|
|
local fail = false
|
|
|
|
local block_world, block_plys = CanTeleportToPos(ply, teleport.pos)
|
|
|
|
if block_world then
|
|
-- if blocked by prop/world, always fail
|
|
fail = true
|
|
elseif block_plys and #block_plys > 0 then
|
|
-- if blocked by player, maybe telefrag
|
|
if ttt_telefrags:GetBool() then
|
|
for _, p in ipairs(block_plys) do
|
|
Telefrag(p, ply, weapon)
|
|
end
|
|
else
|
|
fail = true
|
|
end
|
|
end
|
|
|
|
if not fail then
|
|
TeleportPlayer(ply, teleport)
|
|
else
|
|
ply:Freeze(false)
|
|
LANG.Msg(ply, "tele_failed")
|
|
end
|
|
elseif IsValid(ply) then
|
|
-- should never happen, but at least unfreeze
|
|
ply:Freeze(false)
|
|
LANG.Msg(ply, "tele_failed")
|
|
end
|
|
end
|
|
|
|
local function StartTeleport(ply, teleport, weapon)
|
|
if (not IsValid(ply)) or (not ply:IsTerror()) or (not teleport) then
|
|
return end
|
|
|
|
teleport.ang = ply:EyeAngles()
|
|
|
|
timer.Simple(delay_beamup, function() DoTeleport(ply, teleport, weapon) end)
|
|
|
|
local ang = ply:GetAngles()
|
|
|
|
local edata_up = EffectData()
|
|
edata_up:SetOrigin(ply:GetPos())
|
|
ang = Angle(0, ang.y, ang.r) -- deep copy
|
|
edata_up:SetAngles(ang)
|
|
edata_up:SetEntity(ply)
|
|
edata_up:SetMagnitude(delay_beamup)
|
|
edata_up:SetRadius(delay_beamdown)
|
|
|
|
util.Effect("teleport_beamup", edata_up)
|
|
|
|
local edata_dn = EffectData()
|
|
edata_dn:SetOrigin(teleport.pos)
|
|
ang = Angle(0, ang.y, ang.r) -- deep copy
|
|
edata_dn:SetAngles(ang)
|
|
edata_dn:SetEntity(ply)
|
|
edata_dn:SetMagnitude(delay_beamup)
|
|
edata_dn:SetRadius(delay_beamdown)
|
|
|
|
util.Effect("teleport_beamdown", edata_dn)
|
|
end
|
|
|
|
function SWEP:TeleportRecall()
|
|
local ply = self:GetOwner()
|
|
if IsValid(ply) and ply:IsTerror() then
|
|
local mark = self:GetTeleportMark()
|
|
if mark then
|
|
|
|
local g = ply:GetGroundEntity()
|
|
if g != game.GetWorld() and not IsValid(g) then
|
|
LANG.Msg(ply, "tele_no_ground")
|
|
return
|
|
end
|
|
|
|
if ply:Crouching() then
|
|
LANG.Msg(ply, "tele_no_crouch")
|
|
return
|
|
end
|
|
|
|
ply:Freeze(true)
|
|
|
|
self:TakePrimaryAmmo(1)
|
|
|
|
timer.Simple(0.2, function() StartTeleport(ply, mark, self) end)
|
|
else
|
|
LANG.Msg(ply, "tele_no_mark")
|
|
end
|
|
end
|
|
end
|
|
|
|
local function CanStoreTeleportPos(ply, pos)
|
|
local g = ply:GetGroundEntity()
|
|
if g != game.GetWorld() or (IsValid(g) and g:GetMoveType() != MOVETYPE_NONE) then
|
|
return false, "tele_no_mark_ground"
|
|
elseif ply:Crouching() then
|
|
return false, "tele_no_mark_crouch"
|
|
end
|
|
|
|
return true, nil
|
|
end
|
|
|
|
function SWEP:TeleportStore()
|
|
local ply = self:GetOwner()
|
|
if IsValid(ply) and ply:IsTerror() then
|
|
|
|
local allow, msg = CanStoreTeleportPos(ply, self:GetPos())
|
|
if not allow then
|
|
LANG.Msg(ply, msg)
|
|
return
|
|
end
|
|
|
|
self:SetTeleportMark(ply:GetPos(), ply:EyeAngles())
|
|
|
|
LANG.Msg(ply, "tele_marked")
|
|
end
|
|
end
|
|
|
|
|
|
|
|
function SWEP:Reload()
|
|
return false
|
|
end
|
|
|
|
|
|
if CLIENT then
|
|
function SWEP:Initialize()
|
|
self:AddHUDHelp("tele_help_pri", "tele_help_sec", true)
|
|
|
|
return self.BaseClass.Initialize(self)
|
|
end
|
|
end
|
|
|
|
function SWEP:Deploy()
|
|
if SERVER and IsValid(self:GetOwner()) then
|
|
self:GetOwner():DrawViewModel(false)
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function SWEP:ShootEffects() end
|