Add Comments with Specifications to Turrets and Dragger

- Make Plasma Bullets explode only once if they hit a character and a
  obstacle
- Make turrets fire speed independend from teams and solo players
- Make draggers keep dragging the same tee, also if a closer tee exist
This commit is contained in:
c0d3d3v 2022-05-09 13:56:06 +02:00
parent ab37f95bb4
commit 8fc34ae7b9
No known key found for this signature in database
GPG key ID: 068AF680530DFF31
8 changed files with 138 additions and 49 deletions

View file

@ -23,6 +23,10 @@ CDragger::CDragger(CGameWorld *pGameWorld, vec2 Pos, float Strength, bool Ignore
m_Number = Number;
m_EvalTick = Server()->Tick();
for(auto &TargetId : m_TargetIdInTeam)
{
TargetId = -1;
}
mem_zero(m_apDraggerBeam, sizeof(m_apDraggerBeam));
GameWorld()->InsertEntity(this);
}
@ -63,12 +67,14 @@ void CDragger::LookForPlayersToDrag()
(CEntity **)pPlayersInRange, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
// The closest player (within range) in a team is selected as the target
int TargetIdInTeam[MAX_CLIENTS];
int ClosestTargetIdInTeam[MAX_CLIENTS];
bool CanStillBeTeamTarget[MAX_CLIENTS];
bool IsTarget[MAX_CLIENTS];
int MinDistInTeam[MAX_CLIENTS];
mem_zero(CanStillBeTeamTarget, sizeof(CanStillBeTeamTarget));
mem_zero(MinDistInTeam, sizeof(MinDistInTeam));
mem_zero(IsTarget, sizeof(IsTarget));
for(int &TargetId : TargetIdInTeam)
for(int &TargetId : ClosestTargetIdInTeam)
{
TargetId = -1;
}
@ -76,14 +82,16 @@ void CDragger::LookForPlayersToDrag()
for(int i = 0; i < NumPlayersInRange; i++)
{
CCharacter *pTarget = pPlayersInRange[i];
const int &TargetTeam = pTarget->Team();
// Do not create a dragger beam for super player
if(pTarget->Team() == TEAM_SUPER)
if(TargetTeam == TEAM_SUPER)
{
continue;
}
// If the dragger is disabled for the target's team, no dragger beam will be generated
if(m_Layer == LAYER_SWITCH && m_Number > 0 &&
!GameServer()->Collision()->m_pSwitchers[m_Number].m_Status[pTarget->Team()])
!GameServer()->Collision()->m_pSwitchers[m_Number].m_Status[TargetTeam])
{
continue;
}
@ -95,29 +103,35 @@ void CDragger::LookForPlayersToDrag()
!GameServer()->Collision()->IntersectNoLaser(m_Pos, pTarget->m_Pos, 0, 0);
if(IsReachable && pTarget->IsAlive())
{
const int &TargetClientId = pTarget->GetPlayer()->GetCID();
// Solo players are dragged independently from the rest of the team
if(pTarget->Teams()->m_Core.GetSolo(pTarget->GetPlayer()->GetCID()))
if(pTarget->Teams()->m_Core.GetSolo(TargetClientId))
{
IsTarget[pTarget->GetPlayer()->GetCID()] = true;
IsTarget[TargetClientId] = true;
}
else
{
int Distance = distance(pTarget->m_Pos, m_Pos);
if(MinDistInTeam[pTarget->Team()] == 0 || MinDistInTeam[pTarget->Team()] > Distance)
if(MinDistInTeam[TargetTeam] == 0 || MinDistInTeam[TargetTeam] > Distance)
{
MinDistInTeam[pTarget->Team()] = Distance;
TargetIdInTeam[pTarget->Team()] = pTarget->GetPlayer()->GetCID();
MinDistInTeam[TargetTeam] = Distance;
ClosestTargetIdInTeam[TargetTeam] = TargetClientId;
}
CanStillBeTeamTarget[TargetClientId] = true;
}
}
}
// Set the closest player for each team as a target
for(int &TargetId : TargetIdInTeam)
// Set the closest player for each team as a target if the team does not have a target player yet
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(TargetId != -1)
if((m_TargetIdInTeam[i] != -1 && !CanStillBeTeamTarget[m_TargetIdInTeam[i]]) || m_TargetIdInTeam[i] == -1)
{
IsTarget[TargetId] = true;
m_TargetIdInTeam[i] = ClosestTargetIdInTeam[i];
}
if(m_TargetIdInTeam[i] != -1)
{
IsTarget[m_TargetIdInTeam[i]] = true;
}
}

View file

@ -5,17 +5,33 @@
#include <game/server/entity.h>
class CDraggerBeam;
/**
* Draggers generate dragger beams which pull players towards their center similar to a tractor beam
*
* A dragger will only generate one dragger beam per team for the closest player for whom the following criteria are met:
* - The player is within the dragger range (m_SvDraggerRange).
* - The player is not a super player
* - The dragger is activated
* - The dragger beam to be generated is not blocked by laser stoppers (or solid blocks if IgnoreWalls is set to false)
* With the exception of solo players, for whom a dragger beam is always generated, regardless of the rest of the team,
* if the above criteria are met. Solo players have no influence on the generation of the dragger beam for the rest
* of the team.
* A created dragger beam remains for the selected player until one of the criteria is no longer fulfilled. Only then
* can a new dragger beam be created for that team, which may drag another team partner.
*/
class CDragger : public CEntity
{
// m_Core is the direction vector by which a dragger is shifted at each movement tick (every 150ms)
vec2 m_Core;
float m_Strength;
int m_EvalTick;
void LookForPlayersToDrag();
bool m_IgnoreWalls;
int m_EvalTick;
int m_TargetIdInTeam[MAX_CLIENTS];
CDraggerBeam *m_apDraggerBeam[MAX_CLIENTS];
void LookForPlayersToDrag();
public:
CDragger(CGameWorld *pGameWorld, vec2 Pos, float Strength, bool IgnoreWalls, int Layer = 0, int Number = 0);

View file

@ -52,6 +52,7 @@ void CDraggerBeam::Tick()
Reset();
return;
}
// In the center of the dragger a tee does not experience speed-up
else if(distance(pTarget->m_Pos, m_Pos) > 28)
{
vec2 Temp = pTarget->Core()->m_Vel + (normalize(m_Pos - pTarget->m_Pos) * m_Strength);

View file

@ -5,6 +5,20 @@
#include "dragger.h"
#include <game/server/entity.h>
/**
* Dragger beams pull a selected player towards their center
*
* Dragger beams are generated by a particular dragger for the player closest to it and for whom certain criteria are
* met. Dragger beams exist until these criteria are no longer met. Dragger beams dissolve and automatically
* de-register from their dragger source as soon as the player for whom they were created:
* - is no longer alive
* - is no longer in range (m_SvDraggerRange)
* - can no longer be dragged because the beam is intercepted by a laser stopper (or if !IgnoreWalls by solid blocks)
*
* Dragger beams accelerate the selected player every tick towards their center. The length of the speed vector, which
* is added to that of the player, depends only on the strength of the dragger and is between 1 and 3 units long. If
* the player is in the center of the dragger, it will not accelerate.
*/
class CDraggerBeam : public CEntity
{
CDragger *m_pDragger;

View file

@ -19,9 +19,10 @@ CGun::CGun(CGameWorld *pGameWorld, vec2 Pos, bool Freeze, bool Explosive, int La
m_Explosive = Explosive;
m_Layer = Layer;
m_Number = Number;
m_LastFire = Server()->Tick();
m_EvalTick = Server()->Tick();
mem_zero(m_LastFireTeam, sizeof(m_LastFireTeam));
mem_zero(m_LastFireSolo, sizeof(m_LastFireSolo));
GameWorld()->InsertEntity(this);
}
@ -38,9 +39,10 @@ void CGun::Tick()
}
m_Pos += m_Core;
}
if(g_Config.m_SvPlasmaPerSec > 0 &&
m_LastFire + Server()->TickSpeed() / g_Config.m_SvPlasmaPerSec <= Server()->Tick())
if(g_Config.m_SvPlasmaPerSec != 0)
{
Fire();
}
}
void CGun::Fire()
@ -66,14 +68,26 @@ void CGun::Fire()
for(int i = 0; i < NumPlayersInRange; i++)
{
CCharacter *pTarget = pPlayersInRange[i];
const int &TargetTeam = pTarget->Team();
// Do not fire at super players
if(pTarget->Team() == TEAM_SUPER)
if(TargetTeam == TEAM_SUPER)
{
continue;
}
// If the turret is disabled for the target's team, the turret will not fire
if(m_Layer == LAYER_SWITCH && m_Number > 0 &&
!GameServer()->Collision()->m_pSwitchers[m_Number].m_Status[pTarget->Team()])
!GameServer()->Collision()->m_pSwitchers[m_Number].m_Status[TargetTeam])
{
continue;
}
// Turrets can only shoot at a speed of m_SvPlasmaPerSec
const int &TargetClientId = pTarget->GetPlayer()->GetCID();
const bool &TargetIsSolo = pTarget->Teams()->m_Core.GetSolo(TargetClientId);
if((TargetIsSolo &&
m_LastFireSolo[TargetClientId] + Server()->TickSpeed() / g_Config.m_SvPlasmaPerSec > Server()->Tick()) ||
(!TargetIsSolo &&
m_LastFireTeam[TargetTeam] + Server()->TickSpeed() / g_Config.m_SvPlasmaPerSec > Server()->Tick()))
{
continue;
}
@ -83,28 +97,30 @@ void CGun::Fire()
if(IsReachable && pTarget->IsAlive())
{
// Turrets fire on solo players regardless of the rest of the team
if(pTarget->Teams()->m_Core.GetSolo(pTarget->GetPlayer()->GetCID()))
if(TargetIsSolo)
{
IsTarget[pTarget->GetPlayer()->GetCID()] = true;
IsTarget[TargetClientId] = true;
m_LastFireSolo[TargetClientId] = Server()->Tick();
}
else
{
int Distance = distance(pTarget->m_Pos, m_Pos);
if(MinDistInTeam[pTarget->Team()] == 0 || MinDistInTeam[pTarget->Team()] > Distance)
if(MinDistInTeam[TargetTeam] == 0 || MinDistInTeam[TargetTeam] > Distance)
{
MinDistInTeam[pTarget->Team()] = Distance;
TargetIdInTeam[pTarget->Team()] = pTarget->GetPlayer()->GetCID();
MinDistInTeam[TargetTeam] = Distance;
TargetIdInTeam[TargetTeam] = TargetClientId;
}
}
}
}
// Set the closest player for each team as a target
for(int &TargetId : TargetIdInTeam)
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(TargetId != -1)
if(TargetIdInTeam[i] != -1)
{
IsTarget[TargetId] = true;
IsTarget[TargetIdInTeam[i]] = true;
m_LastFireTeam[i] = Server()->Tick();
}
}
@ -115,7 +131,6 @@ void CGun::Fire()
{
CCharacter *pTarget = GameServer()->GetPlayerChar(i);
new CPlasma(&GameServer()->m_World, m_Pos, normalize(pTarget->m_Pos - m_Pos), m_Freeze, m_Explosive, i);
m_LastFire = Server()->Tick();
}
}
}

View file

@ -6,16 +6,30 @@
#include <game/gamecore.h>
#include <game/server/entity.h>
/**
* Turrets (also referred to as Gun) fire plasma bullets at the nearest player
*
* A turret fires plasma bullets with a certain firing rate (m_SvPlasmaPerSec) at the closest player of a team for whom
* the following criteria are met:
* - The player is within the turret range (m_SvPlasmaRange)
* - The player is not a super player
* - The turret is activated
* - The initial trajectory of the plasma bullet to be generated would not be stopped by any solid block
* With the exception of solo players, for whom plasma bullets will always be fired, regardless of the rest of the team,
* if the above criteria are met. Solo players do not affect the generation of plasma bullets for the rest of the team.
* The shooting rate of m_SvPlasmaPerSec is independent for each team and solo player and starts with the first tick
* when a target player is selected.
*/
class CGun : public CEntity
{
int m_EvalTick;
vec2 m_Core;
bool m_Freeze;
bool m_Explosive;
int m_EvalTick;
int m_LastFireTeam[MAX_CLIENTS];
int m_LastFireSolo[MAX_CLIENTS];
void Fire();
int m_LastFire;
public:
CGun(CGameWorld *pGameWorld, vec2 Pos, bool Freeze, bool Explosive, int Layer = 0, int Number = 0);

View file

@ -29,35 +29,35 @@ CPlasma::CPlasma(CGameWorld *pGameWorld, vec2 Pos, vec2 Dir, bool Freeze,
void CPlasma::Tick()
{
// A plasma ball has only a limited lifetime
// A plasma bullet has only a limited lifetime
if(m_LifeTime == 0)
{
Reset();
return;
}
CCharacter *pTarget = GameServer()->GetPlayerChar(m_ForClientID);
// Without a target, a plasma ball has no reason to live
// Without a target, a plasma bullet has no reason to live
if(!pTarget)
{
// This can allow you to make plasma balls disappear by disconnecting, but this is not a serious cheat
Reset();
return;
}
m_LifeTime--;
Move();
HitCharacter(pTarget);
// Check if the plasma ball is stopped by a solid block or a laser stopper
int HasIntersection = GameServer()->Collision()->IntersectNoLaser(m_Pos, m_Pos + m_Core, 0, 0);
if(HasIntersection)
if(!HitCharacter(pTarget))
{
if(m_Explosive)
// Check if the plasma bullet is stopped by a solid block or a laser stopper
int HasIntersection = GameServer()->Collision()->IntersectNoLaser(m_Pos, m_Pos + m_Core, 0, 0);
if(HasIntersection)
{
// Even in the case of an explosion due to a collision with obstacles, only one player is affected
GameServer()->CreateExplosion(
m_Pos, m_ForClientID, WEAPON_GRENADE, true, pTarget->Team(), pTarget->TeamMask());
if(m_Explosive)
{
// Even in the case of an explosion due to a collision with obstacles, only one player is affected
GameServer()->CreateExplosion(
m_Pos, m_ForClientID, WEAPON_GRENADE, true, pTarget->Team(), pTarget->TeamMask());
}
Reset();
}
Reset();
}
}
@ -77,7 +77,7 @@ bool CPlasma::HitCharacter(CCharacter *pTarget)
return false;
}
// Super player should not be able to stop the plasma balls
// Super player should not be able to stop the plasma bullets
if(HitPlayer->Team() == TEAM_SUPER)
{
return false;
@ -91,7 +91,7 @@ bool CPlasma::HitCharacter(CCharacter *pTarget)
GameServer()->CreateExplosion(
m_Pos, m_ForClientID, WEAPON_GRENADE, true, pTarget->Team(), pTarget->TeamMask());
}
m_MarkedForDestroy = true;
Reset();
return true;
}
@ -102,14 +102,14 @@ void CPlasma::Reset()
void CPlasma::Snap(int SnappingClient)
{
// Only players who can see the targeted player can see the plasma ball
// Only players who can see the targeted player can see the plasma bullet
CCharacter *pTarget = GameServer()->GetPlayerChar(m_ForClientID);
if(!pTarget->CanSnapCharacter(SnappingClient))
{
return;
}
// Only players with the plasma ball in their field of view or who want to see everything will receive the snap
// Only players with the plasma bullet in their field of view or who want to see everything will receive the snap
if(NetworkClipped(SnappingClient))
return;

View file

@ -4,6 +4,21 @@
#include <game/server/entity.h>
/**
* Plasma Bullets are projectiles fired from turrets at a specific target
*
* When hitting a tee, plasma bullets can either freeze or unfreeze the player
* Also, plasma projectiles can explode on impact. However, the player affected by the explosion is not necessarily the
* one the plasma collided with, but if the affected player is not a solo player, then the team-mate with the lowest
* ClientId within the explosion range. Furthermore, the affected player does not feel the explosion at the point of
* impact but at the last position of the plasma bullet. The same applies if a plasma bullet explodes due to a collision
* with a laser stopper or a solid block
* Plasma bullets move every tick in the assigned direction and then accelerate by the factor PLASMA_ACCEL
* Plasma bullets will stop existing as soon as:
* - The player they were created for do no longer exist
* - They have had a collision with a player, a solid block or a laser stopper
* - Their life time of 1.5 seconds has expired
*/
class CPlasma : public CEntity
{
vec2 m_Core;