Skip to content

Commit

Permalink
Merge pull request ddnet#9047 from timakro/pr-add-invincible-mode
Browse files Browse the repository at this point in the history
Add invincible mode
  • Loading branch information
def- authored Oct 4, 2024
2 parents a56e532 + 5457e8f commit d51a726
Show file tree
Hide file tree
Showing 20 changed files with 132 additions and 44 deletions.
Binary file modified data/extras.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions datasrc/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ def FileList(fmt, num):
container.sprites.Add(Sprite("hud_team0_mode", set_hud, 12,6,2,2))

container.sprites.Add(Sprite("part_snowflake", set_extras, 0,0,2,2))
container.sprites.Add(Sprite("part_sparkle", set_extras, 2,0,2,2))


anim = Animation("base")
Expand Down
2 changes: 1 addition & 1 deletion datasrc/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"HAMMER_HIT_DISABLED", "SHOTGUN_HIT_DISABLED", "GRENADE_HIT_DISABLED", "LASER_HIT_DISABLED", "HOOK_HIT_DISABLED",
"TELEGUN_GUN", "TELEGUN_GRENADE", "TELEGUN_LASER",
"WEAPON_HAMMER", "WEAPON_GUN", "WEAPON_SHOTGUN", "WEAPON_GRENADE", "WEAPON_LASER", "WEAPON_NINJA",
"MOVEMENTS_DISABLED", "IN_FREEZE", "PRACTICE_MODE", "LOCK_MODE", "TEAM0_MODE"]
"MOVEMENTS_DISABLED", "IN_FREEZE", "PRACTICE_MODE", "LOCK_MODE", "TEAM0_MODE", "INVINCIBLE"]
GameInfoFlags = [
"TIMESCORE", "GAMETYPE_RACE", "GAMETYPE_FASTCAP", "GAMETYPE_FNG",
"GAMETYPE_DDRACE", "GAMETYPE_DDNET", "GAMETYPE_BLOCK_WORLDS",
Expand Down
20 changes: 20 additions & 0 deletions src/game/client/components/effects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,26 @@ void CEffects::FreezingFlakes(vec2 Pos, vec2 Size, float Alpha)
m_pClient->m_Particles.Add(CParticles::GROUP_EXTRA, &p);
}

void CEffects::SparkleTrail(vec2 Pos, float Alpha)
{
if(!m_Add50hz)
return;

CParticle p;
p.SetDefault();
p.m_Spr = SPRITE_PART_SPARKLE;
p.m_Pos = Pos + random_direction() * random_float(40.0f);
p.m_Vel = vec2(0, 0);
p.m_LifeSpan = 0.5f;
p.m_StartSize = 0.0f;
p.m_EndSize = random_float(20.0f, 30.0f);
p.m_UseAlphaFading = true;
p.m_StartAlpha = Alpha;
p.m_EndAlpha = std::min(0.2f, Alpha);
p.m_Collides = false;
m_pClient->m_Particles.Add(CParticles::GROUP_TRAIL_EXTRA, &p);
}

void CEffects::SmokeTrail(vec2 Pos, vec2 Vel, float Alpha, float TimePassed)
{
if(!m_Add50hz && TimePassed < 0.001f)
Expand Down
1 change: 1 addition & 0 deletions src/game/client/components/effects.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CEffects : public CComponent
void PlayerDeath(vec2 Pos, int ClientId, float Alpha = 1.0f);
void PowerupShine(vec2 Pos, vec2 Size, float Alpha = 1.0f);
void FreezingFlakes(vec2 Pos, vec2 Size, float Alpha = 1.0f);
void SparkleTrail(vec2 Pos, float Alpha = 1.0f);
void Confetti(vec2 Pos, float Alpha = 1.0f);

void Update();
Expand Down
12 changes: 8 additions & 4 deletions src/game/client/components/particles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ CParticles::CParticles()
{
OnReset();
m_RenderTrail.m_pParts = this;
m_RenderTrailExtra.m_pParts = this;
m_RenderExplosions.m_pParts = this;
m_RenderExtra.m_pParts = this;
m_RenderGeneral.m_pParts = this;
Expand Down Expand Up @@ -181,9 +182,12 @@ void CParticles::OnInit()

m_ExtraParticleQuadContainerIndex = Graphics()->CreateQuadContainer(false);

// TODO: Use a loop similar to the one for m_ParticleQuadContainerIndex if you add more additional particles
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ExtraParticleQuadContainerIndex, 1.f);
for(int i = 0; i <= (SPRITE_PART_SPARKLE - SPRITE_PART_SNOWFLAKE); ++i)
{
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ExtraParticleQuadContainerIndex, 1.f);
}

Graphics()->QuadContainerUpload(m_ExtraParticleQuadContainerIndex);
}

Expand All @@ -207,7 +211,7 @@ void CParticles::RenderGroup(int Group)
IGraphics::CTextureHandle *aParticles = GameClient()->m_ParticlesSkin.m_aSpriteParticles;
int FirstParticleOffset = SPRITE_PART_SLICE;
int ParticleQuadContainerIndex = m_ParticleQuadContainerIndex;
if(Group == GROUP_EXTRA)
if(Group == GROUP_EXTRA || Group == GROUP_TRAIL_EXTRA)
{
aParticles = GameClient()->m_ExtrasSkin.m_aSpriteParticles;
FirstParticleOffset = SPRITE_PART_SNOWFLAKE;
Expand Down
4 changes: 4 additions & 0 deletions src/game/client/components/particles.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class CParticles : public CComponent
enum
{
GROUP_PROJECTILE_TRAIL = 0,
GROUP_TRAIL_EXTRA,
GROUP_EXPLOSIONS,
GROUP_EXTRA,
GROUP_GENERAL,
Expand Down Expand Up @@ -111,7 +112,10 @@ class CParticles : public CComponent
virtual void OnRender() override { m_pParts->RenderGroup(TGROUP); }
};

// behind players
CRenderGroup<GROUP_PROJECTILE_TRAIL> m_RenderTrail;
CRenderGroup<GROUP_TRAIL_EXTRA> m_RenderTrailExtra;
// in front of players
CRenderGroup<GROUP_EXPLOSIONS> m_RenderExplosions;
CRenderGroup<GROUP_EXTRA> m_RenderExtra;
CRenderGroup<GROUP_GENERAL> m_RenderGeneral;
Expand Down
6 changes: 6 additions & 0 deletions src/game/client/components/players.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,10 @@ void CPlayers::RenderPlayer(
{
GameClient()->m_Effects.FreezingFlakes(BodyPos, vec2(32, 32), Alpha);
}
if(RenderInfo.m_TeeRenderFlags & TEE_EFFECT_SPARKLE)
{
GameClient()->m_Effects.SparkleTrail(BodyPos, Alpha);
}

if(ClientId < 0)
return;
Expand Down Expand Up @@ -833,6 +837,8 @@ void CPlayers::OnRender()
aRenderInfo[i].m_TeeRenderFlags |= TEE_EFFECT_FROZEN | TEE_NO_WEAPON;
if(m_pClient->m_aClients[i].m_LiveFrozen)
aRenderInfo[i].m_TeeRenderFlags |= TEE_EFFECT_FROZEN;
if(m_pClient->m_aClients[i].m_Invincible)
aRenderInfo[i].m_TeeRenderFlags |= TEE_EFFECT_SPARKLE;

const CGameClient::CSnapState::CCharacterInfo &CharacterInfo = m_pClient->m_Snap.m_aCharacters[i];
const bool Frozen = CharacterInfo.m_HasExtendedData && CharacterInfo.m_ExtendedData.m_FreezeEnd != 0;
Expand Down
8 changes: 8 additions & 0 deletions src/game/client/gameclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ void CGameClient::OnConsoleInit()
&m_Background, // render instead of m_MapLayersBackground when g_Config.m_ClOverlayEntities == 100
&m_MapLayersBackground, // first to render
&m_Particles.m_RenderTrail,
&m_Particles.m_RenderTrailExtra,
&m_Items,
&m_Ghost,
&m_Players,
Expand Down Expand Up @@ -1683,6 +1684,7 @@ void CGameClient::OnNewSnapshot()
pClient->m_ShotgunHitDisabled = pCharacterData->m_Flags & CHARACTERFLAG_SHOTGUN_HIT_DISABLED;
pClient->m_HookHitDisabled = pCharacterData->m_Flags & CHARACTERFLAG_HOOK_HIT_DISABLED;
pClient->m_Super = pCharacterData->m_Flags & CHARACTERFLAG_SUPER;
pClient->m_Invincible = pCharacterData->m_Flags & CHARACTERFLAG_INVINCIBLE;

// Endless
pClient->m_EndlessHook = pCharacterData->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
Expand Down Expand Up @@ -2457,6 +2459,7 @@ void CGameClient::CClientData::Reset()
m_ShotgunHitDisabled = false;
m_HookHitDisabled = false;
m_Super = false;
m_Invincible = false;
m_HasTelegunGun = false;
m_HasTelegunGrenade = false;
m_HasTelegunLaser = false;
Expand Down Expand Up @@ -3694,6 +3697,7 @@ void CGameClient::LoadExtrasSkin(const char *pPath, bool AsDir)
if(m_ExtrasSkinLoaded)
{
Graphics()->UnloadTexture(&m_ExtrasSkin.m_SpriteParticleSnowflake);
Graphics()->UnloadTexture(&m_ExtrasSkin.m_SpriteParticleSparkle);

for(auto &SpriteParticle : m_ExtrasSkin.m_aSpriteParticles)
SpriteParticle = IGraphics::CTextureHandle();
Expand Down Expand Up @@ -3728,7 +3732,11 @@ void CGameClient::LoadExtrasSkin(const char *pPath, bool AsDir)
else if(PngLoaded && Graphics()->CheckImageDivisibility(aPath, ImgInfo, g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE].m_pSet->m_Gridx, g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE].m_pSet->m_Gridy, true) && Graphics()->IsImageFormatRgba(aPath, ImgInfo))
{
m_ExtrasSkin.m_SpriteParticleSnowflake = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SNOWFLAKE]);
m_ExtrasSkin.m_SpriteParticleSparkle = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PART_SPARKLE]);

m_ExtrasSkin.m_aSpriteParticles[0] = m_ExtrasSkin.m_SpriteParticleSnowflake;
m_ExtrasSkin.m_aSpriteParticles[1] = m_ExtrasSkin.m_SpriteParticleSparkle;

m_ExtrasSkinLoaded = true;
}
ImgInfo.Free();
Expand Down
4 changes: 3 additions & 1 deletion src/game/client/gameclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ class CGameClient : public IGameClient
bool m_ShotgunHitDisabled;
bool m_HookHitDisabled;
bool m_Super;
bool m_Invincible;
bool m_HasTelegunGun;
bool m_HasTelegunGrenade;
bool m_HasTelegunLaser;
Expand Down Expand Up @@ -768,7 +769,8 @@ class CGameClient : public IGameClient
struct SClientExtrasSkin
{
IGraphics::CTextureHandle m_SpriteParticleSnowflake;
IGraphics::CTextureHandle m_aSpriteParticles[1];
IGraphics::CTextureHandle m_SpriteParticleSparkle;
IGraphics::CTextureHandle m_aSpriteParticles[2];
};

SClientExtrasSkin m_ExtrasSkin;
Expand Down
30 changes: 15 additions & 15 deletions src/game/client/prediction/entities/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -757,19 +757,19 @@ void CCharacter::HandleTiles(int Index)
Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aType[Team()] = TILE_SWITCHCLOSE;
Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aLastUpdateTick[Team()] = GameWorld()->GameTick();
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER)
else if(Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER && !m_Core.m_Invincible)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aStatus[Team()])
{
Freeze(Collision()->GetSwitchDelay(MapIndex));
}
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER)
else if(Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER && !m_Core.m_Invincible)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aStatus[Team()])
m_Core.m_DeepFrozen = true;
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_DUNFREEZE && Team() != TEAM_SUPER)
else if(Collision()->GetSwitchType(MapIndex) == TILE_DUNFREEZE && Team() != TEAM_SUPER && !m_Core.m_Invincible)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aStatus[Team()])
m_Core.m_DeepFrozen = false;
Expand Down Expand Up @@ -817,14 +817,14 @@ void CCharacter::HandleTiles(int Index)
if(NewJumps != m_Core.m_Jumps)
m_Core.m_Jumps = NewJumps;
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_LFREEZE && Team() != TEAM_SUPER)
else if(Collision()->GetSwitchType(MapIndex) == TILE_LFREEZE && Team() != TEAM_SUPER && !m_Core.m_Invincible)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aStatus[Team()])
{
m_Core.m_LiveFrozen = true;
}
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_LUNFREEZE && Team() != TEAM_SUPER)
else if(Collision()->GetSwitchType(MapIndex) == TILE_LUNFREEZE && Team() != TEAM_SUPER && !m_Core.m_Invincible)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Switchers()[Collision()->GetSwitchNumber(MapIndex)].m_aStatus[Team()])
{
Expand All @@ -833,7 +833,7 @@ void CCharacter::HandleTiles(int Index)
}

// freeze
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Core.m_Super && !m_Core.m_DeepFrozen)
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Core.m_Super && !m_Core.m_Invincible && !m_Core.m_DeepFrozen)
{
Freeze();
}
Expand All @@ -843,21 +843,21 @@ void CCharacter::HandleTiles(int Index)
}

// deep freeze
if(((m_TileIndex == TILE_DFREEZE) || (m_TileFIndex == TILE_DFREEZE)) && !m_Core.m_Super && !m_Core.m_DeepFrozen)
if(((m_TileIndex == TILE_DFREEZE) || (m_TileFIndex == TILE_DFREEZE)) && !m_Core.m_Super && !m_Core.m_Invincible && !m_Core.m_DeepFrozen)
{
m_Core.m_DeepFrozen = true;
}
else if(((m_TileIndex == TILE_DUNFREEZE) || (m_TileFIndex == TILE_DUNFREEZE)) && !m_Core.m_Super && m_Core.m_DeepFrozen)
else if(((m_TileIndex == TILE_DUNFREEZE) || (m_TileFIndex == TILE_DUNFREEZE)) && !m_Core.m_Super && !m_Core.m_Invincible && m_Core.m_DeepFrozen)
{
m_Core.m_DeepFrozen = false;
}

// live freeze
if(((m_TileIndex == TILE_LFREEZE) || (m_TileFIndex == TILE_LFREEZE)) && !m_Core.m_Super)
if(((m_TileIndex == TILE_LFREEZE) || (m_TileFIndex == TILE_LFREEZE)) && !m_Core.m_Super && !m_Core.m_Invincible)
{
m_Core.m_LiveFrozen = true;
}
else if(((m_TileIndex == TILE_LUNFREEZE) || (m_TileFIndex == TILE_LUNFREEZE)) && !m_Core.m_Super)
else if(((m_TileIndex == TILE_LUNFREEZE) || (m_TileFIndex == TILE_LUNFREEZE)) && !m_Core.m_Super && !m_Core.m_Invincible)
{
m_Core.m_LiveFrozen = false;
}
Expand Down Expand Up @@ -959,7 +959,7 @@ void CCharacter::HandleTuneLayer()
void CCharacter::DDRaceTick()
{
mem_copy(&m_Input, &m_SavedInput, sizeof(m_Input));
if(m_Core.m_LiveFrozen && !m_CanMoveInFreeze && !m_Core.m_Super)
if(m_Core.m_LiveFrozen && !m_CanMoveInFreeze && !m_Core.m_Super && !m_Core.m_Invincible)
{
m_Input.m_Direction = 0;
m_Input.m_Jump = 0;
Expand Down Expand Up @@ -1007,7 +1007,7 @@ void CCharacter::DDRacePostCoreTick()

m_FrozenLastTick = false;

if(m_Core.m_DeepFrozen && !m_Core.m_Super)
if(m_Core.m_DeepFrozen && !m_Core.m_Super && !m_Core.m_Invincible)
Freeze();

// following jump rules can be overridden by tiles, like Refill Jumps, Stopper and Wall Jump
Expand All @@ -1032,9 +1032,9 @@ void CCharacter::DDRacePostCoreTick()
m_Core.m_Jumped = 1;
}

if((m_Core.m_Super || m_Core.m_EndlessJump) && m_Core.m_Jumped > 1)
if((m_Core.m_Super || m_Core.m_Invincible || m_Core.m_EndlessJump) && m_Core.m_Jumped > 1)
{
// Super players and players with infinite jumps always have light feet
// Super players, invincible players and players with infinite jumps always have light feet
m_Core.m_Jumped = 1;
}

Expand All @@ -1056,7 +1056,7 @@ bool CCharacter::Freeze(int Seconds)
{
if(!GameWorld()->m_WorldConfig.m_PredictFreeze)
return false;
if(Seconds <= 0 || m_Core.m_Super || m_FreezeTime > Seconds * GameWorld()->GameTickSpeed())
if(Seconds <= 0 || m_Core.m_Super || m_Core.m_Invincible || m_FreezeTime > Seconds * GameWorld()->GameTickSpeed())
return false;
if(m_Core.m_FreezeStart < GameWorld()->GameTick() - GameWorld()->GameTickSpeed())
{
Expand Down
1 change: 1 addition & 0 deletions src/game/client/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum
{
TEE_EFFECT_FROZEN = 1,
TEE_NO_WEAPON = 2,
TEE_EFFECT_SPARKLE = 4,
};

// sprite renderings
Expand Down
2 changes: 2 additions & 0 deletions src/game/gamecore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ void CCharacterCore::Reset()
m_ShotgunHitDisabled = false;
m_HookHitDisabled = false;
m_Super = false;
m_Invincible = false;
m_HasTelegunGun = false;
m_HasTelegunGrenade = false;
m_HasTelegunLaser = false;
Expand Down Expand Up @@ -647,6 +648,7 @@ void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
m_LaserHitDisabled = pObjDDNet->m_Flags & CHARACTERFLAG_LASER_HIT_DISABLED;
m_HookHitDisabled = pObjDDNet->m_Flags & CHARACTERFLAG_HOOK_HIT_DISABLED;
m_Super = pObjDDNet->m_Flags & CHARACTERFLAG_SUPER;
m_Invincible = pObjDDNet->m_Flags & CHARACTERFLAG_INVINCIBLE;

// Endless
m_EndlessHook = pObjDDNet->m_Flags & CHARACTERFLAG_ENDLESS_HOOK;
Expand Down
1 change: 1 addition & 0 deletions src/game/gamecore.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ class CCharacterCore
bool m_ShotgunHitDisabled;
bool m_HookHitDisabled;
bool m_Super;
bool m_Invincible;
bool m_HasTelegunGun;
bool m_HasTelegunGrenade;
bool m_HasTelegunLaser;
Expand Down
7 changes: 7 additions & 0 deletions src/game/server/ddracechat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2169,6 +2169,13 @@ void CGameContext::ConPracticeUnNinja(IConsole::IResult *pResult, void *pUserDat
ConUnNinja(pResult, pUserData);
}

void CGameContext::ConPracticeToggleInvincible(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(pSelf->GetPracticeCharacter(pResult))
ConToggleInvincible(pResult, pUserData);
}

void CGameContext::ConPracticeAddWeapon(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
Expand Down
8 changes: 8 additions & 0 deletions src/game/server/ddracecommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ void CGameContext::ConUnSuper(IConsole::IResult *pResult, void *pUserData)
}
}

void CGameContext::ConToggleInvincible(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->GetPlayerChar(pResult->m_ClientId);
if(pChr)
pChr->SetInvincible(pResult->NumArguments() == 0 ? !pChr->Core()->m_Invincible : pResult->GetInteger(0));
}

void CGameContext::ConSolo(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
Expand Down
Loading

0 comments on commit d51a726

Please sign in to comment.