ddnet/src/game/server/entities/pickup.cpp
bors[bot] e9d08a15fd
Merge #6560
6560: Replace EntityEx with new netobjs r=edg-l a=trml

This is a proposal for replacing EntityEx with new netobjects, like suggested in #5860.
- Adds a new DDNetPickup that includes switch number
- a new DDNetProjectile that replaces the old one (which is renamed to DDRaceProjectile)
  - includes switch number, tunezone and velocity/speed (plus a flag that can be used to send velocitiy of player projectiles with full precision)
- switch number and subtype is added to DDNetLaser (to distinguish e.g. draggers with different strength)

The pr removes EntityEx from the server, but keeps compatibility in the client.

<!-- What is the motivation for the changes of this pull request? -->

<!-- Note that builds and other checks will be run for your change. Don't feel intimidated by failures in some of the checks. If you can't resolve them yourself, experienced devs can also resolve them before merging your pull request. -->

## Checklist

- [ ] Tested the change ingame
- [ ] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test (especially base/) or added coverage to integration test
- [ ] Considered possible null pointers and out of bounds array indexing
- [ ] Changed no physics that affect existing maps
- [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional)


Co-authored-by: trml <trml@users.noreply.github.com>
2023-05-14 08:43:02 +00:00

201 lines
5.7 KiB
C++

/* (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. */
#include "pickup.h"
#include "character.h"
#include <game/generated/protocol.h>
#include <game/mapitems.h>
#include <game/teamscore.h>
#include <game/server/gamecontext.h>
#include <game/server/player.h>
static constexpr int gs_PickupPhysSize = 14;
CPickup::CPickup(CGameWorld *pGameWorld, int Type, int SubType, int Layer, int Number) :
CEntity(pGameWorld, CGameWorld::ENTTYPE_PICKUP, vec2(0, 0), gs_PickupPhysSize)
{
m_Type = Type;
m_Subtype = SubType;
m_Layer = Layer;
m_Number = Number;
GameWorld()->InsertEntity(this);
}
void CPickup::Reset()
{
m_MarkedForDestroy = true;
}
void CPickup::Tick()
{
Move();
// Check if a player intersected us
CEntity *apEnts[MAX_CLIENTS];
int Num = GameWorld()->FindEntities(m_Pos, GetProximityRadius() + ms_CollisionExtraSize, apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
for(int i = 0; i < Num; ++i)
{
auto *pChr = static_cast<CCharacter *>(apEnts[i]);
if(pChr && pChr->IsAlive())
{
if(m_Layer == LAYER_SWITCH && m_Number > 0 && !Switchers()[m_Number].m_aStatus[pChr->Team()])
continue;
bool Sound = false;
// player picked us up, is someone was hooking us, let them go
switch(m_Type)
{
case POWERUP_HEALTH:
if(pChr->Freeze())
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_HEALTH, pChr->TeamMask());
break;
case POWERUP_ARMOR:
if(pChr->Team() == TEAM_SUPER)
continue;
for(int j = WEAPON_SHOTGUN; j < NUM_WEAPONS; j++)
{
if(pChr->GetWeaponGot(j))
{
pChr->SetWeaponGot(j, false);
pChr->SetWeaponAmmo(j, 0);
Sound = true;
}
}
pChr->SetNinjaActivationDir(vec2(0, 0));
pChr->SetNinjaActivationTick(-500);
pChr->SetNinjaCurrentMoveTime(0);
if(Sound)
{
pChr->SetLastWeapon(WEAPON_GUN);
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR, pChr->TeamMask());
}
if(pChr->GetActiveWeapon() >= WEAPON_SHOTGUN)
pChr->SetActiveWeapon(WEAPON_HAMMER);
break;
case POWERUP_ARMOR_SHOTGUN:
if(pChr->Team() == TEAM_SUPER)
continue;
if(pChr->GetWeaponGot(WEAPON_SHOTGUN))
{
pChr->SetWeaponGot(WEAPON_SHOTGUN, false);
pChr->SetWeaponAmmo(WEAPON_SHOTGUN, 0);
pChr->SetLastWeapon(WEAPON_GUN);
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR, pChr->TeamMask());
}
if(pChr->GetActiveWeapon() == WEAPON_SHOTGUN)
pChr->SetActiveWeapon(WEAPON_HAMMER);
break;
case POWERUP_ARMOR_GRENADE:
if(pChr->Team() == TEAM_SUPER)
continue;
if(pChr->GetWeaponGot(WEAPON_GRENADE))
{
pChr->SetWeaponGot(WEAPON_GRENADE, false);
pChr->SetWeaponAmmo(WEAPON_GRENADE, 0);
pChr->SetLastWeapon(WEAPON_GUN);
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR, pChr->TeamMask());
}
if(pChr->GetActiveWeapon() == WEAPON_GRENADE)
pChr->SetActiveWeapon(WEAPON_HAMMER);
break;
case POWERUP_ARMOR_NINJA:
if(pChr->Team() == TEAM_SUPER)
continue;
pChr->SetNinjaActivationDir(vec2(0, 0));
pChr->SetNinjaActivationTick(-500);
pChr->SetNinjaCurrentMoveTime(0);
break;
case POWERUP_ARMOR_LASER:
if(pChr->Team() == TEAM_SUPER)
continue;
if(pChr->GetWeaponGot(WEAPON_LASER))
{
pChr->SetWeaponGot(WEAPON_LASER, false);
pChr->SetWeaponAmmo(WEAPON_LASER, 0);
pChr->SetLastWeapon(WEAPON_GUN);
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_ARMOR, pChr->TeamMask());
}
if(pChr->GetActiveWeapon() == WEAPON_LASER)
pChr->SetActiveWeapon(WEAPON_HAMMER);
break;
case POWERUP_WEAPON:
if(m_Subtype >= 0 && m_Subtype < NUM_WEAPONS && (!pChr->GetWeaponGot(m_Subtype) || pChr->GetWeaponAmmo(m_Subtype) != -1))
{
pChr->GiveWeapon(m_Subtype);
if(m_Subtype == WEAPON_GRENADE)
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_GRENADE, pChr->TeamMask());
else if(m_Subtype == WEAPON_SHOTGUN)
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN, pChr->TeamMask());
else if(m_Subtype == WEAPON_LASER)
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_SHOTGUN, pChr->TeamMask());
if(pChr->GetPlayer())
GameServer()->SendWeaponPickup(pChr->GetPlayer()->GetCID(), m_Subtype);
}
break;
case POWERUP_NINJA:
{
// activate ninja on target player
pChr->GiveNinja();
break;
}
default:
break;
};
}
}
}
void CPickup::TickPaused()
{
}
void CPickup::Snap(int SnappingClient)
{
if(NetworkClipped(SnappingClient))
return;
int SnappingClientVersion = GameServer()->GetClientVersion(SnappingClient);
bool Sixup = Server()->IsSixup(SnappingClient);
if(SnappingClientVersion < VERSION_DDNET_ENTITY_NETOBJS)
{
CCharacter *pChar = GameServer()->GetPlayerChar(SnappingClient);
if(SnappingClient != SERVER_DEMO_CLIENT && (GameServer()->m_apPlayers[SnappingClient]->GetTeam() == TEAM_SPECTATORS || GameServer()->m_apPlayers[SnappingClient]->IsPaused()) && GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID != SPEC_FREEVIEW)
pChar = GameServer()->GetPlayerChar(GameServer()->m_apPlayers[SnappingClient]->m_SpectatorID);
int Tick = (Server()->Tick() % Server()->TickSpeed()) % 11;
if(pChar && pChar->IsAlive() && m_Layer == LAYER_SWITCH && m_Number > 0 && !Switchers()[m_Number].m_aStatus[pChar->Team()] && !Tick)
return;
}
GameServer()->SnapPickup(CSnapContext(SnappingClientVersion, Sixup), GetID(), m_Pos, m_Type, m_Subtype, m_Number);
}
void CPickup::Move()
{
if(Server()->Tick() % (int)(Server()->TickSpeed() * 0.15f) == 0)
{
int Flags;
int index = GameServer()->Collision()->IsMover(m_Pos.x, m_Pos.y, &Flags);
if(index)
{
m_Core = GameServer()->Collision()->CpSpeed(index, Flags);
}
m_Pos += m_Core;
}
}