6566: Allow using rescue (/r) on health pickup r=heinrich5991 a=Robyt3

Check if character is in range of health pickup and don't set rescue position if that's the case, so rescue can be used to get out of the health pickup's freeze effect.

The existing `m_Core.m_IsInFreeze` is not set so this should not have any side-effects.

Closes #3330.

## Checklist

- [X] 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
- [X] 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: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
bors[bot] 2023-05-08 11:31:39 +00:00 committed by GitHub
commit 1112c9e6b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 8 deletions

View file

@ -33,9 +33,6 @@ class CCharacter : public CEntity
public:
~CCharacter();
//character's size
static const int ms_PhysSize = 28;
void PreTick() override;
void Tick() override;
void TickDeferred() override;

View file

@ -11,13 +11,13 @@ void CPickup::Tick()
Move();
// Check if a player intersected us
CEntity *apEnts[MAX_CLIENTS];
int Num = GameWorld()->FindEntities(m_Pos, 20.0f, apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
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)
{
if(GameWorld()->m_WorldConfig.m_IsVanilla && distance(m_Pos, pChr->m_Pos) >= 20.0f * 2) // pickup distance is shorter on vanilla due to using ClosestEntity
if(GameWorld()->m_WorldConfig.m_IsVanilla && distance(m_Pos, pChr->m_Pos) >= (GetProximityRadius() + ms_CollisionExtraSize) * 2) // pickup distance is shorter on vanilla due to using ClosestEntity
continue;
if(m_Layer == LAYER_SWITCH && m_Number > 0 && m_Number < (int)Switchers().size() && !Switchers()[m_Number].m_aStatus[pChr->Team()])
continue;

View file

@ -8,6 +8,8 @@
class CPickup : public CEntity
{
public:
static const int ms_CollisionExtraSize = 6;
void Tick() override;
CPickup(CGameWorld *pGameWorld, int ID, CNetObj_Pickup *pPickup, const CNetObj_EntityEx *pEntEx = 0);
@ -15,6 +17,9 @@ public:
bool Match(CPickup *pPickup);
bool InDDNetTile() { return m_IsCoreActive; }
int Type() const { return m_Type; }
int Subtype() const { return m_Subtype; }
private:
int m_Type;
int m_Subtype;

View file

@ -2,6 +2,7 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "character.h"
#include "laser.h"
#include "pickup.h"
#include "projectile.h"
#include <antibot/antibot_data.h>
@ -2002,10 +2003,31 @@ void CCharacter::DDRaceTick()
}
}
// check for nearby health pickups (also freeze)
bool InHealthPickup = false;
if(!m_Core.m_IsInFreeze)
{
CEntity *apEnts[9];
int Num = GameWorld()->FindEntities(m_Pos, GetProximityRadius() + CPickup::ms_CollisionExtraSize, apEnts, std::size(apEnts), CGameWorld::ENTTYPE_PICKUP);
for(int i = 0; i < Num; ++i)
{
CPickup *pPickup = static_cast<CPickup *>(apEnts[i]);
if(pPickup->Type() == POWERUP_HEALTH)
{
// This uses a separate variable InHealthPickup instead of setting m_Core.m_IsInFreeze
// as the latter causes freezebars to flicker when standing in the freeze range of a
// health pickup. When the same code for client prediction is added, the freezebars
// still flicker, but only when standing at the edge of the health pickup's freeze range.
InHealthPickup = true;
break;
}
}
}
// look for save position for rescue feature
if(g_Config.m_SvRescue || ((g_Config.m_SvTeam == SV_TEAM_FORCED_SOLO || Team() > TEAM_FLOCK) && Team() >= TEAM_FLOCK && Team() < TEAM_SUPER))
{
if(!m_Core.m_IsInFreeze && IsGrounded() && !m_Core.m_DeepFrozen)
if(!m_Core.m_IsInFreeze && IsGrounded() && !m_Core.m_DeepFrozen && !InHealthPickup)
{
SetRescue();
}

View file

@ -35,7 +35,7 @@ void CPickup::Tick()
// Check if a player intersected us
CEntity *apEnts[MAX_CLIENTS];
int Num = GameWorld()->FindEntities(m_Pos, 20.0f, apEnts, MAX_CLIENTS, CGameWorld::ENTTYPE_CHARACTER);
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]);

View file

@ -8,6 +8,8 @@
class CPickup : public CEntity
{
public:
static const int ms_CollisionExtraSize = 6;
CPickup(CGameWorld *pGameWorld, int Type, int SubType = 0, int Layer = 0, int Number = 0);
void Reset() override;
@ -15,10 +17,12 @@ public:
void TickPaused() override;
void Snap(int SnappingClient) override;
int Type() const { return m_Type; }
int Subtype() const { return m_Subtype; }
private:
int m_Type;
int m_Subtype;
//int m_SpawnTick;
// DDRace