5085: New DDRace HUD r=def- a=C0D3D3V

If you want to test this PR, you have to test it on a Server that includes this PR too.

Textures are made by Ravie 

Here a showcase video with most parts shown: https://youtu.be/gPTVj-s3pgc 

Added to the new HUD
- A display of the weapons available to the player
- The weapon the player is carrying is highlighted
- Indicators for the special abilities of the player (Endless Hook, Endless Jumps, Jetpack, Teleport Weapons)
- Indicators for abilities taken away from the player (Deep/Life Freeze, No Hook, No Weapons collision, No Collision)
- Control indicators for dummy controls (dummy hammer, dummy copy) (bottom right)
- Jump indicator (max 10 jumps ar displayed, and greyed out as soon as a jump is used) 
- Ninja status bar that indicates how long a player is capable of using ninja (next to the ninja sword)
- Freeze status bar that indicates the thawing time of a player (below player)
- Movement Information can be displayed in a clean way above the mini score HUD (Position, Speed, Target Angle)
- Indicator if you are in practice mode

The complete HUD also works for players you spectate

I Added a new NetObj since the predicted values are not perfect and would make the display of the information a lot less good: DDNetCharacterDisplayInfo that contains the following information
```
NetIntRange("m_JumpedTotal", -2, 255),
NetTick("m_NinjaActivationTick"),
NetTick("m_FreezeTick"),
NetBool("m_IsInFreeze"),
NetBool("m_IsInPracticeMode"),

NetIntAny("m_TargetX"),  # used for the Movement Information display
NetIntAny("m_TargetY"),
NetIntAny("m_RampValue"),
```
So if someone has an idea what data we could also need in the client for making the display more nice, now is the right moment to add more data to this network object.

A few screenshots:
Assets Tab:
![grafik](https://user-images.githubusercontent.com/14315968/167703792-f0fa86be-159d-4e11-baf4-9539cee38aae.png)
HUD Settings:
![grafik](https://user-images.githubusercontent.com/14315968/167704336-dc7a314e-5603-40a2-98b4-9c03377906dd.png)
Mini Debug HUD:
![grafik](https://user-images.githubusercontent.com/14315968/168302791-c377d93e-33a2-4eb2-9d8d-b78f0808a009.png)
Speed.X is calculated using the players ramp vaule


## Checklist

- [x] Tested the change ingame
- [x] Provided screenshots if it is a visual change
- [ ] Tested in combination with possibly related configuration options
- [ ] Written a unit test if it works standalone, system.c especially
- [x] Considered possible null pointers and out of bounds array indexing
- [x] Changed no physics that affect existing maps
- [x] 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: c0d3d3v <c0d3d3v@mag-keinen-spam.de>
Co-authored-by: Jupeyy <jupjopjap@gmail.com>
This commit is contained in:
bors[bot] 2022-05-16 22:23:08 +00:00 committed by GitHub
commit 47874fb57f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2028 additions and 528 deletions

View file

@ -1234,6 +1234,7 @@ set(EXPECTED_DATA
gui_cursor.png
gui_icons.png
gui_logo.png
hud.png
languages/arabic.txt
languages/belarusian.txt
languages/bosnian.txt
@ -1964,6 +1965,8 @@ if(CLIENT)
components/emoticon.h
components/flow.cpp
components/flow.h
components/freezebars.cpp
components/freezebars.h
components/ghost.cpp
components/ghost.h
components/hud.cpp

BIN
data/hud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -238,6 +238,7 @@ image_arrow = Image("arrow", "arrow.png")
image_demobuttons2 = Image("demobuttons2", "demo_buttons2.png")
image_audio_source = Image("audio_source", "editor/audio_source.png")
image_strongweak = Image("strongweak", "strong_weak.png")
image_hud = Image("hud", "hud.png")
container.images.Add(image_null)
container.images.Add(image_game)
@ -256,6 +257,7 @@ container.images.Add(image_arrow)
container.images.Add(image_demobuttons2)
container.images.Add(image_audio_source)
container.images.Add(image_strongweak)
container.images.Add(image_hud)
container.pickups.Add(Pickup("health"))
container.pickups.Add(Pickup("armor"))
@ -278,6 +280,7 @@ set_guiicons = SpriteSet("guiicons", image_guiicons, 12, 2)
set_demobuttons2 = SpriteSet("demobuttons2", image_demobuttons2, 4, 1)
set_audio_source = SpriteSet("audio_source", image_audio_source, 1, 1)
set_strongweak = SpriteSet("strongweak", image_strongweak, 2, 1)
set_hud = SpriteSet("hud", image_hud, 14, 12)
container.spritesets.Add(set_particles)
container.spritesets.Add(set_game)
@ -291,6 +294,7 @@ container.spritesets.Add(set_guiicons)
container.spritesets.Add(set_demobuttons2)
container.spritesets.Add(set_audio_source)
container.spritesets.Add(set_strongweak)
container.spritesets.Add(set_hud)
container.sprites.Add(Sprite("part_slice", set_particles, 0,0,1,1))
container.sprites.Add(Sprite("part_ball", set_particles, 1,0,1,1))
@ -362,12 +366,16 @@ container.sprites.Add(Sprite("weapon_ninja_muzzle3", set_game, 25,8,7,4))
container.sprites.Add(Sprite("pickup_health", set_game, 10,2,2,2))
container.sprites.Add(Sprite("pickup_armor", set_game, 12,2,2,2))
container.sprites.Add(Sprite("pickup_hammer", set_game, 2,1,4,3))
container.sprites.Add(Sprite("pickup_gun", set_game, 2,4,4,2))
container.sprites.Add(Sprite("pickup_shotgun", set_game, 2,6,8,2))
container.sprites.Add(Sprite("pickup_grenade", set_game, 2,8,7,2))
container.sprites.Add(Sprite("pickup_laser", set_game, 2,12,7,3))
container.sprites.Add(Sprite("pickup_ninja", set_game, 2,10,8,2))
container.sprites.Add(Sprite("pickup_armor_shotgun", set_game, 15,2,2,2))
container.sprites.Add(Sprite("pickup_armor_grenade", set_game, 17,2,2,2))
container.sprites.Add(Sprite("pickup_armor_laser", set_game, 19,2,2,2))
container.sprites.Add(Sprite("pickup_armor_ninja", set_game, 10,10,2,2))
container.sprites.Add(Sprite("pickup_weapon", set_game, 3,0,6,2))
container.sprites.Add(Sprite("pickup_ninja", set_game, 2,10,8,2))
container.sprites.Add(Sprite("pickup_armor_laser", set_game, 19,2,2,2))
container.sprites.Add(Sprite("flag_blue", set_game, 12,8,4,8))
container.sprites.Add(Sprite("flag_red", set_game, 16,8,4,8))
@ -434,6 +442,35 @@ container.sprites.Add(Sprite("audio_source", set_audio_source, 0,0,1,1))
container.sprites.Add(Sprite("hook_strong", set_strongweak, 0,0,1,1))
container.sprites.Add(Sprite("hook_weak", set_strongweak, 1,0,1,1))
container.sprites.Add(Sprite("hud_airjump", set_hud, 0,0,2,2))
container.sprites.Add(Sprite("hud_airjump_empty", set_hud, 2,0,2,2))
container.sprites.Add(Sprite("hud_solo", set_hud, 4,0,2,2))
container.sprites.Add(Sprite("hud_no_collision", set_hud, 6,0,2,2))
container.sprites.Add(Sprite("hud_endless_jump", set_hud, 8,0,2,2))
container.sprites.Add(Sprite("hud_endless_hook", set_hud, 10,0,2,2))
container.sprites.Add(Sprite("hud_jetpack", set_hud, 12,0,2,2))
container.sprites.Add(Sprite("hud_freeze_bar_full_left", set_hud, 0,2,1,1))
container.sprites.Add(Sprite("hud_freeze_bar_full", set_hud, 1,2,1,1))
container.sprites.Add(Sprite("hud_freeze_bar_empty", set_hud, 2,2,1,1))
container.sprites.Add(Sprite("hud_freeze_bar_empty_right", set_hud, 3,2,1,1))
container.sprites.Add(Sprite("hud_ninja_bar_full_left", set_hud, 0,3,1,1))
container.sprites.Add(Sprite("hud_ninja_bar_full", set_hud, 1,3,1,1))
container.sprites.Add(Sprite("hud_ninja_bar_empty", set_hud, 2,3,1,1))
container.sprites.Add(Sprite("hud_ninja_bar_empty_right", set_hud, 3,3,1,1))
container.sprites.Add(Sprite("hud_no_hook_hit", set_hud, 4,2,2,2))
container.sprites.Add(Sprite("hud_no_hammer_hit", set_hud, 6,2,2,2))
container.sprites.Add(Sprite("hud_no_shotgun_hit", set_hud, 8,2,2,2))
container.sprites.Add(Sprite("hud_no_grenade_hit", set_hud, 10,2,2,2))
container.sprites.Add(Sprite("hud_no_laser_hit", set_hud, 12,2,2,2))
container.sprites.Add(Sprite("hud_deep_frozen", set_hud, 10,4,2,2))
container.sprites.Add(Sprite("hud_live_frozen", set_hud, 12,4,2,2))
container.sprites.Add(Sprite("hud_teleport_grenade", set_hud, 4,4,2,2))
container.sprites.Add(Sprite("hud_teleport_gun", set_hud, 6,4,2,2))
container.sprites.Add(Sprite("hud_teleport_laser", set_hud, 8,4,2,2))
container.sprites.Add(Sprite("hud_practice_mode", set_hud, 4,6,2,2))
container.sprites.Add(Sprite("hud_dummy_hammer", set_hud, 6,6,2,2))
container.sprites.Add(Sprite("hud_dummy_copy", set_hud, 8,6,2,2))
anim = Animation("base")
anim.body.frames.Add(AnimKeyframe(0, 0, -4, 0))
anim.back_foot.frames.Add(AnimKeyframe(0, 0, 10, 0))

View file

@ -243,6 +243,17 @@ Objects = [
NetIntRange("m_StrongWeakID", 0, 'MAX_CLIENTS-1'),
]),
NetObjectEx("DDNetCharacterDisplayInfo", "character-display-info@netobj.ddnet.tw", [
NetIntRange("m_JumpedTotal", 0, 255),
NetTick("m_NinjaActivationTick"),
NetTick("m_FreezeTick"),
NetBool("m_IsInFreeze"),
NetBool("m_IsInPracticeMode"),
NetIntAny("m_TargetX"),
NetIntAny("m_TargetY"),
NetIntAny("m_RampValue"),
]),
NetObjectEx("DDNetPlayer", "player@netobj.ddnet.tw", [
NetIntAny("m_Flags"),
NetIntRange("m_AuthLevel", "AUTHED_NO", "AUTHED_ADMIN"),

View file

@ -129,6 +129,19 @@ void CGraph::Add(float v, float r, float g, float b)
m_aColors[m_Index][2] = b;
}
bool CGraph::InsertAt(int i, float v, float r, float g, float b)
{
if(i < 0 || i > MAX_VALUES - 1)
{
return false;
}
m_aValues[i] = v;
m_aColors[i][0] = r;
m_aColors[i][1] = g;
m_aColors[i][2] = b;
return true;
}
void CGraph::Render(IGraphics *pGraphics, IGraphics::CTextureHandle FontTexture, float x, float y, float w, float h, const char *pDescription)
{
//m_pGraphics->BlendNormal();

View file

@ -53,6 +53,7 @@ public:
void ScaleMin();
void Add(float v, float r, float g, float b);
bool InsertAt(int i, float v, float r, float g, float b);
void Render(IGraphics *pGraphics, IGraphics::CTextureHandle FontTexture, float x, float y, float w, float h, const char *pDescription);
};

View file

@ -162,7 +162,9 @@ static void Mix(short *pFinalOut, unsigned Frames)
float r = Voice.m_Circle.m_Radius;
RangeX = r;
int Dist = (int)sqrtf((float)dx * dx + (float)dy * dy); // nasty float
// dx and dy can be larger than 46341 and thus the calculation would go beyond the limits of a integer,
// therefore we cast them into float
int Dist = (int)sqrtf((float)dx * dx + (float)dy * dy);
if(Dist < r)
{
InVoiceField = true;

View file

@ -41,6 +41,7 @@ MACRO_CONFIG_STR(ClAssetsEntites, cl_assets_entities, 50, "default", CFGFLAG_SAV
MACRO_CONFIG_STR(ClAssetGame, cl_asset_game, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for game")
MACRO_CONFIG_STR(ClAssetEmoticons, cl_asset_emoticons, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for emoticons")
MACRO_CONFIG_STR(ClAssetParticles, cl_asset_particles, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for particles")
MACRO_CONFIG_STR(ClAssetHud, cl_asset_hud, 50, "default", CFGFLAG_SAVE | CFGFLAG_CLIENT, "The asset for HUD")
MACRO_CONFIG_STR(BrFilterString, br_filter_string, 25, "Novice", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server browser filtering string")
MACRO_CONFIG_STR(BrExcludeString, br_exclude_string, 25, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server browser exclusion string")
@ -304,7 +305,10 @@ MACRO_CONFIG_INT(ClRaceGhost, cl_race_ghost, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_S
MACRO_CONFIG_INT(ClRaceGhostServerControl, cl_race_ghost_server_control, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Let the server start the ghost")
MACRO_CONFIG_INT(ClRaceShowGhost, cl_race_show_ghost, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ghost")
MACRO_CONFIG_INT(ClRaceSaveGhost, cl_race_save_ghost, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Save ghost")
MACRO_CONFIG_INT(ClDDRaceHud, cl_ddrace_hud, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable DDRace HUD")
MACRO_CONFIG_INT(ClDDRaceScoreBoard, cl_ddrace_scoreboard, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enable DDRace Scoreboard")
MACRO_CONFIG_INT(ClShowFreezeBars, cl_show_freeze_bars, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show a freeze bar under frozen players to indicate the thaw time")
MACRO_CONFIG_INT(SvResetPickups, sv_reset_pickups, 0, 0, 1, CFGFLAG_SERVER | CFGFLAG_GAME, "Whether the weapons are reset on passing the start tile or not")
MACRO_CONFIG_INT(ClShowOthers, cl_show_others, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show players in other teams (2 to show own team only)")
MACRO_CONFIG_INT(ClShowOthersAlpha, cl_show_others_alpha, 40, 0, 100, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show players in other teams (alpha value, 0 invisible, 100 fully visible)")

View file

@ -79,6 +79,7 @@ public:
fs_makedir(GetPath(TYPE_SAVE, "assets/entities", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "assets/game", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "assets/particles", aPath, sizeof(aPath)));
fs_makedir(GetPath(TYPE_SAVE, "assets/hud", aPath, sizeof(aPath)));
#if defined(CONF_VIDEORECORDER)
fs_makedir(GetPath(TYPE_SAVE, "videos", aPath, sizeof(aPath)));
#endif

View file

@ -28,25 +28,32 @@ void CDebugHud::RenderNetCorrections()
/*float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y),
vec2(netobjects.local_character->x, netobjects.local_character->y));*/
float Velspeed = length(vec2(m_pClient->m_Snap.m_pLocalCharacter->m_VelX / 256.0f, m_pClient->m_Snap.m_pLocalCharacter->m_VelY / 256.0f)) * 50;
const float TicksPerSecond = 50.0f;
float Velspeed = length(vec2(m_pClient->m_Snap.m_pLocalCharacter->m_VelX / 256.0f, m_pClient->m_Snap.m_pLocalCharacter->m_VelY / 256.0f)) * TicksPerSecond;
float VelspeedX = m_pClient->m_Snap.m_pLocalCharacter->m_VelX / 256.0f * TicksPerSecond;
float VelspeedY = m_pClient->m_Snap.m_pLocalCharacter->m_VelY / 256.0f * TicksPerSecond;
float Ramp = VelocityRamp(Velspeed, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampStart, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampRange, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampCurvature);
const char *paStrings[] = {"velspeed:", "velspeed*ramp:", "ramp:", "checkpoint:", "Pos", " x:", " y:", "angle:", "netobj corrections", " num:", " on:"};
const int Num = std::size(paStrings);
const char *apStrings[] = {"velspeed:", "velspeed.x*ramp:", "velspeed.y:", "ramp:", "checkpoint:", "Pos", " x:", " y:", "angle:", "netobj corrections", " num:", " on:"};
const int Num = std::size(apStrings);
const float LineHeight = 6.0f;
const float Fontsize = 5.0f;
float x = Width - 100.0f, y = 50.0f;
for(int i = 0; i < Num; ++i)
TextRender()->Text(0, x, y + i * LineHeight, Fontsize, paStrings[i], -1.0f);
TextRender()->Text(0, x, y + i * LineHeight, Fontsize, apStrings[i], -1.0f);
x = Width - 10.0f;
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "%.0f", Velspeed / 32);
str_format(aBuf, sizeof(aBuf), "%.2f Bps", Velspeed / 32);
float w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f);
TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f);
y += LineHeight;
str_format(aBuf, sizeof(aBuf), "%.0f", Velspeed / 32 * Ramp);
str_format(aBuf, sizeof(aBuf), "%.2f Bps", VelspeedX / 32 * Ramp);
w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f);
TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f);
y += LineHeight;
str_format(aBuf, sizeof(aBuf), "%.2f Bps", VelspeedY / 32);
w = TextRender()->TextWidth(0, Fontsize, aBuf, -1, -1.0f);
TextRender()->Text(0, x - w, y, Fontsize, aBuf, -1.0f);
y += LineHeight;
@ -125,25 +132,81 @@ void CDebugHud::RenderTuning()
Count++;
}
y = y + Count * 6;
// Rander Velspeed.X*Ramp Graphs
Graphics()->MapScreen(0, 0, Graphics()->ScreenWidth(), Graphics()->ScreenHeight());
float GraphW = Graphics()->ScreenWidth() / 4.0f;
float GraphH = Graphics()->ScreenHeight() / 6.0f;
float sp = Graphics()->ScreenWidth() / 100.0f;
float GraphX = GraphW;
float GraphY = Graphics()->ScreenHeight() - GraphH - sp;
Graphics()->TextureClear();
Graphics()->BlendNormal();
Graphics()->LinesBegin();
float Height = 50.0f;
float pv = 1;
IGraphics::CLineItem Array[100];
for(int i = 0; i < 100; i++)
CTuningParams *ClinetTuning = &m_pClient->m_Tuning[g_Config.m_ClDummy];
const int StepSizeRampGraph = 270;
const int StepSizeZoomedInGraph = 14;
if(m_OldVelrampStart != ClinetTuning->m_VelrampStart || m_OldVelrampRange != ClinetTuning->m_VelrampRange || m_OldVelrampCurvature != ClinetTuning->m_VelrampCurvature)
{
float Speed = i / 100.0f * 3000;
float Ramp = VelocityRamp(Speed, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampStart, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampRange, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampCurvature);
float RampedSpeed = (Speed * Ramp) / 1000.0f;
Array[i] = IGraphics::CLineItem((i - 1) * 2, y + Height - pv * Height, i * 2, y + Height - RampedSpeed * Height);
//Graphics()->LinesDraw((i-1)*2, 200, i*2, 200);
pv = RampedSpeed;
m_OldVelrampStart = ClinetTuning->m_VelrampStart;
m_OldVelrampRange = ClinetTuning->m_VelrampRange;
m_OldVelrampCurvature = ClinetTuning->m_VelrampCurvature;
m_RampGraph.Init(0.0f, 0.0f);
m_SpeedTurningPoint = 0;
float pv = 1;
// CGraph must be fed with exactly 128 values.
for(int i = 0; i < 128; i++)
{
// This is a calculation of the speed values per second on the X axis, from 270 to 34560 in steps of 270
float Speed = (i + 1) * StepSizeRampGraph;
float Ramp = VelocityRamp(Speed, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampStart, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampRange, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampCurvature);
float RampedSpeed = Speed * Ramp;
if(RampedSpeed >= pv)
{
m_RampGraph.InsertAt(i, RampedSpeed / 32, 0, 1, 0);
m_SpeedTurningPoint = Speed;
}
else
{
m_RampGraph.InsertAt(i, RampedSpeed / 32, 1, 0, 0);
}
pv = RampedSpeed;
}
m_RampGraph.ScaleMin();
m_RampGraph.ScaleMax();
m_ZoomedInGraph.Init(0.0f, 0.0f);
pv = 1;
MiddleOfZoomedInGraph = m_SpeedTurningPoint;
for(int i = 0; i < 128; i++)
{
// This is a calculation of the speed values per second on the X axis, from (MiddleOfZoomedInGraph - 64 * StepSize) to (MiddleOfZoomedInGraph + 64 * StepSize)
float Speed = MiddleOfZoomedInGraph - 64 * StepSizeZoomedInGraph + i * StepSizeZoomedInGraph;
float Ramp = VelocityRamp(Speed, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampStart, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampRange, m_pClient->m_Tuning[g_Config.m_ClDummy].m_VelrampCurvature);
float RampedSpeed = Speed * Ramp;
if(RampedSpeed >= pv)
{
m_ZoomedInGraph.InsertAt(i, RampedSpeed / 32, 0, 1, 0);
m_SpeedTurningPoint = Speed;
}
else
{
m_ZoomedInGraph.InsertAt(i, RampedSpeed / 32, 1, 0, 0);
}
if(i == 0)
{
m_ZoomedInGraph.m_Min = m_ZoomedInGraph.m_MinRange = RampedSpeed;
}
pv = RampedSpeed;
}
m_ZoomedInGraph.ScaleMin();
m_ZoomedInGraph.ScaleMax();
}
Graphics()->LinesDraw(Array, 100);
Graphics()->LinesEnd();
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Velspeed.X*Ramp in Bps (Velspeed %d to %d)", StepSizeRampGraph / 32, 128 * StepSizeRampGraph / 32);
m_RampGraph.Render(Graphics(), Client()->GetDebugFont(), GraphX, GraphY - GraphH - sp, GraphW, GraphH, aBuf);
str_format(aBuf, sizeof(aBuf), "Max Velspeed before it ramps off: %.2f Bps", m_SpeedTurningPoint / 32);
TextRender()->Text(0x0, GraphX, GraphY - sp - GraphH - 12, 12, aBuf, -1.0f);
str_format(aBuf, sizeof(aBuf), "Zoomed in on turning point (Velspeed %d to %d)", ((int)MiddleOfZoomedInGraph - 64 * StepSizeZoomedInGraph) / 32, ((int)MiddleOfZoomedInGraph + 64 * StepSizeZoomedInGraph) / 32);
m_ZoomedInGraph.Render(Graphics(), Client()->GetDebugFont(), GraphX, GraphY, GraphW, GraphH, aBuf);
TextRender()->TextColor(1, 1, 1, 1);
}

View file

@ -2,6 +2,8 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef GAME_CLIENT_COMPONENTS_DEBUGHUD_H
#define GAME_CLIENT_COMPONENTS_DEBUGHUD_H
#include <engine/client/client.h>
#include <game/client/component.h>
class CDebugHud : public CComponent
@ -10,6 +12,14 @@ class CDebugHud : public CComponent
void RenderTuning();
void RenderHint();
CGraph m_RampGraph;
CGraph m_ZoomedInGraph;
float m_SpeedTurningPoint;
float MiddleOfZoomedInGraph;
float m_OldVelrampStart;
float m_OldVelrampRange;
float m_OldVelrampCurvature;
public:
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnRender() override;

View file

@ -0,0 +1,239 @@
#include <game/client/gameclient.h>
#include "freezebars.h"
void CFreezeBars::RenderFreezeBar(const int ClientID)
{
const float FreezeBarWidth = 64.0f;
const float FreezeBarHalfWidth = 32.0f;
const float FreezeBarHight = 16.0f;
// pCharacter contains the predicted character for local players or the last snap for players who are spectated
CCharacterCore *pCharacter = &m_pClient->m_aClients[ClientID].m_Predicted;
if(pCharacter->m_FreezeEnd <= 0.0f || !m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo || pCharacter->m_IsInFreeze)
{
return;
}
const int Max = pCharacter->m_FreezeEnd - pCharacter->m_FreezeTick;
float FreezeProgress = clamp(Max - (Client()->GameTick(g_Config.m_ClDummy) - pCharacter->m_FreezeTick), 0, Max) / (float)Max;
if(FreezeProgress <= 0.0f)
{
return;
}
vec2 Position = m_pClient->m_aClients[ClientID].m_RenderPos;
Position.x -= FreezeBarHalfWidth;
Position.y += 32;
float Alpha = m_pClient->IsOtherTeam(ClientID) ? g_Config.m_ClShowOthersAlpha / 100.0f : 1.0f;
RenderFreezeBarPos(Position.x, Position.y, FreezeBarWidth, FreezeBarHight, FreezeProgress, Alpha);
}
void CFreezeBars::RenderFreezeBarPos(float x, const float y, const float width, const float height, float Progress, const float Alpha)
{
Progress = clamp(Progress, 0.0f, 1.0f);
// what percentage of the end pieces is used for the progress indicator and how much is the rest
// half of the ends are used for the progress display
const float RestPct = 0.5f;
const float ProgPct = 0.5f;
const float EndWidth = height; // to keep the correct scale - the height of the sprite is as long as the width
const float BarHeight = height;
const float WholeBarWidth = width;
const float MiddleBarWidth = WholeBarWidth - (EndWidth * 2.0f);
const float EndProgressWidth = EndWidth * ProgPct;
const float EndRestWidth = EndWidth * RestPct;
const float ProgressBarWidth = WholeBarWidth - (EndProgressWidth * 2.0f);
const float EndProgressProportion = EndProgressWidth / ProgressBarWidth;
const float MiddleProgressProportion = MiddleBarWidth / ProgressBarWidth;
// we cut 2% of all sides of all sprites so we don't get edge bleeding
const float CutL = 0.02f;
const float CutR = 0.98f;
const float CutT = 0.02f;
const float CutB = 0.98f;
const float Slice = 0.02f;
// beginning piece
float BeginningPieceProgress = 1;
if(Progress <= EndProgressProportion)
{
BeginningPieceProgress = Progress / EndProgressProportion;
}
// full
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarFullLeft);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// Subset: top_l, top_m, btm_m, btm_l
Graphics()->QuadsSetSubsetFree(CutL, CutT, RestPct + (ProgPct - CutL) * BeginningPieceProgress, CutT, RestPct + (ProgPct - CutL) * BeginningPieceProgress, CutB, CutL, CutB);
IGraphics::CQuadItem QuadFullBeginning(x, y, EndRestWidth + EndProgressWidth * BeginningPieceProgress, BarHeight);
Graphics()->QuadsDrawTL(&QuadFullBeginning, 1);
Graphics()->QuadsEnd();
// empty
if(BeginningPieceProgress < 1.0f)
{
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarEmptyRight);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// Subset: top_m, top_l, btm_l, btm_m | it is mirrored on the horizontal axe and rotated 180 degrees
Graphics()->QuadsSetSubsetFree(ProgPct - (ProgPct - CutL) * BeginningPieceProgress, CutT, CutL, CutT, CutL, CutB, ProgPct - (ProgPct - CutL) * BeginningPieceProgress, CutB);
IGraphics::CQuadItem QuadEmptyBeginning(x + EndRestWidth + EndProgressWidth * BeginningPieceProgress, y, EndProgressWidth * (1.0f - BeginningPieceProgress), BarHeight);
Graphics()->QuadsDrawTL(&QuadEmptyBeginning, 1);
Graphics()->QuadsEnd();
}
// middle piece
x += EndWidth;
float MiddlePieceProgress = 1;
if(Progress <= EndProgressProportion + MiddleProgressProportion)
{
if(Progress <= EndProgressProportion)
{
MiddlePieceProgress = 0;
}
else
{
MiddlePieceProgress = (Progress - EndProgressProportion) / MiddleProgressProportion;
}
}
const float FullMiddleBarWidth = MiddleBarWidth * MiddlePieceProgress;
const float EmptyMiddleBarWidth = MiddleBarWidth - FullMiddleBarWidth;
// full freeze bar
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarFull);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// select the middle portion of the sprite so we don't get edge bleeding
if(FullMiddleBarWidth <= EndWidth)
{
// prevent pixel puree, select only a small slice
// Subset: top_l, top_m, btm_m, btm_l
Graphics()->QuadsSetSubsetFree(CutL, CutT, CutL + Slice, CutT, CutL + Slice, CutB, CutL, CutB);
}
else
{
// Subset: top_l, top_r, btm_r, btm_l
Graphics()->QuadsSetSubsetFree(CutL, CutT, CutR, CutT, CutR, CutB, CutL, CutB);
}
IGraphics::CQuadItem QuadFull(x, y, FullMiddleBarWidth, BarHeight);
Graphics()->QuadsDrawTL(&QuadFull, 1);
Graphics()->QuadsEnd();
// empty freeze bar
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarEmpty);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// select the middle portion of the sprite so we don't get edge bleeding
if(EmptyMiddleBarWidth <= EndWidth)
{
// prevent pixel puree, select only a small slice
// Subset: top_m, top_l, btm_l, btm_m | it is mirrored on the horizontal axe and rotated 180 degrees
Graphics()->QuadsSetSubsetFree(CutL + Slice, CutT, CutL, CutT, CutL, CutB, CutL + Slice, CutB);
}
else
{
// Subset: top_r, top_l, btm_l, btm_r | it is mirrored on the horizontal axe and rotated 180 degrees
Graphics()->QuadsSetSubsetFree(CutR, CutT, CutL, CutT, CutL, CutB, CutR, CutB);
}
IGraphics::CQuadItem QuadEmpty(x + FullMiddleBarWidth, y, EmptyMiddleBarWidth, BarHeight);
Graphics()->QuadsDrawTL(&QuadEmpty, 1);
Graphics()->QuadsEnd();
// end piece
x += MiddleBarWidth;
float EndingPieceProgress = 1;
if(Progress <= 1)
{
if(Progress <= (EndProgressProportion + MiddleProgressProportion))
{
EndingPieceProgress = 0;
}
else
{
EndingPieceProgress = (Progress - EndProgressProportion - MiddleProgressProportion) / EndProgressProportion;
}
}
if(EndingPieceProgress > 0.0f)
{
// full
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarFullLeft);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// Subset: top_r, top_m, btm_m, btm_r | it is mirrored on the horizontal axe and rotated 180 degrees
Graphics()->QuadsSetSubsetFree(CutR, CutT, CutR - (ProgPct - CutL) * EndingPieceProgress, CutT, CutR - (ProgPct - CutL) * EndingPieceProgress, CutB, CutR, CutB);
IGraphics::CQuadItem QuadFullEnding(x, y, EndProgressWidth * EndingPieceProgress, BarHeight);
Graphics()->QuadsDrawTL(&QuadFullEnding, 1);
Graphics()->QuadsEnd();
}
// empty
Graphics()->TextureSet(m_pClient->m_HudSkin.m_SpriteHudFreezeBarEmptyRight);
Graphics()->QuadsBegin();
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
// Subset: top_m, top_r, btm_r, btm_m
Graphics()->QuadsSetSubsetFree(ProgPct - (ProgPct - CutL) * (1.0f - EndingPieceProgress), CutT, CutR, CutT, CutR, CutB, ProgPct - (ProgPct - CutL) * (1.0f - EndingPieceProgress), CutB);
IGraphics::CQuadItem QuadEmptyEnding(x + EndProgressWidth * EndingPieceProgress, y, EndProgressWidth * (1.0f - EndingPieceProgress) + EndRestWidth, BarHeight);
Graphics()->QuadsDrawTL(&QuadEmptyEnding, 1);
Graphics()->QuadsEnd();
Graphics()->QuadsSetSubset(0, 0, 1, 1);
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
}
inline bool CFreezeBars::IsPlayerInfoAvailable(int ClientID) const
{
const void *pPrevInfo = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_PLAYERINFO, ClientID);
const void *pInfo = Client()->SnapFindItem(IClient::SNAP_CURRENT, NETOBJTYPE_PLAYERINFO, ClientID);
return pPrevInfo && pInfo;
}
void CFreezeBars::OnRender()
{
if(!g_Config.m_ClShowFreezeBars)
{
return;
}
// get screen edges to avoid rendering offscreen
float ScreenX0, ScreenY0, ScreenX1, ScreenY1;
Graphics()->GetScreen(&ScreenX0, &ScreenY0, &ScreenX1, &ScreenY1);
// expand the edges to prevent popping in/out onscreen
//
// it is assumed that the tee with the freeze bar fit into a 240x240 box centered on the tee
// this may need to be changed or calculated differently in the future
float BorderBuffer = 120;
ScreenX0 -= BorderBuffer;
ScreenX1 += BorderBuffer;
ScreenY0 -= BorderBuffer;
ScreenY1 += BorderBuffer;
int LocalClientID = m_pClient->m_Snap.m_LocalClientID;
// render everyone else's freeze bar, then our own
for(int ClientID = 0; ClientID < MAX_CLIENTS; ClientID++)
{
if(ClientID == LocalClientID || !m_pClient->m_Snap.m_aCharacters[ClientID].m_Active || !IsPlayerInfoAvailable(ClientID))
{
continue;
}
//don't render if the tee is offscreen
vec2 *pRenderPos = &m_pClient->m_aClients[ClientID].m_RenderPos;
if(pRenderPos->x < ScreenX0 || pRenderPos->x > ScreenX1 || pRenderPos->y < ScreenY0 || pRenderPos->y > ScreenY1)
{
continue;
}
RenderFreezeBar(ClientID);
}
if(LocalClientID != -1 && m_pClient->m_Snap.m_aCharacters[LocalClientID].m_Active && IsPlayerInfoAvailable(LocalClientID))
{
RenderFreezeBar(LocalClientID);
}
}

View file

@ -0,0 +1,16 @@
#ifndef GAME_CLIENT_COMPONENTS_FREEZEBARS_H
#define GAME_CLIENT_COMPONENTS_FREEZEBARS_H
#include <game/client/component.h>
class CFreezeBars : public CComponent
{
void RenderFreezeBar(const int ClientID);
void RenderFreezeBarPos(float x, const float y, const float width, const float height, float Progress, float Alpha = 1.0f);
bool IsPlayerInfoAvailable(int ClientID) const;
public:
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnRender() override;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -49,8 +49,13 @@ class CHud : public CComponent
void RenderTeambalanceWarning();
void RenderVoting();
void PrepareHealthAmoQuads();
void RenderHealthAndAmmo(const CNetObj_Character *pCharacter);
void PrepareAmmoHealthAndArmorQuads();
void RenderAmmoHealthAndArmor(const CNetObj_Character *pCharacter);
void PreparePlayerStateQuads();
void RenderPlayerState(const int ClientID);
void RenderDummyActions();
void RenderMovementInformation(const int ClientID);
void RenderGameTimer();
void RenderPauseNotification();
@ -62,6 +67,8 @@ class CHud : public CComponent
void MapscreenToGroup(float CenterX, float CenterY, struct CMapItemGroup *PGroup);
static constexpr float MOVEMENT_INFORMATION_LINE_HEIGHT = 8.0f;
public:
CHud();
virtual int Sizeof() const override { return sizeof(*this); }
@ -75,6 +82,7 @@ public:
// DDRace
virtual void OnMessage(int MsgType, void *pRawMsg) override;
void RenderNinjaBarPos(float x, const float y, const float width, const float height, float Progress, float Alpha = 1.0f);
private:
void RenderRecord();
@ -87,6 +95,44 @@ private:
int m_CheckpointTick;
bool m_FinishTime;
bool m_DDRaceTimeReceived;
inline float GetMovementInformationBoxHeight();
inline int GetDigitsIndex(int Value, int Max);
// Quad Offsets
int m_AmmoOffset[NUM_WEAPONS];
int m_HealthOffset;
int m_EmptyHealthOffset;
int m_ArmorOffset;
int m_EmptyArmorOffset;
int m_CursorOffset[NUM_WEAPONS];
int m_FlagOffset;
int m_AirjumpOffset;
int m_AirjumpEmptyOffset;
int m_WeaponHammerOffset;
int m_WeaponGunOffset;
int m_WeaponShotgunOffset;
int m_WeaponGrenadeOffset;
int m_WeaponLaserOffset;
int m_WeaponNinjaOffset;
int m_EndlessJumpOffset;
int m_EndlessHookOffset;
int m_JetpackOffset;
int m_TeleportGrenadeOffset;
int m_TeleportGunOffset;
int m_TeleportLaserOffset;
int m_SoloOffset;
int m_NoCollisionOffset;
int m_NoHookHitOffset;
int m_NoHammerHitOffset;
int m_NoShotgunHitOffset;
int m_NoGrenadeHitOffset;
int m_NoLaserHitOffset;
int m_DeepFrozenOffset;
int m_LiveFrozenOffset;
int m_DummyHammerOffset;
int m_DummyCopyOffset;
int m_PracticeModeOffset;
};
#endif

View file

@ -128,74 +128,46 @@ void CItems::RenderProjectile(const CProjectileData *pCurrent, int ItemID)
{
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteWeaponProjectiles[CurWeapon]);
Graphics()->SetColor(1.f, 1.f, 1.f, Alpha);
int QuadOffset = 2 + 8 + NUM_WEAPONS + CurWeapon;
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y);
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ProjectileOffset[CurWeapon], Pos.x, Pos.y);
}
}
void CItems::RenderPickup(const CNetObj_Pickup *pPrev, const CNetObj_Pickup *pCurrent, bool IsPredicted)
{
const int c[] = {
SPRITE_PICKUP_HEALTH,
SPRITE_PICKUP_ARMOR,
SPRITE_PICKUP_WEAPON,
SPRITE_PICKUP_NINJA,
SPRITE_PICKUP_ARMOR_SHOTGUN,
SPRITE_PICKUP_ARMOR_GRENADE,
SPRITE_PICKUP_ARMOR_NINJA,
SPRITE_PICKUP_ARMOR_LASER};
int CurWeapon = clamp(pCurrent->m_Subtype, 0, NUM_WEAPONS - 1);
if(c[pCurrent->m_Type] == SPRITE_PICKUP_HEALTH)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupHealth);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_ARMOR)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmor);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_ARMOR_SHOTGUN)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmorShotgun);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_ARMOR_GRENADE)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmorGrenade);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_ARMOR_LASER)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmorLaser);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_ARMOR_NINJA)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmorNinja);
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_WEAPON)
{
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeapons[CurWeapon]);
}
else if(c[pCurrent->m_Type] == SPRITE_PICKUP_NINJA)
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupNinja);
Graphics()->QuadsSetRotation(0);
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
int QuadOffset = 2;
float Angle = 0.0f;
float IntraTick = IsPredicted ? Client()->PredIntraGameTick(g_Config.m_ClDummy) : Client()->IntraGameTick(g_Config.m_ClDummy);
vec2 Pos = mix(vec2(pPrev->m_X, pPrev->m_Y), vec2(pCurrent->m_X, pCurrent->m_Y), IntraTick);
float Angle = 0.0f;
if(pCurrent->m_Type == POWERUP_WEAPON)
if(pCurrent->m_Type == POWERUP_HEALTH)
{
Angle = 0; //-pi/6;//-0.25f * pi * 2.0f;
QuadOffset += 2 + CurWeapon;
QuadOffset = m_PickupHealthOffset;
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupHealth);
}
else
else if(pCurrent->m_Type == POWERUP_ARMOR)
{
QuadOffset += pCurrent->m_Type;
if(c[pCurrent->m_Type] == SPRITE_PICKUP_NINJA)
{
QuadOffset = 2 + 8 - 1; // ninja is the last weapon
m_pClient->m_Effects.PowerupShine(Pos, vec2(96, 18));
Pos.x -= 10.0f;
}
else if(c[pCurrent->m_Type] >= SPRITE_PICKUP_ARMOR_SHOTGUN && c[pCurrent->m_Type] <= SPRITE_PICKUP_ARMOR_NINJA)
{
QuadOffset = m_WeaponArmorQuadOffset + (c[pCurrent->m_Type] - SPRITE_PICKUP_ARMOR_SHOTGUN);
}
QuadOffset = m_PickupArmorOffset;
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupArmor);
}
else if(pCurrent->m_Type == POWERUP_WEAPON)
{
QuadOffset = m_PickupWeaponOffset[CurWeapon];
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeapons[CurWeapon]);
}
else if(pCurrent->m_Type == POWERUP_NINJA)
{
QuadOffset = m_PickupNinjaOffset;
m_pClient->m_Effects.PowerupShine(Pos, vec2(96, 18));
Pos.x -= 10.0f;
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupNinja);
}
else if(pCurrent->m_Type >= POWERUP_ARMOR_SHOTGUN && pCurrent->m_Type <= POWERUP_ARMOR_LASER)
{
QuadOffset = m_PickupWeaponArmorOffset[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN];
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpritePickupWeaponArmor[pCurrent->m_Type - POWERUP_ARMOR_SHOTGUN]);
}
Graphics()->QuadsSetRotation(0);
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
Graphics()->QuadsSetRotation(Angle);
static float s_Time = 0.0f;
@ -230,10 +202,15 @@ void CItems::RenderFlag(const CNetObj_Flag *pPrev, const CNetObj_Flag *pCurrent,
Graphics()->TextureSet(GameClient()->m_GameSkin.m_SpriteFlagBlue);
Graphics()->QuadsSetRotation(0);
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
int QuadOffset = 0;
if(pCurrent->m_Team != TEAM_RED)
++QuadOffset;
int QuadOffset;
if(pCurrent->m_Team == TEAM_RED)
{
QuadOffset = m_RedFlagOffset;
}
else
{
QuadOffset = m_BlueFlagOffset;
}
Graphics()->QuadsSetRotation(Angle);
@ -317,14 +294,12 @@ void CItems::RenderLaser(const struct CNetObj_Laser *pCurrent, bool IsPredicted)
// render head
{
int CurParticle = (Client()->GameTick(g_Config.m_ClDummy) % 3);
int QuadOffset = 2 + 8 + NUM_WEAPONS * 2 + CurParticle;
Graphics()->TextureSet(GameClient()->m_ParticlesSkin.m_SpriteParticleSplat[CurParticle]);
Graphics()->QuadsSetRotation(Client()->GameTick(g_Config.m_ClDummy));
Graphics()->SetColor(OuterColor.r, OuterColor.g, OuterColor.b, 1.0f);
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y);
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ParticleSplatOffset[CurParticle], Pos.x, Pos.y);
Graphics()->SetColor(InnerColor.r, InnerColor.g, InnerColor.b, 1.0f);
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, QuadOffset, Pos.x, Pos.y, 20.f / 24.f, 20.f / 24.f);
Graphics()->RenderQuadContainerAsSprite(m_ItemsQuadContainerIndex, m_ParticleSplatOffset[CurParticle], Pos.x, Pos.y, 20.f / 24.f, 20.f / 24.f);
}
}
@ -515,68 +490,46 @@ void CItems::OnInit()
m_ItemsQuadContainerIndex = Graphics()->CreateQuadContainer(false);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
m_RedFlagOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
m_BlueFlagOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, -21.f, -42.f, 42.f, 84.f);
float ScaleX, ScaleY;
RenderTools()->GetSpriteScale(SPRITE_PICKUP_HEALTH, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
m_PickupHealthOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
RenderTools()->GetSpriteScale(&client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_HAMMER], ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, client_data7::g_pData->m_Weapons.m_aId[WEAPON_HAMMER].m_VisualSize * ScaleX, client_data7::g_pData->m_Weapons.m_aId[WEAPON_HAMMER].m_VisualSize * ScaleY);
RenderTools()->GetSpriteScale(&client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_GUN], ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, client_data7::g_pData->m_Weapons.m_aId[WEAPON_GUN].m_VisualSize * ScaleX, client_data7::g_pData->m_Weapons.m_aId[WEAPON_GUN].m_VisualSize * ScaleY);
RenderTools()->GetSpriteScale(&client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_SHOTGUN], ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, client_data7::g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_VisualSize * ScaleX, client_data7::g_pData->m_Weapons.m_aId[WEAPON_SHOTGUN].m_VisualSize * ScaleY);
RenderTools()->GetSpriteScale(&client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_GRENADE], ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, client_data7::g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_VisualSize * ScaleX, client_data7::g_pData->m_Weapons.m_aId[WEAPON_GRENADE].m_VisualSize * ScaleY);
RenderTools()->GetSpriteScale(&client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_LASER], ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, client_data7::g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize * ScaleX, client_data7::g_pData->m_Weapons.m_aId[WEAPON_LASER].m_VisualSize * ScaleY);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_NINJA, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 128.f * ScaleX, 128.f * ScaleY);
m_PickupArmorOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
for(int i = 0; i < NUM_WEAPONS; ++i)
{
RenderTools()->GetSpriteScale(g_pData->m_Weapons.m_aId[i].m_pSpriteBody, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleX, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleY);
m_PickupWeaponOffset[i] = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleX, g_pData->m_Weapons.m_aId[i].m_VisualSize * ScaleY);
}
RenderTools()->GetSpriteScale(SPRITE_PICKUP_NINJA, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
m_PickupNinjaOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 128.f * ScaleX, 128.f * ScaleY);
for(int i = 0; i < 4; i++)
{
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_SHOTGUN + i, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
m_PickupWeaponArmorOffset[i] = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
}
for(int i = 0; i < NUM_WEAPONS; ++i)
for(int &ProjectileOffset : m_ProjectileOffset)
{
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 32.f);
ProjectileOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 32.f);
}
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 24.f);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 24.f);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 24.f);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_SHOTGUN, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
m_WeaponArmorQuadOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_GRENADE, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_NINJA, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
RenderTools()->GetSpriteScale(SPRITE_PICKUP_ARMOR_LASER, ScaleX, ScaleY);
Graphics()->QuadsSetSubset(0, 0, 1, 1);
RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 64.f * ScaleX, 64.f * ScaleY);
for(int &ParticleSplatOffset : m_ParticleSplatOffset)
{
Graphics()->QuadsSetSubset(0, 0, 1, 1);
ParticleSplatOffset = RenderTools()->QuadContainerAddSprite(m_ItemsQuadContainerIndex, 24.f);
}
Graphics()->QuadContainerUpload(m_ItemsQuadContainerIndex);
}

View file

@ -3,6 +3,7 @@
#ifndef GAME_CLIENT_COMPONENTS_ITEMS_H
#define GAME_CLIENT_COMPONENTS_ITEMS_H
#include <game/client/component.h>
#include <game/generated/protocol.h>
class CProjectileData;
@ -15,14 +16,23 @@ class CItems : public CComponent
int m_ItemsQuadContainerIndex;
int m_WeaponArmorQuadOffset = 0;
public:
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnRender() override;
virtual void OnInit() override;
void ReconstructSmokeTrail(const CProjectileData *pCurrent, int DestroyTick);
private:
int m_BlueFlagOffset;
int m_RedFlagOffset;
int m_PickupHealthOffset;
int m_PickupArmorOffset;
int m_PickupWeaponOffset[NUM_WEAPONS];
int m_PickupNinjaOffset;
int m_PickupWeaponArmorOffset[4];
int m_ProjectileOffset[NUM_WEAPONS];
int m_ParticleSplatOffset[3];
};
#endif

View file

@ -1038,6 +1038,7 @@ void CMenus::OnInit()
Console()->Chain("cl_asset_game", ConchainAssetGame, this);
Console()->Chain("cl_asset_emoticons", ConchainAssetEmoticons, this);
Console()->Chain("cl_asset_particles", ConchainAssetParticles, this);
Console()->Chain("cl_asset_hud", ConchainAssetHud, this);
m_TextureBlob = Graphics()->LoadTexture("blob.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);

View file

@ -246,11 +246,16 @@ public:
{
};
struct SCustomHud : public SCustomItem
{
};
protected:
sorted_array<SCustomEntities> m_EntitiesList;
sorted_array<SCustomGame> m_GameList;
sorted_array<SCustomEmoticon> m_EmoticonList;
sorted_array<SCustomParticle> m_ParticlesList;
sorted_array<SCustomHud> m_HudList;
bool m_IsInit = false;
@ -260,11 +265,13 @@ protected:
static int GameScan(const char *pName, int IsDir, int DirType, void *pUser);
static int EmoticonsScan(const char *pName, int IsDir, int DirType, void *pUser);
static int ParticlesScan(const char *pName, int IsDir, int DirType, void *pUser);
static int HudScan(const char *pName, int IsDir, int DirType, void *pUser);
static void ConchainAssetsEntities(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainAssetGame(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainAssetParticles(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainAssetEmoticons(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainAssetHud(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
void ClearCustomItems(int CurTab);

View file

@ -2354,8 +2354,14 @@ void CMenus::RenderSettingsHUD(CUIRect MainView)
// ***** HUD ***** //
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhud, Localize("Show ingame HUD"), &g_Config.m_ClShowhud, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClDDRaceHud, Localize("Use DDRace HUD"), &g_Config.m_ClDDRaceHud, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClDDRaceScoreBoard, Localize("Use DDRace Scoreboard"), &g_Config.m_ClDDRaceScoreBoard, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudDummyActions, Localize("Show dummy actions"), &g_Config.m_ClShowhudDummyActions, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowFreezeBars, Localize("Show freeze bars"), &g_Config.m_ClShowFreezeBars, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowIDs, Localize("Show client IDs"), &g_Config.m_ClShowIDs, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudPlayerPosition, Localize("Show player position"), &g_Config.m_ClShowhudPlayerPosition, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudPlayerSpeed, Localize("Show player speed"), &g_Config.m_ClShowhudPlayerSpeed, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudPlayerAngle, Localize("Show player target angle"), &g_Config.m_ClShowhudPlayerAngle, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudScore, Localize("Show score"), &g_Config.m_ClShowhudScore, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowhudHealthAmmo, Localize("Show health + ammo"), &g_Config.m_ClShowhudHealthAmmo, &MainView, LineMargin);
DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClShowChat, Localize("Show chat"), &g_Config.m_ClShowChat, &MainView, LineMargin);

View file

@ -15,6 +15,16 @@ struct SMenuAssetScanUser
TMenuAssetScanLoadedFunc m_LoadedFunc;
};
// IDs of the tabs in the Assets menu
enum
{
ASSETS_TAB_ENTITIES = 0,
ASSETS_TAB_GAME = 1,
ASSETS_TAB_EMOTICONS = 2,
ASSETS_TAB_PARTICLES = 3,
ASSETS_TAB_HUD = 4
};
void CMenus::LoadEntities(SCustomEntities *pEntitiesItem, void *pUser)
{
auto *pRealUser = (SMenuAssetScanUser *)pUser;
@ -208,33 +218,44 @@ int CMenus::ParticlesScan(const char *pName, int IsDir, int DirType, void *pUser
return AssetScan(pName, IsDir, DirType, pThis->m_ParticlesList, "particles", pGraphics, pUser);
}
int CMenus::HudScan(const char *pName, int IsDir, int DirType, void *pUser)
{
CMenus *pMenus = (CMenus *)pUser;
IGraphics *pGraphics = pMenus->Graphics();
return AssetScan(pName, IsDir, DirType, pMenus->m_HudList, "hud", pGraphics, pUser);
}
static sorted_array<const CMenus::SCustomEntities *> s_SearchEntitiesList;
static sorted_array<const CMenus::SCustomGame *> s_SearchGamesList;
static sorted_array<const CMenus::SCustomEmoticon *> s_SearchEmoticonsList;
static sorted_array<const CMenus::SCustomParticle *> s_SearchParticlesList;
static sorted_array<const CMenus::SCustomHud *> s_SearchHudList;
static bool s_InitCustomList[4] = {
static const int NumberOfAssetsTabs = 5;
static bool s_InitCustomList[NumberOfAssetsTabs] = {
true,
};
static int s_CustomListSize[4] = {
static int s_CustomListSize[NumberOfAssetsTabs] = {
0,
};
static char s_aFilterString[4][50];
static char s_aFilterString[NumberOfAssetsTabs][50];
static int s_CurCustomTab = 0;
static int s_CurCustomTab = ASSETS_TAB_ENTITIES;
static const CMenus::SCustomItem *GetCustomItem(int CurTab, int Index)
{
if(CurTab == 0)
if(CurTab == ASSETS_TAB_ENTITIES)
return s_SearchEntitiesList[Index];
else if(CurTab == 1)
else if(CurTab == ASSETS_TAB_GAME)
return s_SearchGamesList[Index];
else if(CurTab == 2)
else if(CurTab == ASSETS_TAB_EMOTICONS)
return s_SearchEmoticonsList[Index];
else if(CurTab == 3)
else if(CurTab == ASSETS_TAB_PARTICLES)
return s_SearchParticlesList[Index];
else if(CurTab == ASSETS_TAB_HUD)
return s_SearchHudList[Index];
return NULL;
}
@ -253,7 +274,7 @@ void ClearAssetList(sorted_array<TName> &List, IGraphics *pGraphics)
void CMenus::ClearCustomItems(int CurTab)
{
if(CurTab == 0)
if(CurTab == ASSETS_TAB_ENTITIES)
{
for(int i = 0; i < m_EntitiesList.size(); ++i)
{
@ -269,27 +290,34 @@ void CMenus::ClearCustomItems(int CurTab)
// reload current entities
m_pClient->m_MapImages.ChangeEntitiesPath(g_Config.m_ClAssetsEntites);
}
else if(CurTab == 1)
else if(CurTab == ASSETS_TAB_GAME)
{
ClearAssetList(m_GameList, Graphics());
// reload current game skin
GameClient()->LoadGameSkin(g_Config.m_ClAssetGame);
}
else if(CurTab == 2)
else if(CurTab == ASSETS_TAB_EMOTICONS)
{
ClearAssetList(m_EmoticonList, Graphics());
// reload current emoticons skin
GameClient()->LoadEmoticonsSkin(g_Config.m_ClAssetEmoticons);
}
else if(CurTab == 3)
else if(CurTab == ASSETS_TAB_PARTICLES)
{
ClearAssetList(m_ParticlesList, Graphics());
// reload current particles skin
GameClient()->LoadParticlesSkin(g_Config.m_ClAssetParticles);
}
else if(CurTab == ASSETS_TAB_HUD)
{
ClearAssetList(m_HudList, Graphics());
// reload current hud skin
GameClient()->LoadHudSkin(g_Config.m_ClAssetHud);
}
s_InitCustomList[CurTab] = true;
}
@ -330,24 +358,27 @@ int InitSearchList(sorted_array<const TName *> &SearchList, sorted_array<TName>
void CMenus::RenderSettingsCustom(CUIRect MainView)
{
CUIRect Label, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, Page1Tab, Page2Tab, Page3Tab, Page4Tab, ReloadButton;
CUIRect Label, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, Page1Tab, Page2Tab, Page3Tab, Page4Tab, Page5Tab, ReloadButton;
MainView.HSplitTop(20, &Label, &MainView);
float TabsW = Label.w;
Label.VSplitLeft(TabsW / 4, &Page1Tab, &Page2Tab);
Page2Tab.VSplitLeft(TabsW / 4, &Page2Tab, &Page3Tab);
Page3Tab.VSplitLeft(TabsW / 4, &Page3Tab, &Page4Tab);
Label.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page1Tab, &Page2Tab);
Page2Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page2Tab, &Page3Tab);
Page3Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page3Tab, &Page4Tab);
Page4Tab.VSplitLeft(TabsW / NumberOfAssetsTabs, &Page4Tab, &Page5Tab);
static int s_aPageTabs[4] = {};
static int s_aPageTabs[NumberOfAssetsTabs] = {};
if(DoButton_MenuTab((void *)&s_aPageTabs[0], Localize("Entities"), s_CurCustomTab == 0, &Page1Tab, 5, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = 0;
if(DoButton_MenuTab((void *)&s_aPageTabs[1], Localize("Game"), s_CurCustomTab == 1, &Page2Tab, 0, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = 1;
if(DoButton_MenuTab((void *)&s_aPageTabs[2], Localize("Emoticons"), s_CurCustomTab == 2, &Page3Tab, 0, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = 2;
if(DoButton_MenuTab((void *)&s_aPageTabs[3], Localize("Particles"), s_CurCustomTab == 3, &Page4Tab, 10, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = 3;
if(DoButton_MenuTab((void *)&s_aPageTabs[0], Localize("Entities"), s_CurCustomTab == ASSETS_TAB_ENTITIES, &Page1Tab, 5, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = ASSETS_TAB_ENTITIES;
if(DoButton_MenuTab((void *)&s_aPageTabs[1], Localize("Game"), s_CurCustomTab == ASSETS_TAB_GAME, &Page2Tab, 0, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = ASSETS_TAB_GAME;
if(DoButton_MenuTab((void *)&s_aPageTabs[2], Localize("Emoticons"), s_CurCustomTab == ASSETS_TAB_EMOTICONS, &Page3Tab, 0, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = ASSETS_TAB_EMOTICONS;
if(DoButton_MenuTab((void *)&s_aPageTabs[3], Localize("Particles"), s_CurCustomTab == ASSETS_TAB_PARTICLES, &Page4Tab, 0, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = ASSETS_TAB_PARTICLES;
if(DoButton_MenuTab((void *)&s_aPageTabs[4], Localize("HUD"), s_CurCustomTab == ASSETS_TAB_HUD, &Page5Tab, 10, NULL, NULL, NULL, NULL, 4))
s_CurCustomTab = ASSETS_TAB_HUD;
int64_t LoadStartTime = time_get_microseconds();
SMenuAssetScanUser User;
@ -356,7 +387,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
if(time_get_microseconds() - LoadStartTime > 500000)
RenderLoading(false, false);
};
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
{
if(m_EntitiesList.size() == 0)
{
@ -371,18 +402,22 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
if(m_EntitiesList.size() != s_CustomListSize[s_CurCustomTab])
s_InitCustomList[s_CurCustomTab] = true;
}
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
{
InitAssetList(m_GameList, "assets/game", "game", GameScan, Graphics(), Storage(), &User);
}
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
{
InitAssetList(m_EmoticonList, "assets/emoticons", "emoticons", EmoticonsScan, Graphics(), Storage(), &User);
}
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
{
InitAssetList(m_ParticlesList, "assets/particles", "particles", ParticlesScan, Graphics(), Storage(), &User);
}
else if(s_CurCustomTab == ASSETS_TAB_HUD)
{
InitAssetList(m_HudList, "assets/hud", "hud", HudScan, Graphics(), Storage(), this);
}
MainView.HSplitTop(10.0f, 0, &MainView);
@ -392,7 +427,7 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
if(s_InitCustomList[s_CurCustomTab])
{
int ListSize = 0;
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
{
s_SearchEntitiesList.clear();
ListSize = m_EntitiesList.size();
@ -407,18 +442,22 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
s_SearchEntitiesList.add_unsorted(s);
}
}
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
{
ListSize = InitSearchList(s_SearchGamesList, m_GameList);
}
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
{
ListSize = InitSearchList(s_SearchEmoticonsList, m_EmoticonList);
}
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
{
ListSize = InitSearchList(s_SearchParticlesList, m_ParticlesList);
}
else if(s_CurCustomTab == ASSETS_TAB_HUD)
{
ListSize = InitSearchList(s_SearchHudList, m_HudList);
}
s_InitCustomList[s_CurCustomTab] = false;
s_CustomListSize[s_CurCustomTab] = ListSize;
}
@ -430,23 +469,28 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
int SearchListSize = 0;
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
{
SearchListSize = s_SearchEntitiesList.size();
}
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
{
SearchListSize = s_SearchGamesList.size();
TextureHeight = 75;
}
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
{
SearchListSize = s_SearchEmoticonsList.size();
}
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
{
SearchListSize = s_SearchParticlesList.size();
}
else if(s_CurCustomTab == ASSETS_TAB_HUD)
{
SearchListSize = s_SearchHudList.size();
TextureHeight = 128;
}
UiDoListboxStart(&s_InitCustomList[s_CurCustomTab], &CustomList, TextureHeight + 15.0f + 10.0f + Margin, "", "", SearchListSize, CustomList.w / (Margin + TextureWidth), OldSelected, s_ScrollValue, true);
for(int i = 0; i < SearchListSize; ++i)
@ -455,26 +499,31 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
if(s == NULL)
continue;
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
{
if(str_comp(s->m_aName, g_Config.m_ClAssetsEntites) == 0)
OldSelected = i;
}
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
{
if(str_comp(s->m_aName, g_Config.m_ClAssetGame) == 0)
OldSelected = i;
}
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
{
if(str_comp(s->m_aName, g_Config.m_ClAssetEmoticons) == 0)
OldSelected = i;
}
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
{
if(str_comp(s->m_aName, g_Config.m_ClAssetParticles) == 0)
OldSelected = i;
}
else if(s_CurCustomTab == ASSETS_TAB_HUD)
{
if(str_comp(s->m_aName, g_Config.m_ClAssetHud) == 0)
OldSelected = i;
}
CListboxItem Item = UiDoListboxNextItem(s, OldSelected == i);
CUIRect ItemRect = Item.m_Rect;
@ -504,26 +553,31 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
{
if(GetCustomItem(s_CurCustomTab, NewSelected)->m_aName[0] != '\0')
{
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
{
str_copy(g_Config.m_ClAssetsEntites, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetsEntites));
m_pClient->m_MapImages.ChangeEntitiesPath(GetCustomItem(s_CurCustomTab, NewSelected)->m_aName);
}
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
{
str_copy(g_Config.m_ClAssetGame, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetGame));
GameClient()->LoadGameSkin(g_Config.m_ClAssetGame);
}
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
{
str_copy(g_Config.m_ClAssetEmoticons, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetEmoticons));
GameClient()->LoadEmoticonsSkin(g_Config.m_ClAssetEmoticons);
}
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
{
str_copy(g_Config.m_ClAssetParticles, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetParticles));
GameClient()->LoadParticlesSkin(g_Config.m_ClAssetParticles);
}
else if(s_CurCustomTab == ASSETS_TAB_HUD)
{
str_copy(g_Config.m_ClAssetHud, GetCustomItem(s_CurCustomTab, NewSelected)->m_aName, sizeof(g_Config.m_ClAssetHud));
GameClient()->LoadHudSkin(g_Config.m_ClAssetHud);
}
}
}
@ -567,14 +621,16 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
{
char aBuf[IO_MAX_PATH_LENGTH];
char aBufFull[IO_MAX_PATH_LENGTH + 7];
if(s_CurCustomTab == 0)
if(s_CurCustomTab == ASSETS_TAB_ENTITIES)
str_copy(aBufFull, "assets/entities", sizeof(aBufFull));
else if(s_CurCustomTab == 1)
else if(s_CurCustomTab == ASSETS_TAB_GAME)
str_copy(aBufFull, "assets/game", sizeof(aBufFull));
else if(s_CurCustomTab == 2)
else if(s_CurCustomTab == ASSETS_TAB_EMOTICONS)
str_copy(aBufFull, "assets/emoticons", sizeof(aBufFull));
else if(s_CurCustomTab == 3)
else if(s_CurCustomTab == ASSETS_TAB_PARTICLES)
str_copy(aBufFull, "assets/particles", sizeof(aBufFull));
else if(s_CurCustomTab == ASSETS_TAB_HUD)
str_copy(aBufFull, "assets/hud", sizeof(aBufFull));
Storage()->GetCompletePath(IStorage::TYPE_SAVE, aBufFull, aBuf, sizeof(aBuf));
Storage()->CreateFolder("assets", IStorage::TYPE_SAVE);
Storage()->CreateFolder(aBufFull, IStorage::TYPE_SAVE);
@ -654,3 +710,18 @@ void CMenus::ConchainAssetEmoticons(IConsole::IResult *pResult, void *pUserData,
pfnCallback(pResult, pCallbackUserData);
}
void CMenus::ConchainAssetHud(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
CMenus *pThis = (CMenus *)pUserData;
if(pResult->NumArguments() == 1)
{
const char *pArg = pResult->GetString(0);
if(str_comp(pArg, g_Config.m_ClAssetHud) != 0)
{
pThis->GameClient()->LoadHudSkin(pArg);
}
}
pfnCallback(pResult, pCallbackUserData);
}

View file

@ -378,10 +378,8 @@ void CNamePlates::OnInit()
{
ResetNamePlates();
// the direction
// Quad for the direction arrows above the player
m_DirectionQuadContainerIndex = Graphics()->CreateQuadContainer(false);
IGraphics::CQuadItem QuadItem(0.f, 0.f, 22.f, 22.f);
Graphics()->QuadContainerAddQuads(m_DirectionQuadContainerIndex, &QuadItem, 1);
RenderTools()->QuadContainerAddSprite(m_DirectionQuadContainerIndex, 0.f, 0.f, 22.f);
Graphics()->QuadContainerUpload(m_DirectionQuadContainerIndex);
}

View file

@ -76,6 +76,54 @@ inline float AngularApproach(float Src, float Dst, float Amount)
return Dst;
return n;
}
float CPlayers::GetPlayerTargetAngle(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
int ClientID,
float Intra)
{
float AngleIntraTick = Intra;
// using unpredicted angle when rendering other players in-game
if(ClientID >= 0)
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
if(ClientID >= 0 && m_pClient->m_Snap.m_aCharacters[ClientID].m_HasExtendedDisplayInfo)
{
CNetObj_DDNetCharacterDisplayInfo *CharacterDisplayInfo = &m_pClient->m_Snap.m_aCharacters[ClientID].m_ExtendedDisplayInfo;
if(m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedDisplayInfo)
{
const CNetObj_DDNetCharacterDisplayInfo *PrevCharacterDisplayInfo = m_pClient->m_Snap.m_aCharacters[ClientID].m_PrevExtendedDisplayInfo;
float MixX = mix((float)PrevCharacterDisplayInfo->m_TargetX, (float)CharacterDisplayInfo->m_TargetX, AngleIntraTick);
float MixY = mix((float)PrevCharacterDisplayInfo->m_TargetY, (float)CharacterDisplayInfo->m_TargetY, AngleIntraTick);
return angle(vec2(MixX, MixY));
}
else
{
return angle(vec2(CharacterDisplayInfo->m_TargetX, CharacterDisplayInfo->m_TargetY));
}
}
else
{
// If the player moves their weapon through top, then change
// the end angle by 2*Pi, so that the mix function will use the
// short path and not the long one.
if(pPlayerChar->m_Angle > (256.0f * pi) && pPrevChar->m_Angle < 0)
{
return mix((float)pPrevChar->m_Angle, (float)(pPlayerChar->m_Angle - 256.0f * 2 * pi), AngleIntraTick) / 256.0f;
}
else if(pPlayerChar->m_Angle < 0 && pPrevChar->m_Angle > (256.0f * pi))
{
return mix((float)pPrevChar->m_Angle, (float)(pPlayerChar->m_Angle + 256.0f * 2 * pi), AngleIntraTick) / 256.0f;
}
else
{
return mix((float)pPrevChar->m_Angle, (float)pPlayerChar->m_Angle, AngleIntraTick) / 256.0f;
}
}
}
void CPlayers::RenderHookCollLine(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
@ -104,19 +152,7 @@ void CPlayers::RenderHookCollLine(
}
else
{
float AngleIntraTick = IntraTick;
// using unpredicted angle when rendering other players in-game
if(ClientID >= 0)
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
// If the player moves their weapon through top, then change
// the end angle by 2*Pi, so that the mix function will use the
// short path and not the long one.
if(Player.m_Angle > (256.0f * pi) && Prev.m_Angle < 0)
Player.m_Angle -= 256.0f * 2 * pi;
else if(Player.m_Angle < 0 && Prev.m_Angle > (256.0f * pi))
Player.m_Angle += 256.0f * 2 * pi;
Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, AngleIntraTick) / 256.0f;
Angle = GetPlayerTargetAngle(&Prev, &Player, ClientID, IntraTick);
}
vec2 Direction = direction(Angle);
@ -365,19 +401,7 @@ void CPlayers::RenderPlayer(
}
else
{
float AngleIntraTick = IntraTick;
// using unpredicted angle when rendering other players in-game
if(ClientID >= 0)
AngleIntraTick = Client()->IntraGameTick(g_Config.m_ClDummy);
// If the player moves their weapon through top, then change
// the end angle by 2*Pi, so that the mix function will use the
// short path and not the long one.
if(Player.m_Angle > (256.0f * pi) && Prev.m_Angle < 0)
Player.m_Angle -= 256.0f * 2 * pi;
else if(Player.m_Angle < 0 && Prev.m_Angle > (256.0f * pi))
Player.m_Angle += 256.0f * 2 * pi;
Angle = mix((float)Prev.m_Angle, (float)Player.m_Angle, AngleIntraTick) / 256.0f;
Angle = GetPlayerTargetAngle(&Prev, &Player, ClientID, IntraTick);
}
vec2 Direction = direction(Angle);

View file

@ -31,13 +31,17 @@ class CPlayers : public CComponent
const CNetObj_Character *pPlayerChar,
int ClientID,
float Intra = 0.f);
float GetPlayerTargetAngle(
const CNetObj_Character *pPrevChar,
const CNetObj_Character *pPlayerChar,
int ClientID,
float Intra = 0.f);
bool IsPlayerInfoAvailable(int ClientID) const;
int m_WeaponEmoteQuadContainerIndex;
int m_WeaponSpriteMuzzleQuadContainerIndex[NUM_WEAPONS];
public:
vec2 m_CurPredictedPos[MAX_CLIENTS];
virtual int Sizeof() const override { return sizeof(*this); }
virtual void OnInit() override;
virtual void OnRender() override;

View file

@ -693,7 +693,7 @@ void CScoreboard::OnRender()
RenderGoals(Width / 2 - w / 2, 150 + 760 + 10, w);
RenderSpectators(Width / 2 - w / 2, 150 + 760 + 10 + 50 + 10, w);
RenderRecordingNotification((Width / 7) * 4);
RenderRecordingNotification((Width / 7) * 4 + 20);
}
bool CScoreboard::Active()

View file

@ -45,6 +45,7 @@
#include "components/effects.h"
#include "components/emoticon.h"
#include "components/flow.h"
#include "components/freezebars.h"
#include "components/hud.h"
#include "components/items.h"
#include "components/killmessages.h"
@ -125,6 +126,7 @@ void CGameClient::OnConsoleInit()
m_All.Add(&m_Particles.m_RenderExplosions);
m_All.Add(&m_NamePlates);
m_All.Add(&m_Particles.m_RenderGeneral);
m_All.Add(&m_FreezeBars);
m_All.Add(&m_DamageInd);
m_All.Add(&m_Hud);
m_All.Add(&m_Spectator);
@ -262,6 +264,7 @@ void CGameClient::OnInit()
m_GameSkinLoaded = false;
m_ParticlesSkinLoaded = false;
m_EmoticonsSkinLoaded = false;
m_HudSkinLoaded = false;
// setup load amount// load textures
for(int i = 0; i < g_pData->m_NumImages; i++)
@ -272,6 +275,8 @@ void CGameClient::OnInit()
LoadEmoticonsSkin(g_Config.m_ClAssetEmoticons);
else if(i == IMAGE_PARTICLES)
LoadParticlesSkin(g_Config.m_ClAssetParticles);
else if(i == IMAGE_HUD)
LoadHudSkin(g_Config.m_ClAssetHud);
else
g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
m_Menus.RenderLoading(false);
@ -1095,8 +1100,7 @@ void CGameClient::OnNewSnapshot()
mem_zero(&TempCore, sizeof(TempCore));
mem_zero(&TempTeams, sizeof(TempTeams));
TempCore.Init(&TempWorld, Collision(), &TempTeams);
TempCore.Read(pCharacter);
TempCore.m_ActiveWeapon = pCharacter->m_Weapon;
TempCore.ReadCharacter(pCharacter);
while(pCharacter->m_Tick < Tick)
{
@ -1271,6 +1275,7 @@ void CGameClient::OnNewSnapshot()
{
const void *pOld = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_CHARACTER, Item.m_ID);
m_Snap.m_aCharacters[Item.m_ID].m_Cur = *((const CNetObj_Character *)pData);
m_aClients[Item.m_ID].m_Predicted.ReadCharacter((const CNetObj_Character *)pData);
if(pOld)
{
m_Snap.m_aCharacters[Item.m_ID].m_Active = true;
@ -1341,6 +1346,20 @@ void CGameClient::OnNewSnapshot()
pClient->m_Predicted.ReadDDNet(pCharacterData);
}
}
else if(Item.m_Type == NETOBJTYPE_DDNETCHARACTERDISPLAYINFO)
{
const CNetObj_DDNetCharacterDisplayInfo *pCharacterDisplayInfo = (const CNetObj_DDNetCharacterDisplayInfo *)pData;
if(Item.m_ID < MAX_CLIENTS)
{
m_Snap.m_aCharacters[Item.m_ID].m_ExtendedDisplayInfo = *pCharacterDisplayInfo;
m_Snap.m_aCharacters[Item.m_ID].m_PrevExtendedDisplayInfo = (const CNetObj_DDNetCharacterDisplayInfo *)Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_DDNETCHARACTERDISPLAYINFO, Item.m_ID);
m_Snap.m_aCharacters[Item.m_ID].m_HasExtendedDisplayInfo = true;
CClientData *pClient = &m_aClients[Item.m_ID];
pClient->m_Predicted.ReadDDNetDisplayInfo(pCharacterDisplayInfo);
}
}
else if(Item.m_Type == NETOBJTYPE_SPECCHAR)
{
const CNetObj_SpecChar *pSpecCharData = (const CNetObj_SpecChar *)pData;
@ -1705,13 +1724,11 @@ void CGameClient::OnPredict()
{
if(m_Snap.m_pLocalCharacter)
{
m_PredictedChar.Read(m_Snap.m_pLocalCharacter);
m_PredictedChar.m_ActiveWeapon = m_Snap.m_pLocalCharacter->m_Weapon;
m_PredictedChar.ReadCharacter(m_Snap.m_pLocalCharacter);
}
if(m_Snap.m_pLocalPrevCharacter)
{
m_PredictedPrevChar.Read(m_Snap.m_pLocalPrevCharacter);
m_PredictedPrevChar.m_ActiveWeapon = m_Snap.m_pLocalPrevCharacter->m_Weapon;
m_PredictedPrevChar.ReadCharacter(m_Snap.m_pLocalPrevCharacter);
}
return;
}
@ -2418,6 +2435,7 @@ void CGameClient::UpdatePrediction()
int GameTeam = (m_Snap.m_pGameInfoObj->m_GameFlags & GAMEFLAG_TEAMS) ? m_aClients[i].m_Team : i;
m_GameWorld.NetCharAdd(i, &m_Snap.m_aCharacters[i].m_Cur,
m_Snap.m_aCharacters[i].m_HasExtendedData ? &m_Snap.m_aCharacters[i].m_ExtendedData : 0,
m_Snap.m_aCharacters[i].m_HasExtendedDisplayInfo ? &m_Snap.m_aCharacters[i].m_ExtendedDisplayInfo : 0,
GameTeam, IsLocal);
}
@ -2516,7 +2534,7 @@ void CGameClient::DetectStrongHook()
float PredictErr[2];
CCharacterCore ToCharCur;
ToCharCur.Read(&m_Snap.m_aCharacters[ToPlayer].m_Cur);
ToCharCur.ReadCharacterCore(&m_Snap.m_aCharacters[ToPlayer].m_Cur);
CWorldCore World;
World.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
@ -2526,12 +2544,12 @@ void CGameClient::DetectStrongHook()
CCharacterCore ToChar = pFromCharWorld->GetCore();
ToChar.Init(&World, Collision(), &m_Teams);
World.m_apCharacters[ToPlayer] = &ToChar;
ToChar.Read(&m_Snap.m_aCharacters[ToPlayer].m_Prev);
ToChar.ReadCharacterCore(&m_Snap.m_aCharacters[ToPlayer].m_Prev);
CCharacterCore FromChar = pFromCharWorld->GetCore();
FromChar.Init(&World, Collision(), &m_Teams);
World.m_apCharacters[FromPlayer] = &FromChar;
FromChar.Read(&m_Snap.m_aCharacters[FromPlayer].m_Prev);
FromChar.ReadCharacterCore(&m_Snap.m_aCharacters[FromPlayer].m_Prev);
for(int Tick = Client()->PrevGameTick(g_Config.m_ClDummy); Tick < Client()->GameTick(g_Config.m_ClDummy); Tick++)
{
@ -2731,6 +2749,11 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir)
SpritePickupWeapon = IGraphics::CTextureHandle();
}
for(auto &SpritePickupWeaponArmor : m_GameSkin.m_SpritePickupWeaponArmor)
{
SpritePickupWeaponArmor = IGraphics::CTextureHandle();
}
Graphics()->UnloadTexture(&m_GameSkin.m_SpriteFlagBlue);
Graphics()->UnloadTexture(&m_GameSkin.m_SpriteFlagRed);
@ -2852,16 +2875,16 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir)
// pickups
m_GameSkin.m_SpritePickupHealth = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_HEALTH]);
m_GameSkin.m_SpritePickupArmor = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR]);
m_GameSkin.m_SpritePickupHammer = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_HAMMER]);
m_GameSkin.m_SpritePickupGun = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_GUN]);
m_GameSkin.m_SpritePickupShotgun = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_SHOTGUN]);
m_GameSkin.m_SpritePickupGrenade = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_GRENADE]);
m_GameSkin.m_SpritePickupLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_LASER]);
m_GameSkin.m_SpritePickupNinja = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_NINJA]);
m_GameSkin.m_SpritePickupArmorShotgun = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_SHOTGUN]);
m_GameSkin.m_SpritePickupArmorGrenade = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_GRENADE]);
m_GameSkin.m_SpritePickupArmorLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_LASER]);
m_GameSkin.m_SpritePickupArmorNinja = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_NINJA]);
m_GameSkin.m_SpritePickupGrenade = Graphics()->LoadSpriteTexture(ImgInfo, &client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_GRENADE]);
m_GameSkin.m_SpritePickupShotgun = Graphics()->LoadSpriteTexture(ImgInfo, &client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_SHOTGUN]);
m_GameSkin.m_SpritePickupLaser = Graphics()->LoadSpriteTexture(ImgInfo, &client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_LASER]);
m_GameSkin.m_SpritePickupNinja = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_NINJA]);
m_GameSkin.m_SpritePickupGun = Graphics()->LoadSpriteTexture(ImgInfo, &client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_GUN]);
m_GameSkin.m_SpritePickupHammer = Graphics()->LoadSpriteTexture(ImgInfo, &client_data7::g_pData->m_aSprites[client_data7::SPRITE_PICKUP_HAMMER]);
m_GameSkin.m_SpritePickupArmorLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_PICKUP_ARMOR_LASER]);
m_GameSkin.m_SpritePickupWeapons[0] = m_GameSkin.m_SpritePickupHammer;
m_GameSkin.m_SpritePickupWeapons[1] = m_GameSkin.m_SpritePickupGun;
@ -2870,6 +2893,11 @@ void CGameClient::LoadGameSkin(const char *pPath, bool AsDir)
m_GameSkin.m_SpritePickupWeapons[4] = m_GameSkin.m_SpritePickupLaser;
m_GameSkin.m_SpritePickupWeapons[5] = m_GameSkin.m_SpritePickupNinja;
m_GameSkin.m_SpritePickupWeaponArmor[0] = m_GameSkin.m_SpritePickupArmorShotgun;
m_GameSkin.m_SpritePickupWeaponArmor[1] = m_GameSkin.m_SpritePickupArmorGrenade;
m_GameSkin.m_SpritePickupWeaponArmor[2] = m_GameSkin.m_SpritePickupArmorNinja;
m_GameSkin.m_SpritePickupWeaponArmor[3] = m_GameSkin.m_SpritePickupArmorLaser;
// flags
m_GameSkin.m_SpriteFlagBlue = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_FLAG_BLUE]);
m_GameSkin.m_SpriteFlagRed = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_FLAG_RED]);
@ -3007,6 +3035,101 @@ void CGameClient::LoadParticlesSkin(const char *pPath, bool AsDir)
}
}
void CGameClient::LoadHudSkin(const char *pPath, bool AsDir)
{
if(m_HudSkinLoaded)
{
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudAirjump);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudAirjumpEmpty);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudSolo);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoCollision);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudEndlessJump);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudEndlessHook);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudJetpack);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudFreezeBarFullLeft);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudFreezeBarFull);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudFreezeBarEmpty);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudFreezeBarEmptyRight);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNinjaBarFullLeft);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNinjaBarFull);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNinjaBarEmpty);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNinjaBarEmptyRight);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoHookHit);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoHammerHit);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoShotgunHit);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoGrenadeHit);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudNoLaserHit);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudDeepFrozen);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudLiveFrozen);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudTeleportGrenade);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudTeleportGun);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudTeleportLaser);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudPracticeMode);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudDummyHammer);
Graphics()->UnloadTexture(&m_HudSkin.m_SpriteHudDummyCopy);
m_HudSkinLoaded = false;
}
char aPath[IO_MAX_PATH_LENGTH];
bool IsDefault = false;
if(str_comp(pPath, "default") == 0)
{
str_format(aPath, sizeof(aPath), "%s", g_pData->m_aImages[IMAGE_HUD].m_pFilename);
IsDefault = true;
}
else
{
if(AsDir)
str_format(aPath, sizeof(aPath), "assets/hud/%s/%s", pPath, g_pData->m_aImages[IMAGE_HUD].m_pFilename);
else
str_format(aPath, sizeof(aPath), "assets/hud/%s.png", pPath);
}
CImageInfo ImgInfo;
bool PngLoaded = Graphics()->LoadPNG(&ImgInfo, aPath, IStorage::TYPE_ALL);
if(!PngLoaded && !IsDefault)
{
if(AsDir)
LoadHudSkin("default");
else
LoadHudSkin(pPath, true);
}
else if(PngLoaded && Graphics()->CheckImageDivisibility(aPath, ImgInfo, g_pData->m_aSprites[SPRITE_HUD_AIRJUMP].m_pSet->m_Gridx, g_pData->m_aSprites[SPRITE_HUD_AIRJUMP].m_pSet->m_Gridy, true) && Graphics()->IsImageFormatRGBA(aPath, ImgInfo))
{
m_HudSkin.m_SpriteHudAirjump = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_AIRJUMP]);
m_HudSkin.m_SpriteHudAirjumpEmpty = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_AIRJUMP_EMPTY]);
m_HudSkin.m_SpriteHudSolo = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_SOLO]);
m_HudSkin.m_SpriteHudNoCollision = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_COLLISION]);
m_HudSkin.m_SpriteHudEndlessJump = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_ENDLESS_JUMP]);
m_HudSkin.m_SpriteHudEndlessHook = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_ENDLESS_HOOK]);
m_HudSkin.m_SpriteHudJetpack = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_JETPACK]);
m_HudSkin.m_SpriteHudFreezeBarFullLeft = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_FREEZE_BAR_FULL_LEFT]);
m_HudSkin.m_SpriteHudFreezeBarFull = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_FREEZE_BAR_FULL]);
m_HudSkin.m_SpriteHudFreezeBarEmpty = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_FREEZE_BAR_EMPTY]);
m_HudSkin.m_SpriteHudFreezeBarEmptyRight = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_FREEZE_BAR_EMPTY_RIGHT]);
m_HudSkin.m_SpriteHudNinjaBarFullLeft = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NINJA_BAR_FULL_LEFT]);
m_HudSkin.m_SpriteHudNinjaBarFull = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NINJA_BAR_FULL]);
m_HudSkin.m_SpriteHudNinjaBarEmpty = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NINJA_BAR_EMPTY]);
m_HudSkin.m_SpriteHudNinjaBarEmptyRight = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NINJA_BAR_EMPTY_RIGHT]);
m_HudSkin.m_SpriteHudNoHookHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_HOOK_HIT]);
m_HudSkin.m_SpriteHudNoHammerHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_HAMMER_HIT]);
m_HudSkin.m_SpriteHudNoShotgunHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_SHOTGUN_HIT]);
m_HudSkin.m_SpriteHudNoGrenadeHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_GRENADE_HIT]);
m_HudSkin.m_SpriteHudNoLaserHit = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_NO_LASER_HIT]);
m_HudSkin.m_SpriteHudDeepFrozen = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_DEEP_FROZEN]);
m_HudSkin.m_SpriteHudLiveFrozen = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_LIVE_FROZEN]);
m_HudSkin.m_SpriteHudTeleportGrenade = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_TELEPORT_GRENADE]);
m_HudSkin.m_SpriteHudTeleportGun = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_TELEPORT_GUN]);
m_HudSkin.m_SpriteHudTeleportLaser = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_TELEPORT_LASER]);
m_HudSkin.m_SpriteHudPracticeMode = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_PRACTICE_MODE]);
m_HudSkin.m_SpriteHudDummyHammer = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_DUMMY_HAMMER]);
m_HudSkin.m_SpriteHudDummyCopy = Graphics()->LoadSpriteTexture(ImgInfo, &g_pData->m_aSprites[SPRITE_HUD_DUMMY_COPY]);
m_HudSkinLoaded = true;
free(ImgInfo.m_pData);
}
}
void CGameClient::RefindSkins()
{
for(auto &Client : m_aClients)

View file

@ -34,6 +34,7 @@
#include "components/effects.h"
#include "components/emoticon.h"
#include "components/flow.h"
#include "components/freezebars.h"
#include "components/ghost.h"
#include "components/hud.h"
#include "components/items.h"
@ -132,6 +133,7 @@ public:
CPlayers m_Players;
CNamePlates m_NamePlates;
CFreezeBars m_FreezeBars;
CItems m_Items;
CMapImages m_MapImages;
@ -319,6 +321,10 @@ public:
CNetObj_DDNetCharacter m_ExtendedData;
bool m_HasExtendedData;
const CNetObj_DDNetCharacterDisplayInfo *m_PrevExtendedDisplayInfo;
CNetObj_DDNetCharacterDisplayInfo m_ExtendedDisplayInfo;
bool m_HasExtendedDisplayInfo;
// interpolated position
vec2 m_Position;
};
@ -533,6 +539,7 @@ public:
void LoadGameSkin(const char *pPath, bool AsDir = false);
void LoadEmoticonsSkin(const char *pPath, bool AsDir = false);
void LoadParticlesSkin(const char *pPath, bool AsDir = false);
void LoadHudSkin(const char *pPath, bool AsDir = false);
void RefindSkins();
@ -594,8 +601,8 @@ public:
IGraphics::CTextureHandle m_SpritePickupArmor;
IGraphics::CTextureHandle m_SpritePickupArmorShotgun;
IGraphics::CTextureHandle m_SpritePickupArmorGrenade;
IGraphics::CTextureHandle m_SpritePickupArmorLaser;
IGraphics::CTextureHandle m_SpritePickupArmorNinja;
IGraphics::CTextureHandle m_SpritePickupArmorLaser;
IGraphics::CTextureHandle m_SpritePickupGrenade;
IGraphics::CTextureHandle m_SpritePickupShotgun;
IGraphics::CTextureHandle m_SpritePickupLaser;
@ -604,6 +611,7 @@ public:
IGraphics::CTextureHandle m_SpritePickupHammer;
IGraphics::CTextureHandle m_SpritePickupWeapons[6];
IGraphics::CTextureHandle m_SpritePickupWeaponArmor[4];
// flags
IGraphics::CTextureHandle m_SpriteFlagBlue;
@ -648,6 +656,41 @@ public:
SClientEmoticonsSkin m_EmoticonsSkin;
bool m_EmoticonsSkinLoaded;
struct SClientHudSkin
{
IGraphics::CTextureHandle m_SpriteHudAirjump;
IGraphics::CTextureHandle m_SpriteHudAirjumpEmpty;
IGraphics::CTextureHandle m_SpriteHudSolo;
IGraphics::CTextureHandle m_SpriteHudNoCollision;
IGraphics::CTextureHandle m_SpriteHudEndlessJump;
IGraphics::CTextureHandle m_SpriteHudEndlessHook;
IGraphics::CTextureHandle m_SpriteHudJetpack;
IGraphics::CTextureHandle m_SpriteHudFreezeBarFullLeft;
IGraphics::CTextureHandle m_SpriteHudFreezeBarFull;
IGraphics::CTextureHandle m_SpriteHudFreezeBarEmpty;
IGraphics::CTextureHandle m_SpriteHudFreezeBarEmptyRight;
IGraphics::CTextureHandle m_SpriteHudNinjaBarFullLeft;
IGraphics::CTextureHandle m_SpriteHudNinjaBarFull;
IGraphics::CTextureHandle m_SpriteHudNinjaBarEmpty;
IGraphics::CTextureHandle m_SpriteHudNinjaBarEmptyRight;
IGraphics::CTextureHandle m_SpriteHudNoHookHit;
IGraphics::CTextureHandle m_SpriteHudNoHammerHit;
IGraphics::CTextureHandle m_SpriteHudNoShotgunHit;
IGraphics::CTextureHandle m_SpriteHudNoGrenadeHit;
IGraphics::CTextureHandle m_SpriteHudNoLaserHit;
IGraphics::CTextureHandle m_SpriteHudDeepFrozen;
IGraphics::CTextureHandle m_SpriteHudLiveFrozen;
IGraphics::CTextureHandle m_SpriteHudTeleportGrenade;
IGraphics::CTextureHandle m_SpriteHudTeleportGun;
IGraphics::CTextureHandle m_SpriteHudTeleportLaser;
IGraphics::CTextureHandle m_SpriteHudPracticeMode;
IGraphics::CTextureHandle m_SpriteHudDummyHammer;
IGraphics::CTextureHandle m_SpriteHudDummyCopy;
};
SClientHudSkin m_HudSkin;
bool m_HudSkinLoaded;
const std::vector<CSnapEntities> &SnapEntities() { return m_aSnapEntities; }
private:

View file

@ -58,14 +58,14 @@ void CCharacter::HandleJetpack()
if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses)
WillFire = true;
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
WillFire = true;
if(!WillFire)
return;
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
{
return;
}
@ -87,8 +87,8 @@ void CCharacter::HandleJetpack()
void CCharacter::RemoveNinja()
{
m_Ninja.m_CurrentMoveTime = 0;
m_aWeapons[WEAPON_NINJA].m_Got = false;
m_Core.m_Ninja.m_CurrentMoveTime = 0;
m_Core.m_aWeapons[WEAPON_NINJA].m_Got = false;
m_Core.m_ActiveWeapon = m_LastWeapon;
SetWeapon(m_Core.m_ActiveWeapon);
@ -99,7 +99,7 @@ void CCharacter::HandleNinja()
if(m_Core.m_ActiveWeapon != WEAPON_NINJA)
return;
if((GameWorld()->GameTick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * GameWorld()->GameTickSpeed() / 1000))
if((GameWorld()->GameTick() - m_Core.m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * GameWorld()->GameTickSpeed() / 1000))
{
// time's up, return
RemoveNinja();
@ -109,18 +109,18 @@ void CCharacter::HandleNinja()
// force ninja Weapon
SetWeapon(WEAPON_NINJA);
m_Ninja.m_CurrentMoveTime--;
m_Core.m_Ninja.m_CurrentMoveTime--;
if(m_Ninja.m_CurrentMoveTime == 0)
if(m_Core.m_Ninja.m_CurrentMoveTime == 0)
{
// reset velocity
m_Core.m_Vel = m_Ninja.m_ActivationDir * m_Ninja.m_OldVelAmount;
m_Core.m_Vel = m_Core.m_Ninja.m_ActivationDir * m_Core.m_Ninja.m_OldVelAmount;
}
if(m_Ninja.m_CurrentMoveTime > 0)
if(m_Core.m_Ninja.m_CurrentMoveTime > 0)
{
// Set velocity
m_Core.m_Vel = m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity;
m_Core.m_Vel = m_Core.m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity;
vec2 OldPos = m_Pos;
Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(m_ProximityRadius, m_ProximityRadius), 0.f);
@ -184,7 +184,7 @@ void CCharacter::HandleNinja()
void CCharacter::DoWeaponSwitch()
{
// make sure we can switch
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_aWeapons[WEAPON_NINJA].m_Got || !m_aWeapons[m_QueuedWeapon].m_Got)
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_Core.m_aWeapons[WEAPON_NINJA].m_Got || !m_Core.m_aWeapons[m_QueuedWeapon].m_Got)
return;
// switch Weapon
@ -202,7 +202,7 @@ void CCharacter::HandleWeaponSwitch()
bool Anything = false;
for(int i = 0; i < NUM_WEAPONS - 1; ++i)
if(m_aWeapons[i].m_Got)
if(m_Core.m_aWeapons[i].m_Got)
Anything = true;
if(!Anything)
return;
@ -215,7 +215,7 @@ void CCharacter::HandleWeaponSwitch()
while(Next) // Next Weapon selection
{
WantedWeapon = (WantedWeapon + 1) % NUM_WEAPONS;
if(m_aWeapons[WantedWeapon].m_Got)
if(m_Core.m_aWeapons[WantedWeapon].m_Got)
Next--;
}
}
@ -225,7 +225,7 @@ void CCharacter::HandleWeaponSwitch()
while(Prev) // Prev Weapon selection
{
WantedWeapon = (WantedWeapon - 1) < 0 ? NUM_WEAPONS - 1 : WantedWeapon - 1;
if(m_aWeapons[WantedWeapon].m_Got)
if(m_Core.m_aWeapons[WantedWeapon].m_Got)
Prev--;
}
}
@ -235,7 +235,7 @@ void CCharacter::HandleWeaponSwitch()
WantedWeapon = m_Input.m_WantedWeapon - 1;
// check for insane values
if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_Core.m_ActiveWeapon && m_aWeapons[WantedWeapon].m_Got)
if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_Core.m_ActiveWeapon && m_Core.m_aWeapons[WantedWeapon].m_Got)
m_QueuedWeapon = WantedWeapon;
DoWeaponSwitch();
@ -272,14 +272,14 @@ void CCharacter::FireWeapon()
if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses)
WillFire = true;
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
WillFire = true;
if(!WillFire)
return;
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
{
return;
}
@ -445,9 +445,9 @@ void CCharacter::FireWeapon()
// reset Hit objects
m_NumObjectsHit = 0;
m_Ninja.m_ActivationDir = Direction;
m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * GameWorld()->GameTickSpeed() / 1000;
m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
m_Core.m_Ninja.m_ActivationDir = Direction;
m_Core.m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * GameWorld()->GameTickSpeed() / 1000;
m_Core.m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
}
break;
}
@ -482,10 +482,10 @@ void CCharacter::HandleWeapons()
void CCharacter::GiveNinja()
{
m_Ninja.m_ActivationTick = GameWorld()->GameTick();
m_aWeapons[WEAPON_NINJA].m_Got = true;
m_Core.m_Ninja.m_ActivationTick = GameWorld()->GameTick();
m_Core.m_aWeapons[WEAPON_NINJA].m_Got = true;
if(!m_FreezeTime)
m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
m_Core.m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
if(m_Core.m_ActiveWeapon != WEAPON_NINJA)
m_LastWeapon = m_Core.m_ActiveWeapon;
m_Core.m_ActiveWeapon = WEAPON_NINJA;
@ -697,7 +697,9 @@ void CCharacter::HandleTiles(int Index)
if(Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER)
{
if(Collision()->GetSwitchNumber(MapIndex) == 0 || Collision()->m_pSwitchers[Collision()->GetSwitchNumber(MapIndex)].m_Status[Team()])
{
Freeze(Collision()->GetSwitchDelay(MapIndex));
}
}
else if(Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER)
{
@ -859,7 +861,7 @@ void CCharacter::HandleTiles(int Index)
if(m_Core.m_Vel.y > 0 && m_Core.m_Colliding && m_Core.m_LeftWall)
{
m_Core.m_LeftWall = false;
m_Core.m_JumpedTotal = m_Core.m_Jumps - 1;
m_Core.m_JumpedTotal = m_Core.m_Jumps >= 2 ? m_Core.m_Jumps - 2 : 0;
m_Core.m_Jumped = 1;
}
}
@ -923,7 +925,7 @@ void CCharacter::DDRaceTick()
if(m_FreezeTime > 0)
m_FreezeTime--;
else
m_Ninja.m_ActivationTick = GameWorld()->GameTick();
m_Core.m_Ninja.m_ActivationTick = GameWorld()->GameTick();
if(!m_CanMoveInFreeze)
{
m_Input.m_Direction = 0;
@ -935,6 +937,22 @@ void CCharacter::DDRaceTick()
}
HandleTuneLayer();
// check if the tee is in any type of freeze
int Index = Collision()->GetPureMapIndex(m_Pos);
const int aTiles[] = {
Collision()->GetTileIndex(Index),
Collision()->GetFTileIndex(Index),
Collision()->GetSwitchType(Index)};
m_Core.m_IsInFreeze = false;
for(const int Tile : aTiles)
{
if(Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE)
{
m_Core.m_IsInFreeze = true;
break;
}
}
}
void CCharacter::DDRacePostCoreTick()
@ -950,17 +968,32 @@ void CCharacter::DDRacePostCoreTick()
if(m_DeepFreeze && !m_Super)
Freeze();
if(m_Core.m_Jumps == -1 && !m_Super)
if(m_Core.m_Jumps == -1)
{
// The player has only one ground jump, so his feet are always dark
m_Core.m_Jumped |= 2;
else if(m_Core.m_Jumps == 0 && !m_Super)
m_Core.m_Jumped = 3;
}
else if(m_Core.m_Jumps == 0)
{
// The player has no jumps at all, so his feet are always dark
m_Core.m_Jumped |= 2;
}
else if(m_Core.m_Jumps == 1 && m_Core.m_Jumped > 0)
m_Core.m_Jumped = 3;
{
// If the player has only one jump, each jump is the last one
m_Core.m_Jumped |= 2;
}
else if(m_Core.m_JumpedTotal < m_Core.m_Jumps - 1 && m_Core.m_Jumped > 1)
{
// The player has not yet used up all his jumps, so his feet remain light
m_Core.m_Jumped = 1;
}
if((m_Super || m_SuperJump) && m_Core.m_Jumped > 1)
{
// Super players and players with infinite jumps always have light feet
m_Core.m_Jumped = 1;
}
int CurrentIndex = Collision()->GetMapIndex(m_Pos);
HandleSkippableTiles(CurrentIndex);
@ -982,10 +1015,10 @@ bool CCharacter::Freeze(int Seconds)
return false;
if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * GameWorld()->GameTickSpeed()) && Seconds != -1)
return false;
if(m_FreezeTick < GameWorld()->GameTick() - GameWorld()->GameTickSpeed() || Seconds == -1)
if(m_Core.m_FreezeTick < GameWorld()->GameTick() - GameWorld()->GameTickSpeed() || Seconds == -1)
{
m_FreezeTime = Seconds == -1 ? Seconds : Seconds * GameWorld()->GameTickSpeed();
m_FreezeTick = GameWorld()->GameTick();
m_Core.m_FreezeTick = GameWorld()->GameTick();
return true;
}
return false;
@ -1000,10 +1033,10 @@ bool CCharacter::UnFreeze()
{
if(m_FreezeTime > 0)
{
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
m_Core.m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0;
m_FreezeTick = 0;
m_Core.m_FreezeTick = 0;
m_FrozenLastTick = true;
return true;
}
@ -1028,10 +1061,10 @@ void CCharacter::GiveWeapon(int Weapon, bool Remove)
}
else
{
m_aWeapons[Weapon].m_Ammo = -1;
m_Core.m_aWeapons[Weapon].m_Ammo = -1;
}
m_aWeapons[Weapon].m_Got = !Remove;
m_Core.m_aWeapons[Weapon].m_Got = !Remove;
}
void CCharacter::GiveAllWeapons()
@ -1047,7 +1080,7 @@ CTeamsCore *CCharacter::TeamsCore()
return m_Core.m_pTeams;
}
CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended) :
CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo) :
CEntity(pGameWorld, CGameWorld::ENTTYPE_CHARACTER)
{
m_ID = ID;
@ -1060,7 +1093,7 @@ CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar,
m_Core.Reset();
m_Core.Init(&GameWorld()->m_Core, GameWorld()->Collision(), GameWorld()->Teams());
m_Core.m_Id = ID;
mem_zero(&m_Ninja, sizeof(m_Ninja));
mem_zero(&m_Core.m_Ninja, sizeof(m_Core.m_Ninja));
mem_zero(&m_SavedInput, sizeof(m_SavedInput));
m_LatestInput = m_LatestPrevInput = m_PrevInput = m_Input = m_SavedInput;
m_ProximityRadius = ms_PhysSize;
@ -1082,7 +1115,7 @@ CCharacter::CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar,
m_LatestPrevInput = m_LatestInput = m_PrevInput = m_SavedInput = m_Input;
ResetPrediction();
Read(pChar, pExtended, false);
Read(pChar, pExtended, pExtendedDisplayInfo, false);
GameWorld()->InsertEntity(this);
}
@ -1100,7 +1133,8 @@ void CCharacter::ResetPrediction()
m_Core.m_Collision = true;
m_NumInputs = 0;
m_FreezeTime = 0;
m_FreezeTick = 0;
m_Core.m_FreezeTick = 0;
m_Core.m_IsInFreeze = false;
m_DeepFreeze = false;
m_LiveFreeze = false;
m_FrozenLastTick = false;
@ -1119,9 +1153,9 @@ void CCharacter::ResetPrediction()
m_LastTuneZoneTick = 0;
}
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal)
void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, bool IsLocal)
{
m_Core.Read((CNetObj_CharacterCore *)pChar);
m_Core.ReadCharacterCore((const CNetObj_CharacterCore *)pChar);
m_IsLocal = IsLocal;
if(pExtended)
@ -1149,12 +1183,6 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
if(pExtended->m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT)
m_Hit |= DISABLE_HIT_SHOTGUN;
m_aWeapons[WEAPON_HAMMER].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_HAMMER) != 0;
m_aWeapons[WEAPON_GUN].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_GUN) != 0;
m_aWeapons[WEAPON_SHOTGUN].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_SHOTGUN) != 0;
m_aWeapons[WEAPON_GRENADE].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_GRENADE) != 0;
m_aWeapons[WEAPON_LASER].m_Got = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_LASER) != 0;
const bool Ninja = (pExtended->m_Flags & CHARACTERFLAG_WEAPON_NINJA) != 0;
if(Ninja && m_Core.m_ActiveWeapon != WEAPON_NINJA)
GiveNinja();
@ -1185,7 +1213,7 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
if(pChar->m_Weapon != m_Core.m_ActiveWeapon)
{
if(pChar->m_Weapon == WEAPON_NINJA)
m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo = 0;
m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo = 0;
else
{
if(m_Core.m_ActiveWeapon == WEAPON_NINJA)
@ -1195,12 +1223,12 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
SetNinjaCurrentMoveTime(0);
}
if(pChar->m_Weapon == m_LastSnapWeapon)
m_aWeapons[m_Core.m_ActiveWeapon].m_Got = false;
m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got = false;
}
}
// add weapon
if(pChar->m_Weapon != WEAPON_NINJA)
m_aWeapons[pChar->m_Weapon].m_Got = true;
m_Core.m_aWeapons[pChar->m_Weapon].m_Got = true;
// jetpack
if(GameWorld()->m_WorldConfig.m_PredictWeapons && Tuning()->m_JetpackStrength > 0)
@ -1208,8 +1236,8 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
m_LastJetpackStrength = Tuning()->m_JetpackStrength;
m_Jetpack = true;
m_Core.m_Jetpack = true;
m_aWeapons[WEAPON_GUN].m_Got = true;
m_aWeapons[WEAPON_GUN].m_Ammo = -1;
m_Core.m_aWeapons[WEAPON_GUN].m_Got = true;
m_Core.m_aWeapons[WEAPON_GUN].m_Ammo = -1;
m_NinjaJetpack = pChar->m_Weapon == WEAPON_NINJA;
}
else if(pChar->m_Weapon != WEAPON_NINJA)
@ -1247,7 +1275,7 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
// detect unfreeze (in case the player was frozen in the tile prediction and not correctly unfrozen)
if(pChar->m_Emote != EMOTE_PAIN && pChar->m_Emote != EMOTE_NORMAL)
m_DeepFreeze = false;
if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_FreezeTick || absolute(pChar->m_VelX) == 256 * 10 || !GameWorld()->m_WorldConfig.m_PredictFreeze)
if(pChar->m_Weapon != WEAPON_NINJA || pChar->m_AttackTick > m_Core.m_FreezeTick || absolute(pChar->m_VelX) == 256 * 10 || !GameWorld()->m_WorldConfig.m_PredictFreeze)
{
m_DeepFreeze = false;
UnFreeze();
@ -1274,7 +1302,7 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
// set the current weapon
if(pChar->m_Weapon != WEAPON_NINJA)
{
m_aWeapons[pChar->m_Weapon].m_Ammo = (GameWorld()->m_WorldConfig.m_InfiniteAmmo || GameWorld()->m_WorldConfig.m_IsDDRace || pChar->m_Weapon == WEAPON_HAMMER) ? -1 : pChar->m_AmmoCount;
m_Core.m_aWeapons[pChar->m_Weapon].m_Ammo = (GameWorld()->m_WorldConfig.m_InfiniteAmmo || GameWorld()->m_WorldConfig.m_IsDDRace || pChar->m_Weapon == WEAPON_HAMMER) ? -1 : pChar->m_AmmoCount;
if(pChar->m_Weapon != m_Core.m_ActiveWeapon)
SetActiveWeapon(pChar->m_Weapon);
}
@ -1302,6 +1330,22 @@ void CCharacter::Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtende
m_ReloadTimer = maximum(0, m_AttackTick + FireDelayTicks - GameWorld()->GameTick());
}
}
if(pExtendedDisplayInfo)
{
if(GameWorld()->m_WorldConfig.m_PredictFreeze)
{
m_Core.m_FreezeTick = pExtendedDisplayInfo->m_FreezeTick;
}
m_Core.m_IsInFreeze = pExtendedDisplayInfo->m_IsInFreeze;
m_Core.m_Ninja.m_ActivationTick = pExtendedDisplayInfo->m_NinjaActivationTick;
m_Core.m_JumpedTotal = pExtendedDisplayInfo->m_JumpedTotal;
if(!IsLocal)
{
m_Input.m_TargetX = pExtendedDisplayInfo->m_TargetX;
m_Input.m_TargetY = pExtendedDisplayInfo->m_TargetY;
}
}
}
void CCharacter::SetCoreWorld(CGameWorld *pGameWorld)

View file

@ -79,7 +79,6 @@ public:
bool m_Jetpack;
bool m_NinjaJetpack;
int m_FreezeTime;
int m_FreezeTick;
bool m_FrozenLastTick;
bool m_DeepFreeze;
bool m_LiveFreeze;
@ -112,13 +111,13 @@ public:
CCharacterCore GetCore() { return m_Core; }
void SetCore(CCharacterCore Core) { m_Core = Core; }
CCharacterCore *Core() { return &m_Core; }
bool GetWeaponGot(int Type) { return m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_aWeapons[Type].m_Ammo; }
void SetWeaponAmmo(int Type, int Value) { m_aWeapons[Type].m_Ammo = Value; }
void SetNinjaActivationDir(vec2 ActivationDir) { m_Ninja.m_ActivationDir = ActivationDir; }
void SetNinjaActivationTick(int ActivationTick) { m_Ninja.m_ActivationTick = ActivationTick; }
void SetNinjaCurrentMoveTime(int CurrentMoveTime) { m_Ninja.m_CurrentMoveTime = CurrentMoveTime; }
bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; }
void SetWeaponAmmo(int Type, int Value) { m_Core.m_aWeapons[Type].m_Ammo = Value; }
void SetNinjaActivationDir(vec2 ActivationDir) { m_Core.m_Ninja.m_ActivationDir = ActivationDir; }
void SetNinjaActivationTick(int ActivationTick) { m_Core.m_Ninja.m_ActivationTick = ActivationTick; }
void SetNinjaCurrentMoveTime(int CurrentMoveTime) { m_Core.m_Ninja.m_CurrentMoveTime = CurrentMoveTime; }
int GetCID() { return m_ID; }
void SetInput(CNetObj_PlayerInput *pNewInput)
{
@ -133,8 +132,8 @@ public:
int GetAttackTick() { return m_AttackTick; }
int GetStrongWeakID() { return m_StrongWeakID; }
CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended = 0);
void Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, bool IsLocal);
CCharacter(CGameWorld *pGameWorld, int ID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended = 0, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo = 0);
void Read(CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, bool IsLocal);
void SetCoreWorld(CGameWorld *pGameWorld);
int m_LastSnapWeapon;
@ -153,14 +152,6 @@ private:
int m_aHitObjects[10];
int m_NumObjectsHit;
struct WeaponStat
{
int m_AmmoRegenStart;
int m_Ammo;
int m_Ammocost;
bool m_Got;
} m_aWeapons[NUM_WEAPONS];
int m_LastWeapon;
int m_QueuedWeapon;
@ -178,15 +169,6 @@ private:
int m_NumInputs;
// ninja
struct NinjaStat
{
vec2 m_ActivationDir;
int m_ActivationTick;
int m_CurrentMoveTime;
int m_OldVelAmount;
} m_Ninja;
// the player core for the physics
CCharacterCore m_Core;

View file

@ -346,16 +346,16 @@ void CGameWorld::NetObjBegin()
OnModified();
}
void CGameWorld::NetCharAdd(int ObjID, CNetObj_Character *pCharObj, CNetObj_DDNetCharacter *pExtended, int GameTeam, bool IsLocal)
void CGameWorld::NetCharAdd(int ObjID, CNetObj_Character *pCharObj, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, int GameTeam, bool IsLocal)
{
CCharacter *pChar;
if((pChar = (CCharacter *)GetEntity(ObjID, ENTTYPE_CHARACTER)))
{
pChar->Read(pCharObj, pExtended, IsLocal);
pChar->Read(pCharObj, pExtended, pExtendedDisplayInfo, IsLocal);
pChar->Keep();
}
else
pChar = new CCharacter(this, ObjID, pCharObj, pExtended);
pChar = new CCharacter(this, ObjID, pCharObj, pExtended, pExtendedDisplayInfo);
if(pChar)
pChar->m_GameTeam = GameTeam;

View file

@ -80,7 +80,7 @@ public:
void OnModified();
void NetObjBegin();
void NetCharAdd(int ObjID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, int GameTeam, bool IsLocal);
void NetCharAdd(int ObjID, CNetObj_Character *pChar, CNetObj_DDNetCharacter *pExtended, CNetObj_DDNetCharacterDisplayInfo *pExtendedDisplayInfo, int GameTeam, bool IsLocal);
void NetObjAdd(int ObjID, int ObjType, const void *pObjData, const CNetObj_EntityEx *pDataEx);
void NetObjEnd(int LocalID);
void CopyWorld(CGameWorld *pFrom);

View file

@ -102,7 +102,9 @@ void CCharacterCore::Reset()
m_HasTelegunGun = false;
m_HasTelegunGrenade = false;
m_HasTelegunLaser = false;
m_FreezeTick = 0;
m_FreezeEnd = 0;
m_IsInFreeze = false;
m_DeepFrozen = false;
m_LiveFrozen = false;
@ -132,35 +134,51 @@ void CCharacterCore::Tick(bool UseInput)
float Accel = Grounded ? m_Tuning.m_GroundControlAccel : m_Tuning.m_AirControlAccel;
float Friction = Grounded ? m_Tuning.m_GroundFriction : m_Tuning.m_AirFriction;
// handle jumping
// 1 bit = to keep track if a jump has been made on this input (player is holding space bar)
// 2 bit = to track if all air-jumps have been used up (tee gets dark feet)
if(Grounded)
{
m_Jumped &= ~2;
m_JumpedTotal = 0;
}
// handle input
if(UseInput)
{
m_Direction = m_Input.m_Direction;
// setup angle
float tmp_angle = atan2f(m_Input.m_TargetY, m_Input.m_TargetX);
if(tmp_angle < -(pi / 2.0f))
float TmpAngle = atan2f(m_Input.m_TargetY, m_Input.m_TargetX);
if(TmpAngle < -(pi / 2.0f))
{
m_Angle = (int)((tmp_angle + (2.0f * pi)) * 256.0f);
m_Angle = (int)((TmpAngle + (2.0f * pi)) * 256.0f);
}
else
{
m_Angle = (int)(tmp_angle * 256.0f);
m_Angle = (int)(TmpAngle * 256.0f);
}
// handle jump
if(m_Input.m_Jump)
{
if(!(m_Jumped & 1))
if(!(m_Jumped & 1) && m_Jumps != 0)
{
if(Grounded)
{
m_TriggeredEvents |= COREEVENT_GROUND_JUMP;
m_Vel.y = -m_Tuning.m_GroundJumpImpulse;
m_Jumped |= 1;
m_JumpedTotal = 1;
if(m_Jumps > 1)
{
m_Jumped |= 1;
}
else
{
m_Jumped |= 3;
}
m_JumpedTotal = 0;
}
else if(!(m_Jumped & 2))
else if(!(m_Jumped & 2) && m_Jumps >= 1)
{
m_TriggeredEvents |= COREEVENT_AIR_JUMP;
m_Vel.y = -m_Tuning.m_AirJumpImpulse;
@ -170,7 +188,9 @@ void CCharacterCore::Tick(bool UseInput)
}
}
else
{
m_Jumped &= ~1;
}
// handle hook
if(m_Input.m_Hook)
@ -201,15 +221,6 @@ void CCharacterCore::Tick(bool UseInput)
if(m_Direction == 0)
m_Vel.x *= Friction;
// handle jumping
// 1 bit = to keep track if a jump has been made on this input (player is holding space bar)
// 2 bit = to keep track if a air-jump has been made (tee gets dark feet)
if(Grounded)
{
m_Jumped &= ~2;
m_JumpedTotal = 0;
}
// do hook
if(m_HookState == HOOK_IDLE)
{
@ -520,7 +531,7 @@ void CCharacterCore::Write(CNetObj_CharacterCore *pObjCore)
pObjCore->m_Angle = m_Angle;
}
void CCharacterCore::Read(const CNetObj_CharacterCore *pObjCore)
void CCharacterCore::ReadCharacterCore(const CNetObj_CharacterCore *pObjCore)
{
m_Pos.x = pObjCore->m_X;
m_Pos.y = pObjCore->m_Y;
@ -538,6 +549,11 @@ void CCharacterCore::Read(const CNetObj_CharacterCore *pObjCore)
m_Angle = pObjCore->m_Angle;
}
void CCharacterCore::ReadCharacter(const CNetObj_Character *pObjChar)
{
m_ActiveWeapon = pObjChar->m_Weapon;
ReadCharacterCore((const CNetObj_CharacterCore *)pObjChar);
}
void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
{
// Collision
@ -568,14 +584,31 @@ void CCharacterCore::ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet)
m_HasTelegunGun = pObjDDNet->m_Flags & CHARACTERFLAG_TELEGUN_GUN;
m_HasTelegunLaser = pObjDDNet->m_Flags & CHARACTERFLAG_TELEGUN_LASER;
// Weapons
m_aWeapons[WEAPON_HAMMER].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_HAMMER) != 0;
m_aWeapons[WEAPON_GUN].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_GUN) != 0;
m_aWeapons[WEAPON_SHOTGUN].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_SHOTGUN) != 0;
m_aWeapons[WEAPON_GRENADE].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_GRENADE) != 0;
m_aWeapons[WEAPON_LASER].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_LASER) != 0;
m_aWeapons[WEAPON_NINJA].m_Got = (pObjDDNet->m_Flags & CHARACTERFLAG_WEAPON_NINJA) != 0;
// Available jumps
m_Jumps = pObjDDNet->m_Jumps;
}
void CCharacterCore::ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet)
{
m_JumpedTotal = pObjDDNet->m_JumpedTotal;
m_Ninja.m_ActivationTick = pObjDDNet->m_NinjaActivationTick;
m_FreezeTick = pObjDDNet->m_FreezeTick;
m_IsInFreeze = pObjDDNet->m_IsInFreeze;
}
void CCharacterCore::Quantize()
{
CNetObj_CharacterCore Core;
Write(&Core);
Read(&Core);
ReadCharacterCore(&Core);
}
// DDRace

View file

@ -221,11 +221,29 @@ public:
int m_HookTick;
int m_HookState;
int m_HookedPlayer;
int m_ActiveWeapon;
struct WeaponStat
{
int m_AmmoRegenStart;
int m_Ammo;
int m_Ammocost;
bool m_Got;
} m_aWeapons[NUM_WEAPONS];
// ninja
struct
{
vec2 m_ActivationDir;
int m_ActivationTick;
int m_CurrentMoveTime;
int m_OldVelAmount;
} m_Ninja;
bool m_NewHook;
int m_Jumped;
// m_JumpedTotal counts the jumps performed in the air
int m_JumpedTotal;
int m_Jumps;
@ -240,7 +258,8 @@ public:
void Tick(bool UseInput);
void Move();
void Read(const CNetObj_CharacterCore *pObjCore);
void ReadCharacterCore(const CNetObj_CharacterCore *pObjCore);
void ReadCharacter(const CNetObj_Character *pObjChar);
void Write(CNetObj_CharacterCore *pObjCore);
void Quantize();
@ -258,6 +277,7 @@ public:
void SetTeamsCore(CTeamsCore *pTeams);
void SetTeleOuts(std::map<int, std::vector<vec2>> *pTeleOuts);
void ReadDDNet(const CNetObj_DDNetCharacter *pObjDDNet);
void ReadDDNetDisplayInfo(const CNetObj_DDNetCharacterDisplayInfo *pObjDDNet);
bool m_Solo;
bool m_Jetpack;
bool m_NoCollision;
@ -272,7 +292,9 @@ public:
bool m_HasTelegunGun;
bool m_HasTelegunGrenade;
bool m_HasTelegunLaser;
int m_FreezeTick;
int m_FreezeEnd;
bool m_IsInFreeze;
bool m_DeepFrozen;
bool m_LiveFrozen;
CTuningParams m_Tuning;

View file

@ -158,14 +158,14 @@ void CCharacter::HandleJetpack()
if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses)
WillFire = true;
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
WillFire = true;
if(!WillFire)
return;
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo || m_FreezeTime)
{
return;
}
@ -192,14 +192,14 @@ void CCharacter::HandleNinja()
if(m_Core.m_ActiveWeapon != WEAPON_NINJA)
return;
if((Server()->Tick() - m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000))
if((Server()->Tick() - m_Core.m_Ninja.m_ActivationTick) > (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000))
{
// time's up, return
RemoveNinja();
return;
}
int NinjaTime = m_Ninja.m_ActivationTick + (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000) - Server()->Tick();
int NinjaTime = m_Core.m_Ninja.m_ActivationTick + (g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000) - Server()->Tick();
if(NinjaTime % Server()->TickSpeed() == 0 && NinjaTime / Server()->TickSpeed() <= 5)
{
@ -211,18 +211,18 @@ void CCharacter::HandleNinja()
// force ninja Weapon
SetWeapon(WEAPON_NINJA);
m_Ninja.m_CurrentMoveTime--;
m_Core.m_Ninja.m_CurrentMoveTime--;
if(m_Ninja.m_CurrentMoveTime == 0)
if(m_Core.m_Ninja.m_CurrentMoveTime == 0)
{
// reset velocity
m_Core.m_Vel = m_Ninja.m_ActivationDir * m_Ninja.m_OldVelAmount;
m_Core.m_Vel = m_Core.m_Ninja.m_ActivationDir * m_Core.m_Ninja.m_OldVelAmount;
}
if(m_Ninja.m_CurrentMoveTime > 0)
if(m_Core.m_Ninja.m_CurrentMoveTime > 0)
{
// Set velocity
m_Core.m_Vel = m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity;
m_Core.m_Vel = m_Core.m_Ninja.m_ActivationDir * g_pData->m_Weapons.m_Ninja.m_Velocity;
vec2 OldPos = m_Pos;
GameServer()->Collision()->MoveBox(&m_Core.m_Pos, &m_Core.m_Vel, vec2(GetProximityRadius(), GetProximityRadius()), 0.f);
@ -285,7 +285,7 @@ void CCharacter::HandleNinja()
void CCharacter::DoWeaponSwitch()
{
// make sure we can switch
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_aWeapons[WEAPON_NINJA].m_Got || !m_aWeapons[m_QueuedWeapon].m_Got)
if(m_ReloadTimer != 0 || m_QueuedWeapon == -1 || m_Core.m_aWeapons[WEAPON_NINJA].m_Got || !m_Core.m_aWeapons[m_QueuedWeapon].m_Got)
return;
// switch Weapon
@ -300,7 +300,7 @@ void CCharacter::HandleWeaponSwitch()
bool Anything = false;
for(int i = 0; i < NUM_WEAPONS - 1; ++i)
if(m_aWeapons[i].m_Got)
if(m_Core.m_aWeapons[i].m_Got)
Anything = true;
if(!Anything)
return;
@ -313,7 +313,7 @@ void CCharacter::HandleWeaponSwitch()
while(Next) // Next Weapon selection
{
WantedWeapon = (WantedWeapon + 1) % NUM_WEAPONS;
if(m_aWeapons[WantedWeapon].m_Got)
if(m_Core.m_aWeapons[WantedWeapon].m_Got)
Next--;
}
}
@ -323,7 +323,7 @@ void CCharacter::HandleWeaponSwitch()
while(Prev) // Prev Weapon selection
{
WantedWeapon = (WantedWeapon - 1) < 0 ? NUM_WEAPONS - 1 : WantedWeapon - 1;
if(m_aWeapons[WantedWeapon].m_Got)
if(m_Core.m_aWeapons[WantedWeapon].m_Got)
Prev--;
}
}
@ -333,7 +333,7 @@ void CCharacter::HandleWeaponSwitch()
WantedWeapon = m_Input.m_WantedWeapon - 1;
// check for insane values
if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_Core.m_ActiveWeapon && m_aWeapons[WantedWeapon].m_Got)
if(WantedWeapon >= 0 && WantedWeapon < NUM_WEAPONS && WantedWeapon != m_Core.m_ActiveWeapon && m_Core.m_aWeapons[WantedWeapon].m_Got)
m_QueuedWeapon = WantedWeapon;
DoWeaponSwitch();
@ -372,7 +372,7 @@ void CCharacter::FireWeapon()
if(CountInput(m_LatestPrevInput.m_Fire, m_LatestInput.m_Fire).m_Presses)
WillFire = true;
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(FullAuto && (m_LatestInput.m_Fire & 1) && m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
WillFire = true;
if(!WillFire)
@ -390,7 +390,7 @@ void CCharacter::FireWeapon()
}
// check for ammo
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo)
{
/*// 125ms is a magical limit of how fast a human can click
m_ReloadTimer = 125 * Server()->TickSpeed() / 1000;
@ -576,9 +576,9 @@ void CCharacter::FireWeapon()
// reset Hit objects
m_NumObjectsHit = 0;
m_Ninja.m_ActivationDir = Direction;
m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
m_Core.m_Ninja.m_ActivationDir = Direction;
m_Core.m_Ninja.m_CurrentMoveTime = g_pData->m_Weapons.m_Ninja.m_Movetime * Server()->TickSpeed() / 1000;
m_Core.m_Ninja.m_OldVelAmount = length(m_Core.m_Vel);
GameServer()->CreateSound(m_Pos, SOUND_NINJA_FIRE, Teams()->TeamMask(Team(), -1, m_pPlayer->GetCID()));
}
@ -587,8 +587,8 @@ void CCharacter::FireWeapon()
m_AttackTick = Server()->Tick();
/*if(m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo > 0) // -1 == unlimited
m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo--;*/
/*if(m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo > 0) // -1 == unlimited
m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo--;*/
if(!m_ReloadTimer)
{
@ -623,21 +623,21 @@ void CCharacter::HandleWeapons()
void CCharacter::GiveNinja()
{
m_Ninja.m_ActivationTick = Server()->Tick();
m_aWeapons[WEAPON_NINJA].m_Got = true;
m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
m_Core.m_Ninja.m_ActivationTick = Server()->Tick();
m_Core.m_aWeapons[WEAPON_NINJA].m_Got = true;
m_Core.m_aWeapons[WEAPON_NINJA].m_Ammo = -1;
if(m_Core.m_ActiveWeapon != WEAPON_NINJA)
m_LastWeapon = m_Core.m_ActiveWeapon;
m_Core.m_ActiveWeapon = WEAPON_NINJA;
if(!m_aWeapons[WEAPON_NINJA].m_Got)
if(!m_Core.m_aWeapons[WEAPON_NINJA].m_Got)
GameServer()->CreateSound(m_Pos, SOUND_PICKUP_NINJA, Teams()->TeamMask(Team(), -1, m_pPlayer->GetCID()));
}
void CCharacter::RemoveNinja()
{
m_Ninja.m_CurrentMoveTime = 0;
m_aWeapons[WEAPON_NINJA].m_Got = false;
m_Core.m_Ninja.m_CurrentMoveTime = 0;
m_Core.m_aWeapons[WEAPON_NINJA].m_Got = false;
m_Core.m_ActiveWeapon = m_LastWeapon;
SetWeapon(m_Core.m_ActiveWeapon);
@ -863,12 +863,12 @@ void CCharacter::TickPaused()
{
++m_AttackTick;
++m_DamageTakenTick;
++m_Ninja.m_ActivationTick;
++m_Core.m_Ninja.m_ActivationTick;
++m_ReckoningTick;
if(m_LastAction != -1)
++m_LastAction;
if(m_aWeapons[m_Core.m_ActiveWeapon].m_AmmoRegenStart > -1)
++m_aWeapons[m_Core.m_ActiveWeapon].m_AmmoRegenStart;
if(m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_AmmoRegenStart > -1)
++m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_AmmoRegenStart;
if(m_EmoteStop > -1)
++m_EmoteStop;
}
@ -1089,8 +1089,8 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID)
{
Health = m_Health;
Armor = m_Armor;
if(m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo > 0)
AmmoCount = (!m_FreezeTime) ? m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo : 0;
if(m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo > 0)
AmmoCount = (!m_FreezeTime) ? m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Ammo : 0;
}
if(GetPlayer()->m_Afk || GetPlayer()->IsPaused())
@ -1152,9 +1152,9 @@ void CCharacter::SnapCharacter(int SnappingClient, int ID)
pCharacter->m_AmmoCount = AmmoCount;
if(m_FreezeTime > 0 || m_FreezeTime == -1 || m_DeepFreeze)
pCharacter->m_AmmoCount = m_FreezeTick + g_Config.m_SvFreezeDelay * Server()->TickSpeed();
pCharacter->m_AmmoCount = m_Core.m_FreezeTick + g_Config.m_SvFreezeDelay * Server()->TickSpeed();
else if(Weapon == WEAPON_NINJA)
pCharacter->m_AmmoCount = m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000;
pCharacter->m_AmmoCount = m_Core.m_Ninja.m_ActivationTick + g_pData->m_Weapons.m_Ninja.m_Duration * Server()->TickSpeed() / 1000;
pCharacter->m_Health = Health;
pCharacter->m_Armor = Armor;
@ -1228,15 +1228,15 @@ void CCharacter::Snap(int SnappingClient)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_TELEGUN_GRENADE;
if(m_Core.m_HasTelegunLaser)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_TELEGUN_LASER;
if(m_aWeapons[WEAPON_HAMMER].m_Got)
if(m_Core.m_aWeapons[WEAPON_HAMMER].m_Got)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_HAMMER;
if(m_aWeapons[WEAPON_GUN].m_Got)
if(m_Core.m_aWeapons[WEAPON_GUN].m_Got)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_GUN;
if(m_aWeapons[WEAPON_SHOTGUN].m_Got)
if(m_Core.m_aWeapons[WEAPON_SHOTGUN].m_Got)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_SHOTGUN;
if(m_aWeapons[WEAPON_GRENADE].m_Got)
if(m_Core.m_aWeapons[WEAPON_GRENADE].m_Got)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_GRENADE;
if(m_aWeapons[WEAPON_LASER].m_Got)
if(m_Core.m_aWeapons[WEAPON_LASER].m_Got)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_LASER;
if(m_Core.m_ActiveWeapon == WEAPON_NINJA)
pDDNetCharacter->m_Flags |= CHARACTERFLAG_WEAPON_NINJA;
@ -1249,6 +1249,18 @@ void CCharacter::Snap(int SnappingClient)
pDDNetCharacter->m_Jumps = m_Core.m_Jumps;
pDDNetCharacter->m_TeleCheckpoint = m_TeleCheckpoint;
pDDNetCharacter->m_StrongWeakID = m_StrongWeakID;
CNetObj_DDNetCharacterDisplayInfo *pDDNetCharacterDisplayInfo = static_cast<CNetObj_DDNetCharacterDisplayInfo *>(Server()->SnapNewItem(NETOBJTYPE_DDNETCHARACTERDISPLAYINFO, ID, sizeof(CNetObj_DDNetCharacterDisplayInfo)));
if(!pDDNetCharacterDisplayInfo)
return;
pDDNetCharacterDisplayInfo->m_JumpedTotal = m_Core.m_JumpedTotal;
pDDNetCharacterDisplayInfo->m_NinjaActivationTick = m_Core.m_Ninja.m_ActivationTick;
pDDNetCharacterDisplayInfo->m_FreezeTick = m_Core.m_FreezeTick;
pDDNetCharacterDisplayInfo->m_IsInFreeze = m_Core.m_IsInFreeze;
pDDNetCharacterDisplayInfo->m_IsInPracticeMode = Teams()->IsPractice(Team());
pDDNetCharacterDisplayInfo->m_TargetX = m_Core.m_Input.m_TargetX;
pDDNetCharacterDisplayInfo->m_TargetY = m_Core.m_Input.m_TargetY;
pDDNetCharacterDisplayInfo->m_RampValue = round_to_int(VelocityRamp(length(m_Core.m_Vel) * 50, m_Core.m_Tuning.m_VelrampStart, m_Core.m_Tuning.m_VelrampRange, m_Core.m_Tuning.m_VelrampCurvature) * 1000.0f);
}
// DDRace
@ -1483,7 +1495,9 @@ void CCharacter::HandleTiles(int Index)
// freeze
if(((m_TileIndex == TILE_FREEZE) || (m_TileFIndex == TILE_FREEZE)) && !m_Super && !m_DeepFreeze)
{
Freeze();
}
else if(((m_TileIndex == TILE_UNFREEZE) || (m_TileFIndex == TILE_UNFREEZE)) && !m_DeepFreeze)
UnFreeze();
@ -1603,7 +1617,7 @@ void CCharacter::HandleTiles(int Index)
if(m_Core.m_Vel.y > 0 && m_Core.m_Colliding && m_Core.m_LeftWall)
{
m_Core.m_LeftWall = false;
m_Core.m_JumpedTotal = m_Core.m_Jumps - 1;
m_Core.m_JumpedTotal = m_Core.m_Jumps >= 2 ? m_Core.m_Jumps - 2 : 0;
m_Core.m_Jumped = 1;
}
}
@ -1704,7 +1718,9 @@ void CCharacter::HandleTiles(int Index)
else if(GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_FREEZE && Team() != TEAM_SUPER)
{
if(GameServer()->Collision()->GetSwitchNumber(MapIndex) == 0 || GameServer()->Collision()->m_pSwitchers[GameServer()->Collision()->GetSwitchNumber(MapIndex)].m_Status[Team()])
{
Freeze(GameServer()->Collision()->GetSwitchDelay(MapIndex));
}
}
else if(GameServer()->Collision()->GetSwitchType(MapIndex) == TILE_DFREEZE && Team() != TEAM_SUPER)
{
@ -2080,7 +2096,7 @@ void CCharacter::DDRaceTick()
if(m_FreezeTime > 0)
m_FreezeTime--;
else
m_Ninja.m_ActivationTick = Server()->Tick();
m_Core.m_Ninja.m_ActivationTick = Server()->Tick();
m_Input.m_Direction = 0;
m_Input.m_Jump = 0;
m_Input.m_Hook = 0;
@ -2090,29 +2106,28 @@ void CCharacter::DDRaceTick()
HandleTuneLayer(); // need this before coretick
// check if the tee is in any type of freeze
int Index = GameServer()->Collision()->GetPureMapIndex(m_Pos);
const int aTiles[] = {
GameServer()->Collision()->GetTileIndex(Index),
GameServer()->Collision()->GetFTileIndex(Index),
GameServer()->Collision()->GetSwitchType(Index)};
m_Core.m_IsInFreeze = false;
for(const int Tile : aTiles)
{
if(Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE)
{
m_Core.m_IsInFreeze = 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))
{
int Index = GameServer()->Collision()->GetPureMapIndex(m_Pos);
const int aTiles[] = {
GameServer()->Collision()->GetTileIndex(Index),
GameServer()->Collision()->GetFTileIndex(Index),
GameServer()->Collision()->GetSwitchType(Index)};
if(IsGrounded() && !m_DeepFreeze)
if(!m_Core.m_IsInFreeze && IsGrounded() && !m_DeepFreeze)
{
bool IsInFreeze = false;
for(const int Tile : aTiles)
{
if(Tile == TILE_FREEZE || Tile == TILE_DFREEZE || Tile == TILE_LFREEZE)
{
IsInFreeze = true;
break;
}
}
if(!IsInFreeze)
{
SetRescue();
}
SetRescue();
}
}
@ -2131,17 +2146,32 @@ void CCharacter::DDRacePostCoreTick()
if(m_DeepFreeze && !m_Super)
Freeze();
if(m_Core.m_Jumps == -1 && !m_Super)
if(m_Core.m_Jumps == -1)
{
// The player has only one ground jump, so his feet are always dark
m_Core.m_Jumped |= 2;
else if(m_Core.m_Jumps == 0 && !m_Super)
m_Core.m_Jumped = 3;
}
else if(m_Core.m_Jumps == 0)
{
// The player has no jumps at all, so his feet are always dark
m_Core.m_Jumped |= 2;
}
else if(m_Core.m_Jumps == 1 && m_Core.m_Jumped > 0)
m_Core.m_Jumped = 3;
{
// If the player has only one jump, each jump is the last one
m_Core.m_Jumped |= 2;
}
else if(m_Core.m_JumpedTotal < m_Core.m_Jumps - 1 && m_Core.m_Jumped > 1)
{
// The player has not yet used up all his jumps, so his feet remain light
m_Core.m_Jumped = 1;
}
if((m_Super || m_SuperJump) && m_Core.m_Jumped > 1)
{
// Super players and players with infinite jumps always have light feet
m_Core.m_Jumped = 1;
}
int CurrentIndex = GameServer()->Collision()->GetMapIndex(m_Pos);
HandleSkippableTiles(CurrentIndex);
@ -2186,11 +2216,11 @@ bool CCharacter::Freeze(int Seconds)
{
if((Seconds <= 0 || m_Super || m_FreezeTime == -1 || m_FreezeTime > Seconds * Server()->TickSpeed()) && Seconds != -1)
return false;
if(m_FreezeTick < Server()->Tick() - Server()->TickSpeed() || Seconds == -1)
if(m_Core.m_FreezeTick < Server()->Tick() - Server()->TickSpeed() || Seconds == -1)
{
m_Armor = 0;
m_FreezeTime = Seconds == -1 ? Seconds : Seconds * Server()->TickSpeed();
m_FreezeTick = Server()->Tick();
m_Core.m_FreezeTick = Server()->Tick();
return true;
}
return false;
@ -2206,10 +2236,10 @@ bool CCharacter::UnFreeze()
if(m_FreezeTime > 0)
{
m_Armor = 10;
if(!m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
if(!m_Core.m_aWeapons[m_Core.m_ActiveWeapon].m_Got)
m_Core.m_ActiveWeapon = WEAPON_GUN;
m_FreezeTime = 0;
m_FreezeTick = 0;
m_Core.m_FreezeTick = 0;
m_FrozenLastTick = true;
return true;
}
@ -2234,10 +2264,10 @@ void CCharacter::GiveWeapon(int Weapon, bool Remove)
}
else
{
m_aWeapons[Weapon].m_Ammo = -1;
m_Core.m_aWeapons[Weapon].m_Ammo = -1;
}
m_aWeapons[Weapon].m_Got = !Remove;
m_Core.m_aWeapons[Weapon].m_Got = !Remove;
}
void CCharacter::GiveAllWeapons()
@ -2252,7 +2282,7 @@ void CCharacter::ResetPickups()
{
for(int i = WEAPON_SHOTGUN; i < NUM_WEAPONS - 1; i++)
{
m_aWeapons[i].m_Got = false;
m_Core.m_aWeapons[i].m_Got = false;
if(m_Core.m_ActiveWeapon == i)
m_Core.m_ActiveWeapon = WEAPON_GUN;
}

View file

@ -98,15 +98,6 @@ private:
CEntity *m_apHitObjects[10];
int m_NumObjectsHit;
struct WeaponStat
{
int m_AmmoRegenStart;
int m_Ammo;
int m_Ammocost;
bool m_Got;
} m_aWeapons[NUM_WEAPONS];
int m_LastWeapon;
int m_QueuedWeapon;
@ -139,15 +130,6 @@ private:
int m_Health;
int m_Armor;
// ninja
struct
{
vec2 m_ActivationDir;
int m_ActivationTick;
int m_CurrentMoveTime;
int m_OldVelAmount;
} m_Ninja;
// the player core for the physics
CCharacterCore m_Core;
CGameTeams *m_pTeams = nullptr;
@ -203,7 +185,6 @@ public:
bool m_NinjaJetpack;
int m_TeamBeforeSuper;
int m_FreezeTime;
int m_FreezeTick;
bool m_FrozenLastTick;
bool m_DeepFreeze;
bool m_LiveFreeze;
@ -259,14 +240,14 @@ public:
CCharacterCore GetCore() { return m_Core; }
void SetCore(CCharacterCore Core) { m_Core = Core; }
CCharacterCore *Core() { return &m_Core; }
bool GetWeaponGot(int Type) { return m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_aWeapons[Type].m_Ammo; }
void SetWeaponAmmo(int Type, int Value) { m_aWeapons[Type].m_Ammo = Value; }
bool GetWeaponGot(int Type) { return m_Core.m_aWeapons[Type].m_Got; }
void SetWeaponGot(int Type, bool Value) { m_Core.m_aWeapons[Type].m_Got = Value; }
int GetWeaponAmmo(int Type) { return m_Core.m_aWeapons[Type].m_Ammo; }
void SetWeaponAmmo(int Type, int Value) { m_Core.m_aWeapons[Type].m_Ammo = Value; }
bool IsAlive() { return m_Alive; }
void SetNinjaActivationDir(vec2 ActivationDir) { m_Ninja.m_ActivationDir = ActivationDir; }
void SetNinjaActivationTick(int ActivationTick) { m_Ninja.m_ActivationTick = ActivationTick; }
void SetNinjaCurrentMoveTime(int CurrentMoveTime) { m_Ninja.m_CurrentMoveTime = CurrentMoveTime; }
void SetNinjaActivationDir(vec2 ActivationDir) { m_Core.m_Ninja.m_ActivationDir = ActivationDir; }
void SetNinjaActivationTick(int ActivationTick) { m_Core.m_Ninja.m_ActivationTick = ActivationTick; }
void SetNinjaCurrentMoveTime(int CurrentMoveTime) { m_Core.m_Ninja.m_CurrentMoveTime = CurrentMoveTime; }
int GetLastAction() const { return m_LastAction; }

View file

@ -26,10 +26,10 @@ void CSaveTee::Save(CCharacter *pChr)
for(int i = 0; i < NUM_WEAPONS; i++)
{
m_aWeapons[i].m_AmmoRegenStart = pChr->m_aWeapons[i].m_AmmoRegenStart;
m_aWeapons[i].m_Ammo = pChr->m_aWeapons[i].m_Ammo;
m_aWeapons[i].m_Ammocost = pChr->m_aWeapons[i].m_Ammocost;
m_aWeapons[i].m_Got = pChr->m_aWeapons[i].m_Got;
m_aWeapons[i].m_AmmoRegenStart = pChr->m_Core.m_aWeapons[i].m_AmmoRegenStart;
m_aWeapons[i].m_Ammo = pChr->m_Core.m_aWeapons[i].m_Ammo;
m_aWeapons[i].m_Ammocost = pChr->m_Core.m_aWeapons[i].m_Ammocost;
m_aWeapons[i].m_Got = pChr->m_Core.m_aWeapons[i].m_Got;
}
m_LastWeapon = pChr->m_LastWeapon;
@ -39,7 +39,7 @@ void CSaveTee::Save(CCharacter *pChr)
m_Jetpack = pChr->m_Jetpack;
m_NinjaJetpack = pChr->m_NinjaJetpack;
m_FreezeTime = pChr->m_FreezeTime;
m_FreezeTick = pChr->Server()->Tick() - pChr->m_FreezeTick;
m_FreezeTick = pChr->Server()->Tick() - pChr->m_Core.m_FreezeTick;
m_DeepFreeze = pChr->m_DeepFreeze;
m_LiveFreeze = pChr->m_LiveFreeze;
@ -120,11 +120,11 @@ void CSaveTee::Load(CCharacter *pChr, int Team, bool IsSwap)
for(int i = 0; i < NUM_WEAPONS; i++)
{
pChr->m_aWeapons[i].m_AmmoRegenStart = m_aWeapons[i].m_AmmoRegenStart;
pChr->m_Core.m_aWeapons[i].m_AmmoRegenStart = m_aWeapons[i].m_AmmoRegenStart;
// m_Ammo not used anymore for tracking freeze following https://github.com/ddnet/ddnet/pull/2086
pChr->m_aWeapons[i].m_Ammo = -1;
pChr->m_aWeapons[i].m_Ammocost = m_aWeapons[i].m_Ammocost;
pChr->m_aWeapons[i].m_Got = m_aWeapons[i].m_Got;
pChr->m_Core.m_aWeapons[i].m_Ammo = -1;
pChr->m_Core.m_aWeapons[i].m_Ammocost = m_aWeapons[i].m_Ammocost;
pChr->m_Core.m_aWeapons[i].m_Got = m_aWeapons[i].m_Got;
}
pChr->m_LastWeapon = m_LastWeapon;
@ -134,7 +134,7 @@ void CSaveTee::Load(CCharacter *pChr, int Team, bool IsSwap)
pChr->m_Jetpack = m_Jetpack;
pChr->m_NinjaJetpack = m_NinjaJetpack;
pChr->m_FreezeTime = m_FreezeTime;
pChr->m_FreezeTick = pChr->Server()->Tick() - m_FreezeTick;
pChr->m_Core.m_FreezeTick = pChr->Server()->Tick() - m_FreezeTick;
pChr->m_DeepFreeze = m_DeepFreeze;
pChr->m_LiveFreeze = m_LiveFreeze;

View file

@ -43,6 +43,10 @@ MACRO_CONFIG_INT(ClShowhud, cl_showhud, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE,
MACRO_CONFIG_INT(ClShowhudHealthAmmo, cl_showhud_healthammo, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Health + Ammo)")
MACRO_CONFIG_INT(ClShowhudScore, cl_showhud_score, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Score)")
MACRO_CONFIG_INT(ClShowhudTimer, cl_showhud_timer, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Timer)")
MACRO_CONFIG_INT(ClShowhudDummyActions, cl_showhud_dummy_actions, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Dummy Actions)")
MACRO_CONFIG_INT(ClShowhudPlayerPosition, cl_showhud_player_position, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Position)")
MACRO_CONFIG_INT(ClShowhudPlayerSpeed, cl_showhud_player_speed, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Speed)")
MACRO_CONFIG_INT(ClShowhudPlayerAngle, cl_showhud_player_angle, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame HUD (Player Aim Angle)")
MACRO_CONFIG_INT(ClShowRecord, cl_showrecord, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show old style DDRace client records")
MACRO_CONFIG_INT(ClShowNotifications, cl_shownotifications, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Make the client notify when someone highlights you")
MACRO_CONFIG_INT(ClShowEmotes, cl_showemotes, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show tee emotes")
@ -201,5 +205,6 @@ MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, 15, CFGFLAG_SERVER, "(Debug buil
#endif
MACRO_CONFIG_INT(DbgFocus, dbg_focus, 0, 0, 1, CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(DbgTuning, dbg_tuning, 0, 0, 1, CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(DbgTuning, dbg_tuning, 0, 0, 1, CFGFLAG_CLIENT, "Display information about the tuning parameters that affect the own player")
#endif