2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2020-09-26 19:41:58 +00:00
|
|
|
#include "laser.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/generated/protocol.h>
|
|
|
|
#include <game/server/gamecontext.h>
|
2013-07-18 23:06:48 +00:00
|
|
|
#include <game/server/gamemodes/DDRace.h>
|
2008-08-14 18:25:44 +00:00
|
|
|
|
2010-07-29 05:21:18 +00:00
|
|
|
#include <engine/shared/config.h>
|
2011-01-29 00:59:50 +00:00
|
|
|
#include <game/server/teams.h>
|
2008-08-14 18:25:44 +00:00
|
|
|
|
2021-01-09 14:18:52 +00:00
|
|
|
#include "character.h"
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
CLaser::CLaser(CGameWorld *pGameWorld, vec2 Pos, vec2 Direction, float StartEnergy, int Owner, int Type) :
|
|
|
|
CEntity(pGameWorld, CGameWorld::ENTTYPE_LASER)
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Pos = Pos;
|
|
|
|
m_Owner = Owner;
|
|
|
|
m_Energy = StartEnergy;
|
|
|
|
m_Dir = Direction;
|
|
|
|
m_Bounces = 0;
|
|
|
|
m_EvalTick = 0;
|
2020-09-26 19:41:58 +00:00
|
|
|
m_TelePos = vec2(0, 0);
|
2013-07-20 12:16:41 +00:00
|
|
|
m_WasTele = false;
|
2011-01-07 18:37:21 +00:00
|
|
|
m_Type = Type;
|
2018-02-14 15:27:26 +00:00
|
|
|
m_TeleportCancelled = false;
|
2018-11-02 23:02:20 +00:00
|
|
|
m_IsBlueTeleport = false;
|
2014-04-14 20:15:48 +00:00
|
|
|
m_TuneZone = GameServer()->Collision()->IsTune(GameServer()->Collision()->GetMapIndex(m_Pos));
|
2022-02-11 09:56:34 +00:00
|
|
|
CCharacter *pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
|
|
|
m_TeamMask = pOwnerChar ? pOwnerChar->Teams()->TeamMask(pOwnerChar->Team(), -1, m_Owner) : 0;
|
|
|
|
m_BelongsToPracticeTeam = pOwnerChar && pOwnerChar->Teams()->IsPractice(pOwnerChar->Team());
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
GameWorld()->InsertEntity(this);
|
|
|
|
DoBounce();
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
bool CLaser::HitCharacter(vec2 From, vec2 To)
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 At;
|
2011-03-19 20:21:42 +00:00
|
|
|
CCharacter *pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
|
|
|
CCharacter *pHit;
|
2013-07-20 12:16:41 +00:00
|
|
|
bool pDontHitSelf = g_Config.m_SvOldLaser || (m_Bounces == 0 && !m_WasTele);
|
2011-03-19 20:21:42 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(pOwnerChar ? (!(pOwnerChar->m_Hit & CCharacter::DISABLE_HIT_LASER) && m_Type == WEAPON_LASER) || (!(pOwnerChar->m_Hit & CCharacter::DISABLE_HIT_SHOTGUN) && m_Type == WEAPON_SHOTGUN) : g_Config.m_SvHit)
|
2013-07-20 12:06:56 +00:00
|
|
|
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner);
|
2011-03-19 20:21:42 +00:00
|
|
|
else
|
2013-07-20 12:06:56 +00:00
|
|
|
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar);
|
2011-03-19 20:21:42 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!pHit || (pHit == pOwnerChar && g_Config.m_SvOldLaser) || (pHit != pOwnerChar && pOwnerChar ? (pOwnerChar->m_Hit & CCharacter::DISABLE_HIT_LASER && m_Type == WEAPON_LASER) || (pOwnerChar->m_Hit & CCharacter::DISABLE_HIT_SHOTGUN && m_Type == WEAPON_SHOTGUN) : !g_Config.m_SvHit))
|
2008-08-14 18:25:44 +00:00
|
|
|
return false;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_From = From;
|
|
|
|
m_Pos = At;
|
2010-07-29 05:21:18 +00:00
|
|
|
m_Energy = -1;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_Type == WEAPON_SHOTGUN)
|
2010-07-29 05:21:18 +00:00
|
|
|
{
|
2010-12-01 22:06:28 +00:00
|
|
|
vec2 Temp;
|
2014-04-13 14:41:02 +00:00
|
|
|
|
|
|
|
float Strength;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!m_TuneZone)
|
2014-04-13 14:41:02 +00:00
|
|
|
Strength = GameServer()->Tuning()->m_ShotgunStrength;
|
|
|
|
else
|
2014-04-13 14:49:58 +00:00
|
|
|
Strength = GameServer()->TuningList()[m_TuneZone].m_ShotgunStrength;
|
2014-04-13 14:41:02 +00:00
|
|
|
|
2010-12-01 22:06:28 +00:00
|
|
|
if(!g_Config.m_SvOldLaser)
|
2014-04-13 14:41:02 +00:00
|
|
|
Temp = pHit->Core()->m_Vel + normalize(m_PrevPos - pHit->Core()->m_Pos) * Strength;
|
2016-08-07 20:38:45 +00:00
|
|
|
else if(pOwnerChar)
|
2014-04-13 14:41:02 +00:00
|
|
|
Temp = pHit->Core()->m_Vel + normalize(pOwnerChar->Core()->m_Pos - pHit->Core()->m_Pos) * Strength;
|
2016-08-07 20:38:45 +00:00
|
|
|
else
|
|
|
|
Temp = pHit->Core()->m_Vel;
|
2018-08-15 15:47:07 +00:00
|
|
|
pHit->Core()->m_Vel = ClampVel(pHit->m_MoveRestrictions, Temp);
|
2010-08-27 23:30:50 +00:00
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
else if(m_Type == WEAPON_LASER)
|
2010-07-29 05:21:18 +00:00
|
|
|
{
|
2011-07-22 14:23:03 +00:00
|
|
|
pHit->UnFreeze();
|
2010-07-29 05:21:18 +00:00
|
|
|
}
|
2008-08-14 18:25:44 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLaser::DoBounce()
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_EvalTick = Server()->Tick();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_Energy < 0)
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2021-05-22 18:02:00 +00:00
|
|
|
m_MarkedForDestroy = true;
|
2008-08-14 18:25:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2010-07-29 05:21:18 +00:00
|
|
|
m_PrevPos = m_Pos;
|
|
|
|
vec2 Coltile;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-04 10:16:30 +00:00
|
|
|
int Res;
|
2013-07-18 23:06:48 +00:00
|
|
|
int z;
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_WasTele)
|
2013-07-18 23:06:48 +00:00
|
|
|
{
|
2013-07-19 00:04:40 +00:00
|
|
|
m_PrevPos = m_TelePos;
|
2013-07-18 23:06:48 +00:00
|
|
|
m_Pos = m_TelePos;
|
2020-09-26 19:41:58 +00:00
|
|
|
m_TelePos = vec2(0, 0);
|
2013-07-18 23:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
vec2 To = m_Pos + m_Dir * m_Energy;
|
|
|
|
|
2015-11-08 09:20:44 +00:00
|
|
|
Res = GameServer()->Collision()->IntersectLineTeleWeapon(m_Pos, To, &Coltile, &To, &z);
|
2011-04-09 06:41:31 +00:00
|
|
|
|
2011-03-04 10:16:30 +00:00
|
|
|
if(Res)
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!HitCharacter(m_Pos, To))
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
|
|
|
// intersected
|
2010-05-29 07:25:38 +00:00
|
|
|
m_From = m_Pos;
|
|
|
|
m_Pos = To;
|
2009-01-11 10:26:17 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
vec2 TempPos = m_Pos;
|
|
|
|
vec2 TempDir = m_Dir * 4.0f;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-09-01 00:14:05 +00:00
|
|
|
int f = 0;
|
2011-03-04 10:16:30 +00:00
|
|
|
if(Res == -1)
|
|
|
|
{
|
2014-05-12 21:55:35 +00:00
|
|
|
f = GameServer()->Collision()->GetTile(round_to_int(Coltile.x), round_to_int(Coltile.y));
|
2015-11-08 09:20:10 +00:00
|
|
|
GameServer()->Collision()->SetCollisionAt(round_to_int(Coltile.x), round_to_int(Coltile.y), TILE_SOLID);
|
2010-07-29 05:21:18 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
GameServer()->Collision()->MovePoint(&TempPos, &TempDir, 1.0f, 0);
|
2011-03-04 10:16:30 +00:00
|
|
|
if(Res == -1)
|
|
|
|
{
|
2014-05-12 21:55:35 +00:00
|
|
|
GameServer()->Collision()->SetCollisionAt(round_to_int(Coltile.x), round_to_int(Coltile.y), f);
|
2010-07-29 05:21:18 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Pos = TempPos;
|
|
|
|
m_Dir = normalize(TempDir);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(!m_TuneZone)
|
2014-03-12 23:54:44 +00:00
|
|
|
m_Energy -= distance(m_From, m_Pos) + GameServer()->Tuning()->m_LaserBounceCost;
|
|
|
|
else
|
2014-04-13 14:49:58 +00:00
|
|
|
m_Energy -= distance(m_From, m_Pos) + GameServer()->TuningList()[m_TuneZone].m_LaserBounceCost;
|
2013-07-18 23:06:48 +00:00
|
|
|
|
2020-05-25 13:08:24 +00:00
|
|
|
CGameControllerDDRace *pControllerDDRace = (CGameControllerDDRace *)GameServer()->m_pController;
|
2022-01-22 12:54:25 +00:00
|
|
|
if(Res == TILE_TELEINWEAPON && !pControllerDDRace->m_TeleOuts[z - 1].empty())
|
2013-07-18 23:06:48 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
int TeleOut = GameServer()->m_World.m_Core.RandomOr0(pControllerDDRace->m_TeleOuts[z - 1].size());
|
|
|
|
m_TelePos = pControllerDDRace->m_TeleOuts[z - 1][TeleOut];
|
2013-07-20 12:16:41 +00:00
|
|
|
m_WasTele = true;
|
2013-07-18 23:06:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Bounces++;
|
2013-07-20 12:16:41 +00:00
|
|
|
m_WasTele = false;
|
2013-07-18 23:06:48 +00:00
|
|
|
}
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2014-03-12 23:54:44 +00:00
|
|
|
int BounceNum = GameServer()->Tuning()->m_LaserBounceNum;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_TuneZone)
|
2014-04-13 14:49:58 +00:00
|
|
|
BounceNum = GameServer()->TuningList()[m_TuneZone].m_LaserBounceNum;
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2014-03-12 23:54:44 +00:00
|
|
|
if(m_Bounces > BounceNum)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Energy = -1;
|
2011-07-22 12:58:06 +00:00
|
|
|
|
2019-11-22 14:37:18 +00:00
|
|
|
GameServer()->CreateSound(m_Pos, SOUND_LASER_BOUNCE, m_TeamMask);
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!HitCharacter(m_Pos, To))
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_From = m_Pos;
|
|
|
|
m_Pos = To;
|
|
|
|
m_Energy = -1;
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
|
|
|
}
|
2018-02-14 15:27:26 +00:00
|
|
|
|
2018-07-15 22:43:54 +00:00
|
|
|
CCharacter *pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
2020-11-20 11:14:04 +00:00
|
|
|
if(m_Owner >= 0 && m_Energy <= 0 && !m_TeleportCancelled && pOwnerChar &&
|
2019-11-22 14:37:18 +00:00
|
|
|
pOwnerChar->IsAlive() && pOwnerChar->HasTelegunLaser() && m_Type == WEAPON_LASER)
|
2018-02-14 15:27:26 +00:00
|
|
|
{
|
2018-07-15 22:43:54 +00:00
|
|
|
vec2 PossiblePos;
|
|
|
|
bool Found = false;
|
|
|
|
|
|
|
|
// Check if the laser hits a player.
|
|
|
|
bool pDontHitSelf = g_Config.m_SvOldLaser || (m_Bounces == 0 && !m_WasTele);
|
|
|
|
vec2 At;
|
|
|
|
CCharacter *pHit;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(pOwnerChar ? (!(pOwnerChar->m_Hit & CCharacter::DISABLE_HIT_LASER) && m_Type == WEAPON_LASER) : g_Config.m_SvHit)
|
2018-07-15 22:43:54 +00:00
|
|
|
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner);
|
|
|
|
else
|
|
|
|
pHit = GameServer()->m_World.IntersectCharacter(m_Pos, To, 0.f, At, pDontHitSelf ? pOwnerChar : 0, m_Owner, pOwnerChar);
|
2018-02-14 15:27:26 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(pHit)
|
2018-07-15 22:43:54 +00:00
|
|
|
Found = GetNearestAirPosPlayer(pHit->m_Pos, &PossiblePos);
|
|
|
|
else
|
|
|
|
Found = GetNearestAirPos(m_Pos, m_From, &PossiblePos);
|
2018-02-14 15:27:26 +00:00
|
|
|
|
2020-11-20 11:14:04 +00:00
|
|
|
if(Found)
|
2018-07-15 22:43:54 +00:00
|
|
|
{
|
|
|
|
pOwnerChar->m_TeleGunPos = PossiblePos;
|
|
|
|
pOwnerChar->m_TeleGunTeleport = true;
|
2018-11-02 23:02:20 +00:00
|
|
|
pOwnerChar->m_IsBlueTeleGunTeleport = m_IsBlueTeleport;
|
2018-02-14 15:27:26 +00:00
|
|
|
}
|
|
|
|
}
|
2020-11-20 11:14:04 +00:00
|
|
|
else if(m_Owner >= 0)
|
2018-02-14 15:27:26 +00:00
|
|
|
{
|
2018-07-15 22:43:54 +00:00
|
|
|
int MapIndex = GameServer()->Collision()->GetPureMapIndex(Coltile);
|
2018-02-14 15:27:26 +00:00
|
|
|
int TileFIndex = GameServer()->Collision()->GetFTileIndex(MapIndex);
|
2021-12-19 11:05:51 +00:00
|
|
|
bool IsSwitchTeleGun = GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_ALLOW_TELE_GUN;
|
|
|
|
bool IsBlueSwitchTeleGun = GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_ALLOW_BLUE_TELE_GUN;
|
2018-11-10 19:47:11 +00:00
|
|
|
int IsTeleInWeapon = GameServer()->Collision()->IsTeleportWeapon(MapIndex);
|
2018-02-14 15:27:26 +00:00
|
|
|
|
2018-11-10 19:47:11 +00:00
|
|
|
if(!IsTeleInWeapon)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(IsSwitchTeleGun || IsBlueSwitchTeleGun)
|
|
|
|
{
|
2018-11-10 19:47:11 +00:00
|
|
|
// Delay specifies which weapon the tile should work for.
|
|
|
|
// Delay = 0 means all.
|
|
|
|
int delay = GameServer()->Collision()->GetSwitchDelay(MapIndex);
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if((delay != 3 && delay != 0) && m_Type == WEAPON_LASER)
|
|
|
|
{
|
2018-11-10 19:47:11 +00:00
|
|
|
IsSwitchTeleGun = IsBlueSwitchTeleGun = false;
|
|
|
|
}
|
2018-11-02 23:02:20 +00:00
|
|
|
}
|
2018-10-26 15:05:21 +00:00
|
|
|
|
2018-11-10 19:47:11 +00:00
|
|
|
m_IsBlueTeleport = TileFIndex == TILE_ALLOW_BLUE_TELE_GUN || IsBlueSwitchTeleGun;
|
2018-11-02 23:02:20 +00:00
|
|
|
|
2018-11-10 19:47:11 +00:00
|
|
|
// Teleport is canceled if the last bounce tile is not a TILE_ALLOW_TELE_GUN.
|
|
|
|
// Teleport also works if laser didn't bounce.
|
|
|
|
m_TeleportCancelled =
|
2020-09-26 19:41:58 +00:00
|
|
|
m_Type == WEAPON_LASER && (TileFIndex != TILE_ALLOW_TELE_GUN && TileFIndex != TILE_ALLOW_BLUE_TELE_GUN && !IsSwitchTeleGun && !IsBlueSwitchTeleGun);
|
2018-11-10 19:47:11 +00:00
|
|
|
}
|
2018-02-14 15:27:26 +00:00
|
|
|
}
|
|
|
|
|
2010-09-08 16:22:11 +00:00
|
|
|
//m_Owner = -1;
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLaser::Reset()
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2021-05-22 18:02:00 +00:00
|
|
|
m_MarkedForDestroy = true;
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLaser::Tick()
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2022-02-11 09:56:34 +00:00
|
|
|
if((g_Config.m_SvDestroyLasersOnDeath || m_BelongsToPracticeTeam) && m_Owner >= 0)
|
2019-04-21 18:17:41 +00:00
|
|
|
{
|
|
|
|
CCharacter *pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
|
|
|
if(!(pOwnerChar && pOwnerChar->IsAlive()))
|
|
|
|
{
|
|
|
|
Reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-15 16:48:25 +00:00
|
|
|
float Delay;
|
2020-09-26 19:41:58 +00:00
|
|
|
if(m_TuneZone)
|
2014-04-13 14:49:58 +00:00
|
|
|
Delay = GameServer()->TuningList()[m_TuneZone].m_LaserBounceDelay;
|
2014-03-12 23:54:44 +00:00
|
|
|
else
|
2014-03-15 16:48:25 +00:00
|
|
|
Delay = GameServer()->Tuning()->m_LaserBounceDelay;
|
2015-07-09 00:08:14 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if((Server()->Tick() - m_EvalTick) > (Server()->TickSpeed() * Delay / 1000.0f))
|
2015-07-09 00:08:14 +00:00
|
|
|
DoBounce();
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
|
|
|
|
2012-01-09 23:49:31 +00:00
|
|
|
void CLaser::TickPaused()
|
|
|
|
{
|
|
|
|
++m_EvalTick;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLaser::Snap(int SnappingClient)
|
2008-08-14 18:25:44 +00:00
|
|
|
{
|
2015-10-30 18:55:51 +00:00
|
|
|
if(NetworkClipped(SnappingClient) && NetworkClipped(SnappingClient, m_From))
|
2008-08-14 18:25:44 +00:00
|
|
|
return;
|
2020-09-26 19:41:58 +00:00
|
|
|
CCharacter *OwnerChar = 0;
|
2010-12-04 21:51:03 +00:00
|
|
|
if(m_Owner >= 0)
|
2010-12-04 16:35:41 +00:00
|
|
|
OwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
2011-04-19 13:15:21 +00:00
|
|
|
if(!OwnerChar)
|
2010-12-04 16:51:14 +00:00
|
|
|
return;
|
2014-01-12 14:48:53 +00:00
|
|
|
|
|
|
|
CCharacter *pOwnerChar = 0;
|
2021-06-23 05:05:49 +00:00
|
|
|
int64_t TeamMask = -1LL;
|
2014-01-12 14:48:53 +00:00
|
|
|
|
|
|
|
if(m_Owner >= 0)
|
|
|
|
pOwnerChar = GameServer()->GetPlayerChar(m_Owner);
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(pOwnerChar && pOwnerChar->IsAlive())
|
|
|
|
TeamMask = pOwnerChar->Teams()->TeamMask(pOwnerChar->Team(), -1, m_Owner);
|
2014-01-12 14:48:53 +00:00
|
|
|
|
2022-03-04 20:23:32 +00:00
|
|
|
if(SnappingClient != SERVER_DEMO_CLIENT && !CmaskIsSet(TeamMask, SnappingClient))
|
2010-12-04 16:35:41 +00:00
|
|
|
return;
|
2021-01-09 20:40:17 +00:00
|
|
|
CNetObj_Laser *pObj = static_cast<CNetObj_Laser *>(Server()->SnapNewItem(NETOBJTYPE_LASER, GetID(), sizeof(CNetObj_Laser)));
|
2010-12-16 02:29:08 +00:00
|
|
|
if(!pObj)
|
|
|
|
return;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
pObj->m_X = (int)m_Pos.x;
|
|
|
|
pObj->m_Y = (int)m_Pos.y;
|
|
|
|
pObj->m_FromX = (int)m_From.x;
|
|
|
|
pObj->m_FromY = (int)m_From.y;
|
|
|
|
pObj->m_StartTick = m_EvalTick;
|
2008-08-14 18:25:44 +00:00
|
|
|
}
|
2021-12-14 09:35:00 +00:00
|
|
|
|
|
|
|
void CLaser::SwapClients(int Client1, int Client2)
|
|
|
|
{
|
|
|
|
m_Owner = m_Owner == Client1 ? Client2 : m_Owner == Client2 ? Client1 : m_Owner;
|
|
|
|
}
|