mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
WIP Race Checkpoints
MobjList count WIP: Checkpoints grant lap bonus help? can't allocate vector fixed tagged line iteration and collision detection Multiplayer animations and map retart fixes Clear between maps
This commit is contained in:
parent
495d875631
commit
df4e99b050
11 changed files with 272 additions and 91 deletions
|
|
@ -6805,6 +6805,22 @@ INT32 D_NumPlayers(void)
|
|||
return num;
|
||||
}
|
||||
|
||||
/** Returns the number of players racing, not spectating and includes bots
|
||||
* \return Number of players. Can be zero if we're running a ::dedicated
|
||||
* server.
|
||||
*/
|
||||
INT32 D_NumPlayersInRace(void)
|
||||
{
|
||||
INT32 numPlayers = 0;
|
||||
INT32 i;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator)
|
||||
numPlayers++;
|
||||
}
|
||||
return numPlayers;
|
||||
}
|
||||
|
||||
/** Return whether a player is a real person (not a CPU) and not spectating.
|
||||
*/
|
||||
boolean D_IsPlayerHumanAndGaming (INT32 player_number)
|
||||
|
|
|
|||
|
|
@ -657,6 +657,7 @@ extern UINT8 playernode[MAXPLAYERS];
|
|||
extern UINT8 playerconsole[MAXPLAYERS];
|
||||
|
||||
INT32 D_NumPlayers(void);
|
||||
INT32 D_NumPlayersInRace(void);
|
||||
boolean D_IsPlayerHumanAndGaming(INT32 player_number);
|
||||
|
||||
void D_ResetTiccmds(void);
|
||||
|
|
|
|||
|
|
@ -5248,7 +5248,7 @@ void G_InitNew(UINT8 pencoremode, INT32 map, boolean resetplayer, boolean skippr
|
|||
players[i].score = 0;
|
||||
}
|
||||
|
||||
if (resetplayer || map != gamemap)
|
||||
if (resetplayer || !(gametyperules & GTR_CHECKPOINTS && map == gamemap))
|
||||
{
|
||||
players[i].checkpointId = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -263,6 +263,9 @@ mobj_t *Obj_FindCheckpoint(INT32 id);
|
|||
boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *return_pos);
|
||||
angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint);
|
||||
void Obj_ActivateCheckpointInstantly(mobj_t* mobj);
|
||||
UINT32 Obj_GetCheckpointCount();
|
||||
void Obj_ClearCheckpoints();
|
||||
void Obj_DeactivateCheckpoints();
|
||||
|
||||
/* Rideroid / Rideroid Node */
|
||||
void Obj_RideroidThink(mobj_t *mo);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "byteptr.h"
|
||||
#include "k_race.h"
|
||||
#include "command.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// I was ALMOST tempted to start tearing apart all
|
||||
// of the map loading code and turning it into C++
|
||||
|
|
@ -510,7 +511,8 @@ void gpRank_t::Update(void)
|
|||
}
|
||||
|
||||
lvl->time = UINT32_MAX;
|
||||
lvl->totalLapPoints = K_RaceLapCount(gamemap - 1) * 2;
|
||||
|
||||
lvl->totalLapPoints = ( K_RaceLapCount(gamemap - 1) + Obj_GetCheckpointCount() )* 2;
|
||||
lvl->totalPrisons = maptargets;
|
||||
|
||||
UINT8 i;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "r_fps.h"
|
||||
#include "g_party.h"
|
||||
#include "g_input.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
boolean level_tally_t::UseBonuses(void)
|
||||
{
|
||||
|
|
@ -343,7 +344,7 @@ void level_tally_t::Init(player_t *player)
|
|||
if ((gametypes[gt]->rules & GTR_CIRCUIT) == GTR_CIRCUIT)
|
||||
{
|
||||
laps = player->lapPoints;
|
||||
totalLaps = numlaps;
|
||||
totalLaps = numlaps + numlaps * Obj_GetCheckpointCount();
|
||||
|
||||
if (inDuel == false)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct MobjList
|
|||
{
|
||||
ptr->next(front());
|
||||
front(ptr);
|
||||
count_++;
|
||||
}
|
||||
|
||||
void erase(T* node)
|
||||
|
|
@ -45,6 +46,7 @@ struct MobjList
|
|||
{
|
||||
front(node->next());
|
||||
node->next(nullptr);
|
||||
count_--;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -69,6 +71,7 @@ struct MobjList
|
|||
{
|
||||
prev->next(node->next());
|
||||
node->next(nullptr);
|
||||
count_--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -77,9 +80,12 @@ struct MobjList
|
|||
auto begin() const { return view().begin(); }
|
||||
auto end() const { return view().end(); }
|
||||
|
||||
auto count() { return count_; }
|
||||
|
||||
private:
|
||||
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
|
||||
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
|
||||
UINT32 count_ = 0;
|
||||
};
|
||||
|
||||
}; // namespace srb2
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../info.h"
|
||||
#include "../g_game.h"
|
||||
#include "../k_color.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_objects.h"
|
||||
|
|
@ -34,9 +35,17 @@
|
|||
#include "../sounds.h"
|
||||
#include "../tables.h"
|
||||
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::clamp;
|
||||
|
||||
extern mobj_t* svg_checkpoints;
|
||||
|
||||
#define checkpoint_id(o) ((o)->thing_args[0])
|
||||
#define checkpoint_linetag(o) ((o)->thing_args[1])
|
||||
#define checkpoint_extralength(o) ((o)->thing_args[2])
|
||||
#define checkpoint_other(o) ((o)->target)
|
||||
#define checkpoint_orb(o) ((o)->tracer)
|
||||
#define checkpoint_arm(o) ((o)->hnext)
|
||||
|
|
@ -51,12 +60,14 @@ namespace
|
|||
|
||||
struct LineOnDemand : line_t
|
||||
{
|
||||
LineOnDemand(const line_t* line) {}
|
||||
|
||||
LineOnDemand(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2) :
|
||||
line_t {
|
||||
.v1 = &v1_data_,
|
||||
.dx = x2 - x1,
|
||||
.dy = y2 - y1,
|
||||
.bbox = {std::max(y1, y2), std::min(y1, y2), std::min(x1, x2), std::max(x1, x2)},
|
||||
.bbox = {max(y1, y2), min(y1, y2), min(x1, x2), max(x1, x2)},
|
||||
},
|
||||
v1_data_ {.x = x1, .y = y1}
|
||||
{
|
||||
|
|
@ -76,6 +87,12 @@ struct LineOnDemand : line_t
|
|||
bbox[BOXLEFT] <= other.bbox[BOXRIGHT] && bbox[BOXRIGHT] >= other.bbox[BOXLEFT];
|
||||
}
|
||||
|
||||
bool overlaps(const line_t& other) const
|
||||
{
|
||||
return bbox[BOXTOP] >= other.bbox[BOXBOTTOM] && bbox[BOXBOTTOM] <= other.bbox[BOXTOP] &&
|
||||
bbox[BOXLEFT] <= other.bbox[BOXRIGHT] && bbox[BOXRIGHT] >= other.bbox[BOXLEFT];
|
||||
}
|
||||
|
||||
private:
|
||||
vertex_t v1_data_;
|
||||
};
|
||||
|
|
@ -170,6 +187,30 @@ struct Checkpoint : mobj_t
|
|||
deactivate();
|
||||
}
|
||||
|
||||
// will not work properly after a player enters intoa new lap
|
||||
INT32 players_passed()
|
||||
{
|
||||
INT32 pcount = 0;
|
||||
for (INT32 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && !players[i].spectator && players[i].checkpointId >= id())
|
||||
pcount++;
|
||||
}
|
||||
return pcount;
|
||||
}
|
||||
|
||||
boolean top_half_has_passed()
|
||||
{
|
||||
INT32 pcount = 0;
|
||||
INT32 winningpos = 1;
|
||||
|
||||
INT32 nump = D_NumPlayersInRace();
|
||||
winningpos = nump / 2;
|
||||
winningpos += nump % 2;
|
||||
|
||||
return players_passed() >= winningpos;
|
||||
}
|
||||
|
||||
void animate()
|
||||
{
|
||||
orient();
|
||||
|
|
@ -181,10 +222,11 @@ struct Checkpoint : mobj_t
|
|||
|
||||
if (!clip_var())
|
||||
{
|
||||
speed(speed() - FixedDiv(speed() / 50, std::max<fixed_t>(speed_multiplier(), 1)));
|
||||
speed(speed() - FixedDiv(speed() / 50, max<fixed_t>(speed_multiplier(), 1)));
|
||||
}
|
||||
}
|
||||
else if (!activated())
|
||||
|
||||
if (!top_half_has_passed())
|
||||
{
|
||||
sparkle_between(0);
|
||||
}
|
||||
|
|
@ -193,7 +235,7 @@ struct Checkpoint : mobj_t
|
|||
void twirl(angle_t dir, fixed_t multiplier)
|
||||
{
|
||||
var(0);
|
||||
speed_multiplier(std::clamp(multiplier, kMinSpeedMultiplier, kMaxSpeedMultiplier));
|
||||
speed_multiplier(clamp(multiplier, kMinSpeedMultiplier, kMaxSpeedMultiplier));
|
||||
speed(FixedDiv(kBaseSpeed, speed_multiplier()));
|
||||
reverse(AngleDeltaSigned(angle_to_other(), dir) > 0);
|
||||
|
||||
|
|
@ -266,7 +308,7 @@ private:
|
|||
kMinPivotDelay
|
||||
);
|
||||
|
||||
return to_angle(FixedDiv(std::max(var(), pos) - pos, FRACUNIT - pos)) / 4;
|
||||
return to_angle(FixedDiv(max(var(), pos) - pos, FRACUNIT - pos)) / 4;
|
||||
}
|
||||
|
||||
void orient()
|
||||
|
|
@ -304,7 +346,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void spawn_sparkle(const vector3_t& pos, fixed_t xy_momentum, fixed_t z_momentum, angle_t dir)
|
||||
void spawn_sparkle(const vector3_t& pos, fixed_t xy_momentum, fixed_t z_momentum, angle_t dir, skincolornum_t color = SKINCOLOR_ULTRAMARINE)
|
||||
{
|
||||
auto rng = [=](int units) { return P_RandomRange(PR_DECORATION, -(units) * scale, +(units) * scale); };
|
||||
|
||||
|
|
@ -324,10 +366,10 @@ private:
|
|||
if (xy_momentum)
|
||||
{
|
||||
P_Thrust(p, dir, xy_momentum);
|
||||
p->momz = P_RandomKey(PR_DECORATION, std::max<fixed_t>(z_momentum, 1));
|
||||
p->momz = P_RandomKey(PR_DECORATION, max<fixed_t>(z_momentum, 1));
|
||||
p->destscale = 0;
|
||||
p->scalespeed = p->scale / 35;
|
||||
p->color = SKINCOLOR_ULTRAMARINE;
|
||||
p->color = color;
|
||||
p->fuse = 0;
|
||||
|
||||
// Something lags at the start of the level. The
|
||||
|
|
@ -342,7 +384,7 @@ private:
|
|||
}
|
||||
else
|
||||
{
|
||||
p->color = K_RainbowColor(leveltime);
|
||||
p->color = color;
|
||||
p->fuse = 2;
|
||||
}
|
||||
}
|
||||
|
|
@ -369,7 +411,8 @@ private:
|
|||
{x + FixedMul(ofs, FCOS(a)), y + FixedMul(ofs, FSIN(a)), z + (kSparkleZ * scale)},
|
||||
momentum,
|
||||
momentum / 2,
|
||||
dir
|
||||
dir,
|
||||
activated() ? SKINCOLOR_GREEN : SKINCOLOR_ULTRAMARINE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -402,25 +445,41 @@ struct CheckpointManager
|
|||
auto begin() { return list_.begin(); }
|
||||
auto end() { return list_.end(); }
|
||||
|
||||
auto find(INT32 id) { return std::find_if(begin(), end(), [id](Checkpoint* chk) { return chk->id() == id; }); }
|
||||
auto find_checkpoint(INT32 id) {
|
||||
auto it = find_if(list_.begin(), list_.end(), [id](auto pair) { return pair.first->id() == id; });
|
||||
if (it != list_.end())
|
||||
{
|
||||
return it->first;
|
||||
}
|
||||
return static_cast<Checkpoint*>(nullptr);
|
||||
}
|
||||
|
||||
void push_front(Checkpoint* chk) { list_.push_front(chk); }
|
||||
// auto find_pair(Checkpoint* chk) {
|
||||
// pair<Checkpoint*, vector<line_t*>> retpair;
|
||||
// auto it = find_if(list_.begin(), list_.end(), [chk](auto pair) { return pair.first == chk; });
|
||||
// if (it != list_.end())
|
||||
// {
|
||||
// retpair = *it;
|
||||
// return retpair;
|
||||
// }
|
||||
// return static_cast<pair<Checkpoint*, vector<line_t*>>>(nullptr);
|
||||
// }
|
||||
|
||||
void erase(Checkpoint* chk) { list_.erase(chk); }
|
||||
|
||||
private:
|
||||
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
|
||||
};
|
||||
|
||||
CheckpointManager g_checkpoints;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_LinkCheckpoint(mobj_t* end)
|
||||
void remove_checkpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
auto it = find_if(list_.begin(), list_.end(), [&](auto pair) { return pair.first == chk; });
|
||||
if (it != list_.end())
|
||||
{
|
||||
list_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (chk->spawnpoint && chk->id() == 0)
|
||||
void link_checkpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
auto id = chk->id();
|
||||
if (chk->spawnpoint && id == 0)
|
||||
{
|
||||
auto msg = fmt::format(
|
||||
"Checkpoint thing (index #{}, thing type {}) has an invalid ID! ID must not be 0.\n",
|
||||
|
|
@ -431,10 +490,8 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
return;
|
||||
}
|
||||
|
||||
if (auto it = g_checkpoints.find(chk->id()); it != g_checkpoints.end())
|
||||
if (auto other = find_checkpoint(id))
|
||||
{
|
||||
Checkpoint* other = *it;
|
||||
|
||||
if (chk->spawnpoint && other->spawnpoint && chk->spawnpoint->angle != other->spawnpoint->angle)
|
||||
{
|
||||
auto msg = fmt::format(
|
||||
|
|
@ -447,25 +504,51 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
CONS_Alert(CONS_WARNING, "%s", msg.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
other->other(chk);
|
||||
chk->other(other);
|
||||
}
|
||||
else
|
||||
else // Checkpoint isn't in the list, find any associated tagged lines and make the pair
|
||||
{
|
||||
g_checkpoints.push_front(chk);
|
||||
vector<line_t*> checklines;
|
||||
if (checkpoint_linetag(chk))
|
||||
{
|
||||
INT32 li;
|
||||
INT32 tag = checkpoint_linetag(chk);
|
||||
TAG_ITER_LINES(tag, li)
|
||||
{
|
||||
line_t* line = lines + li;
|
||||
checklines.push_back(line);
|
||||
}
|
||||
}
|
||||
list_.emplace_back(chk, move(checklines));
|
||||
}
|
||||
|
||||
chk->gingerbread();
|
||||
}
|
||||
|
||||
void clear() { list_.clear(); }
|
||||
|
||||
auto count() { return list_.size(); }
|
||||
|
||||
private:
|
||||
vector<pair<Checkpoint*, vector<line_t*>>> list_;
|
||||
};
|
||||
|
||||
CheckpointManager g_checkpoints;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_LinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
g_checkpoints.link_checkpoint(end);
|
||||
}
|
||||
|
||||
void Obj_UnlinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
|
||||
g_checkpoints.erase(chk);
|
||||
|
||||
g_checkpoints.remove_checkpoint(end);
|
||||
P_RemoveMobj(chk->orb());
|
||||
P_RemoveMobj(chk->arm());
|
||||
}
|
||||
|
||||
void Obj_CheckpointThink(mobj_t* end)
|
||||
|
|
@ -480,39 +563,64 @@ void Obj_CheckpointThink(mobj_t* end)
|
|||
chk->animate();
|
||||
}
|
||||
|
||||
void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
||||
void __attribute__((optimize("O0"))) Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
||||
{
|
||||
LineOnDemand ray(old_x, old_y, player->mo->x, player->mo->y, player->mo->radius);
|
||||
|
||||
auto it = std::find_if(
|
||||
auto it = find_if(
|
||||
g_checkpoints.begin(),
|
||||
g_checkpoints.end(),
|
||||
[&](const Checkpoint* chk)
|
||||
[&](auto chkpair)
|
||||
{
|
||||
Checkpoint* chk = chkpair.first;
|
||||
if (!chk->valid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LineOnDemand gate = chk->crossing_line();
|
||||
LineOnDemand* gate;
|
||||
|
||||
if (chkpair.second.empty())
|
||||
{
|
||||
LineOnDemand dyngate = chk->crossing_line();
|
||||
if (!ray.overlaps(dyngate))
|
||||
return false;
|
||||
gate = &dyngate;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = find_if(
|
||||
chkpair.second.begin(),
|
||||
chkpair.second.end(),
|
||||
[&](const line_t* line)
|
||||
{
|
||||
return ray.overlaps(*line);
|
||||
}
|
||||
);
|
||||
|
||||
if (it == chkpair.second.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
line_t* line = *it;
|
||||
gate = static_cast<LineOnDemand*>(line);
|
||||
}
|
||||
|
||||
// Check if the bounding boxes of the two lines
|
||||
// overlap. This relies on the player movement not
|
||||
// being so large that it creates an oversized box,
|
||||
// but thankfully that doesn't seem to happen, under
|
||||
// normal circumstances.
|
||||
if (!ray.overlaps(gate))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
INT32 side = P_PointOnLineSide(player->mo->x, player->mo->y, &gate);
|
||||
INT32 oldside = P_PointOnLineSide(old_x, old_y, &gate);
|
||||
INT32 side = P_PointOnLineSide(player->mo->x, player->mo->y, gate);
|
||||
INT32 oldside = P_PointOnLineSide(old_x, old_y, gate);
|
||||
|
||||
if (side == oldside)
|
||||
{
|
||||
// Did not cross.
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -524,41 +632,54 @@ void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y)
|
|||
return;
|
||||
}
|
||||
|
||||
Checkpoint* chk = *it;
|
||||
Checkpoint* chk = it->first;
|
||||
|
||||
if (chk->activated())
|
||||
if (player->checkpointId == chk->id())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (Checkpoint* chk : g_checkpoints)
|
||||
if (player->position <= 1)
|
||||
{
|
||||
angle_t direction = R_PointToAngle2(old_x, old_y, player->mo->x, player->mo->y);
|
||||
fixed_t speed_multiplier = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
||||
chk->twirl(direction, speed_multiplier);
|
||||
chk->other()->twirl(direction, speed_multiplier);
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_CHECKPOINTS)
|
||||
{
|
||||
for (auto chkpair : g_checkpoints)
|
||||
{
|
||||
Checkpoint* chk = chkpair.first;
|
||||
if (chk->valid())
|
||||
{
|
||||
// Swing down any previously passed checkpoints.
|
||||
// TODO: this could look weird in multiplayer if
|
||||
// other players cross different checkpoints.
|
||||
chk->untwirl();
|
||||
chk->other()->untwirl();
|
||||
}
|
||||
}
|
||||
|
||||
angle_t direction = R_PointToAngle2(old_x, old_y, player->mo->x, player->mo->y);
|
||||
fixed_t speed_multiplier = FixedDiv(player->speed, K_GetKartSpeed(player, false, false));
|
||||
|
||||
chk->twirl(direction, speed_multiplier);
|
||||
chk->other()->twirl(direction, speed_multiplier);
|
||||
}
|
||||
|
||||
S_StartSound(player->mo, sfx_s3k63);
|
||||
|
||||
player->checkpointId = chk->id();
|
||||
|
||||
if (D_NumPlayersInRace() > 1 && !K_IsPlayerLosing(player))
|
||||
{
|
||||
if (player->position == 1)
|
||||
{
|
||||
player->lapPoints += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->lapPoints += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t* Obj_FindCheckpoint(INT32 id)
|
||||
{
|
||||
auto it = g_checkpoints.find(id);
|
||||
|
||||
return it != g_checkpoints.end() ? *it : nullptr;
|
||||
return g_checkpoints.find_checkpoint(id);
|
||||
}
|
||||
|
||||
boolean Obj_GetCheckpointRespawnPosition(const mobj_t* mobj, vector3_t* return_pos)
|
||||
|
|
@ -593,3 +714,27 @@ void Obj_ActivateCheckpointInstantly(mobj_t* mobj)
|
|||
chk->other()->activate();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a count of checkpoint gates, not objects
|
||||
UINT32 Obj_GetCheckpointCount()
|
||||
{
|
||||
return g_checkpoints.count();
|
||||
}
|
||||
|
||||
void Obj_ClearCheckpoints()
|
||||
{
|
||||
g_checkpoints.clear();
|
||||
}
|
||||
|
||||
void Obj_DeactivateCheckpoints()
|
||||
{
|
||||
for (auto chkpair : g_checkpoints)
|
||||
{
|
||||
Checkpoint* chk = chkpair.first;
|
||||
if (chk->valid())
|
||||
{
|
||||
chk->untwirl();
|
||||
chk->other()->untwirl();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -12561,8 +12561,6 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
|
|||
return false;
|
||||
break;
|
||||
case MT_CHECKPOINT_END:
|
||||
if (!(gametyperules & GTR_CHECKPOINTS))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@
|
|||
#include "k_hud.h" // K_ClearPersistentMessages
|
||||
#include "k_endcam.h"
|
||||
#include "k_credits.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// Replay names have time
|
||||
#if !defined (UNDER_CE)
|
||||
|
|
@ -8586,6 +8587,8 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
|
|||
|
||||
LUA_InvalidateLevel();
|
||||
|
||||
Obj_ClearCheckpoints();
|
||||
|
||||
for (ss = sectors; sectors+numsectors != ss; ss++)
|
||||
{
|
||||
Z_Free(ss->attached);
|
||||
|
|
|
|||
|
|
@ -2117,6 +2117,12 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
player->lapPoints++;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->position == 1 && !(gametyperules & GTR_CHECKPOINTS))
|
||||
{
|
||||
Obj_DeactivateCheckpoints();
|
||||
}
|
||||
player->checkpointId = 0;
|
||||
}
|
||||
|
||||
// Set up lap animation vars
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue