- Clear times upon round reset
Savestates:
-- Finish implementating savestates
-- Hook up savestate saving to touching a checkpoint
-- Delete savestates upon round reset
+- Softlock prevention
+- FIXME?: Splat damage is dealt AFTER health restoring of savestate loading if the player were to smash into something and die from another source during I think the same frame
- I hope that loading a savestate from Damage_Calculate hook when player is about to die and setting incoming
damage to 0 can still save them and dying (for example by suicide bind) isn't a hardcoded death :)
HUD:
- Display current round's players
-- Display splits
+- Display checkpoint splits
- Display how many players are about to lose this round and show that on splits
- Maybe show eliminated players on leaderboard, there should be a difference between 2nd place and Nth place for bragging rights
- Medals for placements?
#ifdef SVQC
#include <common/gamemodes/gamemode/ctscup/sv_ctscup.qc>
#endif
-#include <common/gamemodes/gamemode/ctscup/savestate.qc>
#ifdef SVQC
#include <common/gamemodes/gamemode/ctscup/sv_ctscup.qh>
#endif
-#include <common/gamemodes/gamemode/ctscup/savestate.qh>
+++ /dev/null
-//these files can be moved but while CTS Cup is WIP I'll keep them in CTS Cup's gamemode folder
-//files to update if moving: sv_ctscup.qh, ctscup folder's _mod files
-
-#include "savestate.qh"
-
-void SaveSaveState(entity player)
-{
- if (player.savestate)
- {
- player.savestate.origin = player.origin;
- player.savestate.v_angle = player.v_angle;
- player.savestate.angles = player.angles;
- player.savestate.velocity = player.velocity;
- //SetResource(player.savestate, RES_ROCKETS, GetResource(player, RES_ROCKETS));
- //SetResource(player.savestate, RES_BULLETS, GetResource(player, RES_BULLETS));
- //SetResource(player.savestate, RES_CELLS, GetResource(player, RES_CELLS));
- //SetResource(player.savestate, RES_PLASMA, GetResource(player, RES_PLASMA));
- //SetResource(player.savestate, RES_SHELLS, GetResource(player, RES_SHELLS));
- //SetResource(player.savestate, RES_FUEL, GetResource(player, RES_FUEL));
- //SetResource(player.savestate, RES_HEALTH, max(1, GetResource(player, RES_HEALTH)));
- //SetResource(player.savestate, RES_ARMOR, GetResource(player, RES_ARMOR));
- //STAT(WEAPONS, player.savestate) = STAT(WEAPONS, player);
- //StatusEffects_copy(player.statuseffects, player.savestate, 0);
- player.savestate.items = player.items;
- player.savestate.pauserotarmor_finished = player.pauserotarmor_finished;
- player.savestate.pauserothealth_finished = player.pauserothealth_finished;
- player.savestate.pauserotfuel_finished = player.pauserotfuel_finished;
- player.savestate.pauseregen_finished = player.pauseregen_finished;
- player.savestate.teleport_time = time;
- }
-}
-
-bool LoadSaveState(entity player)
-{
- if (player.savestate)
- {
- player.origin = player.savestate.origin;
- player.v_angle = player.savestate.v_angle;
- player.angles = player.savestate.angles;
- player.fixangle = true;
- player.velocity = player.savestate.velocity;
- //SetResource(player, RES_ROCKETS, GetResource(player.savestate, RES_ROCKETS));
- //SetResource(player, RES_BULLETS, GetResource(player.savestate, RES_BULLETS));
- //SetResource(player, RES_CELLS, GetResource(player.savestate, RES_CELLS));
- //SetResource(player, RES_PLASMA, GetResource(player.savestate, RES_PLASMA));
- //SetResource(player, RES_SHELLS, GetResource(player.savestate, RES_SHELLS));
- //SetResource(player, RES_FUEL, GetResource(player.savestate, RES_FUEL));
- //SetResource(player, RES_HEALTH, GetResource(player.savestate, RES_HEALTH));
- //SetResource(player, RES_ARMOR, GetResource(player.savestate, RES_ARMOR));
- //STAT(WEAPONS, player) = STAT(WEAPONS, player.savestate);
- //StatusEffects_copy(player.savestate, player.statuseffects, player.savestate.teleport_time);
- //StatusEffects_update(player);
- player.items = player.savestate.items;
- player.pauserotarmor_finished = time + player.savestate.pauserotarmor_finished - player.savestate.teleport_time;
- player.pauserothealth_finished = time + player.savestate.pauserothealth_finished - player.savestate.teleport_time;
- player.pauserotfuel_finished = time + player.savestate.pauserotfuel_finished - player.savestate.teleport_time;
- player.pauseregen_finished = time + player.savestate.pauseregen_finished - player.savestate.teleport_time;
-
- return true;
- }
- return false;
-}
-
-void DeleteSaveState(entity player)
-{
- if (player.savestate)
- delete(player.savestate);
-}
-
+++ /dev/null
-//#include <common/resources/cl_resources.qh>
-//#include <common/mutators/mutator/status_effects/status_effects.qh>
-//#include <lib/stats.qh>
-
-.entity savestate;
-
-void SaveSaveState(entity player);
-bool LoadSaveState(entity player);
-void DeleteSaveState(entity player);
-
-.vector origin;
-.vector v_angle;
-.vector angles;
-.bool fixangle;
-.vector velocity;
-.float items;
-.float pauserotarmor_finished;
-.float pauserothealth_finished;
-.float pauserotfuel_finished;
-.float pauseregen_finished;
-.float teleport_time;
SaveSaveState(player);
}
- // upon spawning for a new round within 1s of the round starting, save a savestate
- if ((time - 1) < (round_handler_GetEndTime() - autocvar_g_ctscup_maxroundlength))
+ //debug print
+ //print(sprintf("%f", time), " time \n");
+ //print(sprintf("%f", round_handler_GetEndTime()), " round_handler_GetEndTime() \n");
+ //print(sprintf("%f", (roundFirstFinisherTime + autocvar_g_ctscup_finishwait)), " (roundFirstFinisherTime + autocvar_g_ctscup_finishwait) \n\n");
+
+ // upon spawning for a new round, save a savestate instead of loading an old one
+ // for whatever reason on the frame players are reset and spawned for a new round to start
+ // round_handler_GetEndTime() still gives the end time for last round and time should be bigger than that
+ if ((time > round_handler_GetEndTime()) || (roundFirstFinisherTime && (time > (roundFirstFinisherTime + autocvar_g_ctscup_finishwait))))
{
SaveSaveState(player);
}
void CTSCUP_RoundStart()
{
+ roundFirstFinisherTime = 0;
+
CTSCUP_AliveParticipants();
}
MUTATOR_HOOKFUNCTION(ctscup, reset_map_players)
{
- roundFirstFinisherTime = 0;
+ // roundFirstFinisherTime = 0;
if (tournamentStarted) roundCounter++;
else CTSCUP_TournamentStart();
return canSpawn;
}
+MUTATOR_HOOKFUNCTION(ctscup, Race_Checkpoint)
+{
+ entity player = M_ARGV(0, entity);
+
+ SaveSaveState(player);
+}
+
MUTATOR_HOOKFUNCTION(ctscup, ClientCommand_Spectate)
{
entity player = M_ARGV(0, entity);
#pragma once
-#include "savestate.qh"
-
#include <common/mutators/base.qh>
#include <server/race.qh>
+#include <server/savestate.qh>
#include <common/gamemodes/gamemode/cts/sv_cts.qh>
void ctscup_Initialize();
#include <server/portals.qc>
#include <server/race.qc>
#include <server/round_handler.qc>
+#include <server/savestate.qc>
#include <server/scores.qc>
#include <server/scores_rules.qc>
#include <server/spawnpoints.qc>
#include <server/portals.qh>
#include <server/race.qh>
#include <server/round_handler.qh>
+#include <server/savestate.qh>
#include <server/scores.qh>
#include <server/scores_rules.qh>
#include <server/spawnpoints.qh>
/**/
MUTATOR_HOOKABLE(GetRecords, EV_GetRecords);
+#define EV_Race_Checkpoint(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /**/
+MUTATOR_HOOKABLE(Race_Checkpoint, EV_Race_Checkpoint);
+
#define EV_Race_FinalCheckpoint(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
}
fclose(fh);
}
+
+ MUTATOR_CALLHOOK(Race_Checkpoint, player);
}
else if(player.race_checkpoint == race_NextCheckpoint(this.race_checkpoint))
{
--- /dev/null
+#include "savestate.qh"
+
+void SaveSaveState(entity player)
+{
+ if (player.savestate)
+ {
+ player.savestate.origin = player.origin;
+ player.savestate.v_angle = player.v_angle;
+ player.savestate.angles = player.angles;
+ player.savestate.velocity = player.velocity;
+ SetResource(player.savestate, RES_ROCKETS, GetResource(player, RES_ROCKETS));
+ SetResource(player.savestate, RES_BULLETS, GetResource(player, RES_BULLETS));
+ SetResource(player.savestate, RES_CELLS, GetResource(player, RES_CELLS));
+ SetResource(player.savestate, RES_PLASMA, GetResource(player, RES_PLASMA));
+ SetResource(player.savestate, RES_SHELLS, GetResource(player, RES_SHELLS));
+ SetResource(player.savestate, RES_FUEL, GetResource(player, RES_FUEL));
+ SetResource(player.savestate, RES_HEALTH, max(1, GetResource(player, RES_HEALTH)));
+ SetResource(player.savestate, RES_ARMOR, GetResource(player, RES_ARMOR));
+ STAT(WEAPONS, player.savestate) = STAT(WEAPONS, player);
+ StatusEffects_copy(player.statuseffects, player.savestate, 0);
+ player.savestate.items = player.items;
+ player.savestate.pauserotarmor_finished = player.pauserotarmor_finished;
+ player.savestate.pauserothealth_finished = player.pauserothealth_finished;
+ player.savestate.pauserotfuel_finished = player.pauserotfuel_finished;
+ player.savestate.pauseregen_finished = player.pauseregen_finished;
+ player.savestate.teleport_time = time;
+ }
+}
+
+bool LoadSaveState(entity player)
+{
+ if (player.savestate)
+ {
+ player.origin = player.savestate.origin;
+ player.v_angle = player.savestate.v_angle;
+ player.angles = player.savestate.angles;
+ player.fixangle = true;
+ player.velocity = player.savestate.velocity;
+ SetResource(player, RES_ROCKETS, GetResource(player.savestate, RES_ROCKETS));
+ SetResource(player, RES_BULLETS, GetResource(player.savestate, RES_BULLETS));
+ SetResource(player, RES_CELLS, GetResource(player.savestate, RES_CELLS));
+ SetResource(player, RES_PLASMA, GetResource(player.savestate, RES_PLASMA));
+ SetResource(player, RES_SHELLS, GetResource(player.savestate, RES_SHELLS));
+ SetResource(player, RES_FUEL, GetResource(player.savestate, RES_FUEL));
+ SetResource(player, RES_HEALTH, GetResource(player.savestate, RES_HEALTH));
+ SetResource(player, RES_ARMOR, GetResource(player.savestate, RES_ARMOR));
+ STAT(WEAPONS, player) = STAT(WEAPONS, player.savestate);
+ StatusEffects_copy(player.savestate, player.statuseffects, player.savestate.teleport_time);
+ StatusEffects_update(player);
+ player.items = player.savestate.items;
+ player.pauserotarmor_finished = time + player.savestate.pauserotarmor_finished - player.savestate.teleport_time;
+ player.pauserothealth_finished = time + player.savestate.pauserothealth_finished - player.savestate.teleport_time;
+ player.pauserotfuel_finished = time + player.savestate.pauserotfuel_finished - player.savestate.teleport_time;
+ player.pauseregen_finished = time + player.savestate.pauseregen_finished - player.savestate.teleport_time;
+
+ return true;
+ }
+ return false;
+}
+
+void DeleteSaveState(entity player)
+{
+ if (player.savestate)
+ delete(player.savestate);
+}
+
--- /dev/null
+#include <common/resources/cl_resources.qh>
+#include <common/mutators/mutator/status_effects/status_effects.qh>
+#include <lib/stats.qh>
+
+.entity savestate;
+
+void SaveSaveState(entity player);
+bool LoadSaveState(entity player);
+void DeleteSaveState(entity player);
+
+.vector origin;
+.vector v_angle;
+.vector angles;
+.bool fixangle;
+.vector velocity;
+.float items;
+.float pauserotarmor_finished;
+.float pauserothealth_finished;
+.float pauserotfuel_finished;
+.float pauseregen_finished;
+.float teleport_time;