mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-22 21:41:31 +00:00
Merge branch 'fix-ufo-desync' into 'master'
Fix Battle UFO desync if midgame joins + UFO bobbing speed fix Closes #783 See merge request KartKrew/Kart!1671
This commit is contained in:
commit
3c9f4fe3b5
13 changed files with 330 additions and 172 deletions
|
|
@ -50,6 +50,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
p_floor.c
|
||||
p_inter.c
|
||||
p_lights.c
|
||||
p_link.cpp
|
||||
p_loop.c
|
||||
p_map.c
|
||||
p_mapthing.cpp
|
||||
|
|
|
|||
|
|
@ -821,7 +821,7 @@ void K_BattleInit(boolean singleplayercontext)
|
|||
}
|
||||
|
||||
g_battleufo.due = starttime;
|
||||
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID();
|
||||
g_battleufo.previousId = Obj_RandomBattleUFOSpawnerID() - 1;
|
||||
}
|
||||
|
||||
UINT8 K_Bumpers(player_t *player)
|
||||
|
|
|
|||
|
|
@ -184,8 +184,7 @@ void Obj_BattleUFODeath(mobj_t *ufo);
|
|||
void Obj_LinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_UnlinkBattleUFOSpawner(mobj_t *spawner);
|
||||
void Obj_SpawnBattleUFOFromSpawner(void);
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void);
|
||||
void Obj_ResetUFOSpawners(void);
|
||||
INT32 Obj_RandomBattleUFOSpawnerID(void);
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam);
|
||||
|
||||
/* Power-Up Aura */
|
||||
|
|
@ -230,7 +229,6 @@ void Obj_FakeShadowThink(mobj_t *shadow);
|
|||
boolean Obj_FakeShadowZ(const mobj_t *shadow, fixed_t *return_z, pslope_t **return_slope);
|
||||
|
||||
/* Checkpoints */
|
||||
void Obj_ResetCheckpoints(void);
|
||||
void Obj_LinkCheckpoint(mobj_t *end);
|
||||
void Obj_UnlinkCheckpoint(mobj_t *end);
|
||||
void Obj_CheckpointThink(mobj_t *end);
|
||||
|
|
|
|||
86
src/mobj_list.hpp
Normal file
86
src/mobj_list.hpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef mobj_list_hpp
|
||||
#define mobj_list_hpp
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "cxxutil.hpp"
|
||||
#include "mobj.hpp"
|
||||
#include "mobj_list_view.hpp"
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
// Requires:
|
||||
// void T::next(T*)
|
||||
// T* T::next() const
|
||||
template <typename T, mobj_t*& Head>
|
||||
struct MobjList
|
||||
{
|
||||
static_assert(std::is_convertible_v<T, mobj_t>);
|
||||
|
||||
MobjList() {}
|
||||
|
||||
T* front() const { return static_cast<T*>(Head); }
|
||||
bool empty() const { return !front(); }
|
||||
|
||||
void push_front(T* ptr)
|
||||
{
|
||||
ptr->next(front());
|
||||
front(ptr);
|
||||
}
|
||||
|
||||
void erase(T* node)
|
||||
{
|
||||
if (front() == node)
|
||||
{
|
||||
front(node->next());
|
||||
node->next(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto view = this->view();
|
||||
auto end = view.end();
|
||||
auto it = view.begin();
|
||||
|
||||
SRB2_ASSERT(it != end);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
T* prev = *it;
|
||||
|
||||
it++;
|
||||
|
||||
if (it == end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*it == node)
|
||||
{
|
||||
prev->next(node->next());
|
||||
node->next(nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto begin() const { return view().begin(); }
|
||||
auto end() const { return view().end(); }
|
||||
|
||||
private:
|
||||
void front(T* ptr) { Mobj::ManagedPtr {Head} = ptr; }
|
||||
auto view() const { return MobjListView(front(), [](T* node) { return node->next(); }); }
|
||||
};
|
||||
|
||||
}; // namespace srb2
|
||||
|
||||
#endif/*mobj_list_hpp*/
|
||||
|
|
@ -14,15 +14,17 @@
|
|||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "mobj.hpp"
|
||||
#include "p_mobj.h"
|
||||
|
||||
namespace srb2
|
||||
{
|
||||
|
||||
// for (T* ptr : MobjList(hnext(), [](T* ptr) { return ptr->hnext(); }))
|
||||
template <typename T, typename F, std::enable_if_t<std::is_convertible_v<T, Mobj>, bool> = true>
|
||||
template <typename T, typename F>
|
||||
struct MobjListView
|
||||
{
|
||||
static_assert(std::is_convertible_v<T, mobj_t>);
|
||||
|
||||
struct Iterator
|
||||
{
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
|
@ -32,12 +34,20 @@ struct MobjListView
|
|||
using reference = value_type;
|
||||
|
||||
Iterator(pointer ptr, F adv) : ptr_(deref(ptr)), adv_(adv) {}
|
||||
Iterator& operator=(const Iterator& b)
|
||||
{
|
||||
// adv_ may be a lambda. However, lambdas are not
|
||||
// copy assignable. Therefore, perform copy
|
||||
// construction instead!
|
||||
this->~Iterator();
|
||||
return *new(this) Iterator {b};
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& b) const { return ptr_ == b.ptr_; };
|
||||
bool operator!=(const Iterator& b) const { return ptr_ != b.ptr_; };
|
||||
|
||||
reference operator*() const { return ptr_; }
|
||||
pointer operator->() { return &ptr_; }
|
||||
pointer operator->() { return ptr_; }
|
||||
|
||||
Iterator& operator++()
|
||||
{
|
||||
|
|
@ -56,7 +66,7 @@ struct MobjListView
|
|||
pointer ptr_;
|
||||
F adv_;
|
||||
|
||||
static T* deref(T* ptr) { return ptr && ptr->valid() ? ptr : nullptr; }
|
||||
static T* deref(T* ptr) { return !P_MobjWasRemoved(ptr) ? ptr : nullptr; }
|
||||
};
|
||||
|
||||
MobjListView(T* ptr, F adv) : ptr_(ptr), adv_(adv) {}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
|
||||
#include "../math/fixed.hpp"
|
||||
#include "../mobj.hpp"
|
||||
#include "../mobj_list.hpp"
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../m_random.h"
|
||||
|
|
@ -9,101 +13,96 @@
|
|||
#include "../k_objects.h"
|
||||
#include "../k_kart.h"
|
||||
|
||||
using srb2::math::Fixed;
|
||||
using srb2::Mobj;
|
||||
using srb2::MobjList;
|
||||
|
||||
extern mobj_t* svg_battleUfoSpawners;
|
||||
|
||||
#define BATTLEUFO_LEG_ZOFFS (3*FRACUNIT) // Spawn height offset from the body
|
||||
#define BATTLEUFO_LEGS (3) // Number of UFO legs to spawn
|
||||
#define BATTLEUFO_BOB_AMP (4) // UFO bob strength
|
||||
#define BATTLEUFO_BOB_SPEED (TICRATE*2) // UFO bob speed
|
||||
|
||||
#define spawner_id(o) ((o)->thing_args[0])
|
||||
|
||||
#define ufo_spawner(o) ((o)->target)
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Spawner : mobj_t
|
||||
struct Spawner : Mobj
|
||||
{
|
||||
INT32 id() const { return spawner_id(this); }
|
||||
void thing_args() = delete;
|
||||
INT32 id() const { return this->mobj_t::thing_args[0]; }
|
||||
|
||||
void hnext() = delete;
|
||||
Spawner* next() const { return Mobj::hnext<Spawner>(); }
|
||||
void next(Spawner* n) { Mobj::hnext(n); }
|
||||
};
|
||||
|
||||
struct UFO : mobj_t
|
||||
struct UFO : Mobj
|
||||
{
|
||||
Spawner* spawner() const { return static_cast<Spawner*>(ufo_spawner(this)); }
|
||||
void spawner(Spawner* n) { P_SetTarget(&ufo_spawner(this), n); }
|
||||
void target() = delete;
|
||||
Spawner* spawner() const { return Mobj::target<Spawner>(); }
|
||||
void spawner(Spawner* n) { Mobj::target(n); }
|
||||
|
||||
void spawn_beam()
|
||||
{
|
||||
mobj_t *x;
|
||||
Mobj *x = spawn_from<Mobj>({0, 0, height / 4}, MT_BATTLEUFO_BEAM);
|
||||
|
||||
x = P_SpawnMobjFromMobj(this, 0, 0, FixedDiv(this->height / 4, this->scale), MT_BATTLEUFO_BEAM);
|
||||
x->renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE;
|
||||
x->colorized = true;
|
||||
x->color = SKINCOLOR_SAPPHIRE;
|
||||
}
|
||||
};
|
||||
|
||||
struct SpawnerCompare
|
||||
{
|
||||
bool operator()(const Spawner* a, const Spawner* b) const
|
||||
void bob()
|
||||
{
|
||||
return a->id() < b->id();
|
||||
// Copied and slightly modified from k_kart.c
|
||||
Fixed sine = (BATTLEUFO_BOB_AMP * Fixed {FSIN(M_TAU_FIXED * BATTLEUFO_BOB_SPEED * leveltime)}) / 4;
|
||||
|
||||
momz = flip(sine * scale());
|
||||
}
|
||||
};
|
||||
|
||||
class SpawnerList
|
||||
{
|
||||
private:
|
||||
std::set<Spawner*, SpawnerCompare> set_;
|
||||
MobjList<Spawner, svg_battleUfoSpawners> list_;
|
||||
|
||||
public:
|
||||
void insert(Spawner* spawner)
|
||||
{
|
||||
auto [it, inserted] = set_.insert(spawner);
|
||||
|
||||
if (inserted)
|
||||
{
|
||||
mobj_t* dummy = nullptr;
|
||||
P_SetTarget(&dummy, spawner);
|
||||
}
|
||||
}
|
||||
|
||||
void erase(Spawner* spawner)
|
||||
{
|
||||
if (set_.erase(spawner))
|
||||
{
|
||||
mobj_t* dummy = spawner;
|
||||
P_SetTarget(&dummy, nullptr);
|
||||
}
|
||||
}
|
||||
void insert(Spawner* spawner) { list_.push_front(spawner); }
|
||||
void erase(Spawner* spawner) { list_.erase(spawner); }
|
||||
|
||||
Spawner* next(INT32 order) const
|
||||
{
|
||||
auto it = std::upper_bound(
|
||||
set_.begin(),
|
||||
set_.end(),
|
||||
order,
|
||||
[](INT32 a, const Spawner* b) { return a < b->id(); }
|
||||
);
|
||||
using T = const Spawner*;
|
||||
|
||||
return it != set_.end() ? *it : *set_.begin();
|
||||
auto it = std::find_if(list_.begin(), list_.end(), [order](T p) { return order < p->id(); });
|
||||
auto min = [&](auto cmp) { return std::min_element(list_.begin(), list_.end(), cmp); };
|
||||
|
||||
return *(it != list_.end()
|
||||
? min([order](T a, T b) { return order < a->id() && a->id() < b->id(); })
|
||||
: min([](T a, T b) { return a->id() < b->id(); }));
|
||||
}
|
||||
|
||||
INT32 random_id() const
|
||||
{
|
||||
if (set_.empty())
|
||||
if (list_.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto it = set_.begin();
|
||||
auto it = list_.begin();
|
||||
std::size_t count = std::distance(it, list_.end());
|
||||
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, set_.size()));
|
||||
if (count > 1u)
|
||||
{
|
||||
std::advance(it, P_RandomKey(PR_BATTLEUFO, count - 1u));
|
||||
}
|
||||
|
||||
return (*std::prev(it == set_.begin() ? set_.end() : it))->id();
|
||||
return it->id();
|
||||
}
|
||||
|
||||
void spawn_ufo() const
|
||||
{
|
||||
if (set_.empty())
|
||||
if (list_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -123,10 +122,7 @@ void Obj_BattleUFOThink(mobj_t *mobj)
|
|||
{
|
||||
UFO* ufo = static_cast<UFO*>(mobj);
|
||||
|
||||
// Copied and slightly modified from k_kart.c
|
||||
fixed_t sine = FixedMul(ufo->scale, BATTLEUFO_BOB_AMP * FINESINE((((M_TAU_FIXED * BATTLEUFO_BOB_SPEED) * leveltime) >> ANGLETOFINESHIFT) & FINEMASK));
|
||||
fixed_t targz = FixedMul(ufo->scale, sine) * P_MobjFlip(ufo);
|
||||
ufo->momz = targz;
|
||||
ufo->bob();
|
||||
|
||||
if ((leveltime/2) & 1)
|
||||
{
|
||||
|
|
@ -227,16 +223,11 @@ void Obj_SpawnBattleUFOFromSpawner(void)
|
|||
g_spawners.spawn_ufo();
|
||||
}
|
||||
|
||||
INT32 Obj_GetFirstBattleUFOSpawnerID(void)
|
||||
INT32 Obj_RandomBattleUFOSpawnerID(void)
|
||||
{
|
||||
return g_spawners.random_id();
|
||||
}
|
||||
|
||||
void Obj_ResetUFOSpawners(void)
|
||||
{
|
||||
g_spawners = {};
|
||||
}
|
||||
|
||||
void Obj_BattleUFOBeamThink(mobj_t *beam)
|
||||
{
|
||||
P_SetObjectMomZ(beam, beam->info->speed, true);
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "../mobj_list.hpp"
|
||||
|
||||
#include "../doomdef.h"
|
||||
#include "../doomtype.h"
|
||||
#include "../info.h"
|
||||
|
|
@ -32,10 +33,13 @@
|
|||
#include "../sounds.h"
|
||||
#include "../tables.h"
|
||||
|
||||
extern mobj_t* svg_checkpoints;
|
||||
|
||||
#define checkpoint_id(o) ((o)->thing_args[0])
|
||||
#define checkpoint_other(o) ((o)->target)
|
||||
#define checkpoint_orb(o) ((o)->tracer)
|
||||
#define checkpoint_arm(o) ((o)->hnext)
|
||||
#define checkpoint_next(o) ((o)->hprev)
|
||||
#define checkpoint_var(o) ((o)->movedir)
|
||||
#define checkpoint_speed(o) ((o)->movecount)
|
||||
#define checkpoint_speed_multiplier(o) ((o)->movefactor)
|
||||
|
|
@ -120,6 +124,9 @@ struct Checkpoint : mobj_t
|
|||
Arm* arm() const { return static_cast<Arm*>(checkpoint_arm(this)); }
|
||||
void arm(Arm* n) { P_SetTarget(&checkpoint_arm(this), n); }
|
||||
|
||||
Checkpoint* next() const { return static_cast<Checkpoint*>(checkpoint_next(this)); }
|
||||
void next(Checkpoint* n) { P_SetTarget(&checkpoint_next(this), n); }
|
||||
|
||||
fixed_t var() const { return checkpoint_var(this); }
|
||||
void var(fixed_t n) { checkpoint_var(this) = n; }
|
||||
|
||||
|
|
@ -391,34 +398,23 @@ private:
|
|||
|
||||
struct CheckpointManager
|
||||
{
|
||||
auto begin() { return vec_.begin(); }
|
||||
auto end() { return vec_.end(); }
|
||||
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; }); }
|
||||
|
||||
void push_back(Checkpoint* chk) { vec_.push_back(chk); }
|
||||
void push_front(Checkpoint* chk) { list_.push_front(chk); }
|
||||
|
||||
void erase(const Checkpoint* chk)
|
||||
{
|
||||
if (auto it = std::find(vec_.begin(), vec_.end(), chk); it != end())
|
||||
{
|
||||
vec_.erase(it);
|
||||
}
|
||||
}
|
||||
void erase(Checkpoint* chk) { list_.erase(chk); }
|
||||
|
||||
private:
|
||||
std::vector<Checkpoint*> vec_;
|
||||
srb2::MobjList<Checkpoint, svg_checkpoints> list_;
|
||||
};
|
||||
|
||||
CheckpointManager g_checkpoints;
|
||||
|
||||
}; // namespace
|
||||
|
||||
void Obj_ResetCheckpoints(void)
|
||||
{
|
||||
g_checkpoints = {};
|
||||
}
|
||||
|
||||
void Obj_LinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
|
|
@ -456,7 +452,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
}
|
||||
else
|
||||
{
|
||||
g_checkpoints.push_back(chk);
|
||||
g_checkpoints.push_front(chk);
|
||||
}
|
||||
|
||||
chk->gingerbread();
|
||||
|
|
@ -464,7 +460,7 @@ void Obj_LinkCheckpoint(mobj_t* end)
|
|||
|
||||
void Obj_UnlinkCheckpoint(mobj_t* end)
|
||||
{
|
||||
auto chk = static_cast<const Checkpoint*>(end);
|
||||
auto chk = static_cast<Checkpoint*>(end);
|
||||
|
||||
g_checkpoints.erase(chk);
|
||||
|
||||
|
|
|
|||
49
src/p_link.cpp
Normal file
49
src/p_link.cpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "p_link.h"
|
||||
#include "p_mobj.h"
|
||||
|
||||
|
||||
#define LINK_PACK \
|
||||
svg_battleUfoSpawners,\
|
||||
svg_checkpoints
|
||||
|
||||
|
||||
using link = mobj_t*;
|
||||
using each_ref = std::initializer_list<std::reference_wrapper<mobj_t*>>;
|
||||
|
||||
link LINK_PACK;
|
||||
|
||||
void P_InitMobjPointers(void)
|
||||
{
|
||||
for (mobj_t*& head : each_ref {LINK_PACK})
|
||||
{
|
||||
head = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void P_SaveMobjPointers(void(*fn)(mobj_t*))
|
||||
{
|
||||
for (mobj_t* head : {LINK_PACK})
|
||||
{
|
||||
fn(head);
|
||||
}
|
||||
}
|
||||
|
||||
void P_LoadMobjPointers(void(*fn)(mobj_t**))
|
||||
{
|
||||
for (mobj_t*& head : each_ref {LINK_PACK})
|
||||
{
|
||||
fn(&head);
|
||||
}
|
||||
}
|
||||
27
src/p_link.h
Normal file
27
src/p_link.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// DR. ROBOTNIK'S RING RACERS
|
||||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2023 by James Robert Roman
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// terms of the GNU General Public License, version 2.
|
||||
// See the 'LICENSE' file for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef p_link_h
|
||||
#define p_link_h
|
||||
|
||||
#include "typedef.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void P_InitMobjPointers(void);
|
||||
void P_SaveMobjPointers(void(*callback)(mobj_t*));
|
||||
void P_LoadMobjPointers(void(*callback)(mobj_t**));
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif/*p_link_h*/
|
||||
36
src/p_mobj.c
36
src/p_mobj.c
|
|
@ -14538,24 +14538,10 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj)
|
|||
return true;
|
||||
}
|
||||
|
||||
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj)
|
||||
{
|
||||
mobj_t *mobj = NULL;
|
||||
size_t arg = SIZE_MAX;
|
||||
|
||||
mobj = P_SpawnMobj(x, y, z, type);
|
||||
mobj->spawnpoint = mthing;
|
||||
|
||||
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
|
||||
mobj->pitch = FixedAngle(mthing->pitch << FRACBITS);
|
||||
mobj->roll = FixedAngle(mthing->roll << FRACBITS);
|
||||
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
|
||||
mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
|
||||
|
||||
mobj->spritexscale = mthing->spritexscale;
|
||||
mobj->spriteyscale = mthing->spriteyscale;
|
||||
|
||||
P_SetThingTID(mobj, mthing->tid);
|
||||
|
||||
mobj->special = mthing->special;
|
||||
|
|
@ -14609,6 +14595,26 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y,
|
|||
mobj->script_stringargs[arg] = Z_Realloc(mobj->script_stringargs[arg], len + 1, PU_LEVEL, NULL);
|
||||
M_Memcpy(mobj->script_stringargs[arg], mthing->script_stringargs[arg], len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
||||
{
|
||||
mobj_t *mobj = NULL;
|
||||
|
||||
mobj = P_SpawnMobj(x, y, z, type);
|
||||
mobj->spawnpoint = mthing;
|
||||
|
||||
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
|
||||
mobj->pitch = FixedAngle(mthing->pitch << FRACBITS);
|
||||
mobj->roll = FixedAngle(mthing->roll << FRACBITS);
|
||||
|
||||
P_SetScale(mobj, FixedMul(mobj->scale, mthing->scale));
|
||||
mobj->destscale = FixedMul(mobj->destscale, mthing->scale);
|
||||
|
||||
mobj->spritexscale = mthing->spritexscale;
|
||||
mobj->spriteyscale = mthing->spriteyscale;
|
||||
|
||||
P_CopyMapThingSpecialFieldsToMobj(mthing, mobj);
|
||||
|
||||
if (!P_SetupSpawnedMapThing(mthing, mobj))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -557,6 +557,7 @@ fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const f
|
|||
fixed_t P_GetMapThingSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y);
|
||||
|
||||
mobj_t *P_SpawnMapThing(mapthing_t *mthing);
|
||||
void P_CopyMapThingSpecialFieldsToMobj(const mapthing_t *mthing, mobj_t *mobj);
|
||||
void P_SpawnHoop(mapthing_t *mthing);
|
||||
void P_SpawnItemPattern(mapthing_t *mthing);
|
||||
void P_SpawnItemLine(mapthing_t *mt1, mapthing_t *mt2);
|
||||
|
|
|
|||
131
src/p_saveg.c
131
src/p_saveg.c
|
|
@ -36,6 +36,7 @@
|
|||
#include "lua_script.h"
|
||||
#include "p_slopes.h"
|
||||
#include "m_cond.h" // netUnlocked
|
||||
#include "p_link.h"
|
||||
|
||||
// SRB2Kart
|
||||
#include "k_grandprix.h"
|
||||
|
|
@ -50,6 +51,8 @@
|
|||
savedata_t savedata;
|
||||
savedata_cup_t cupsavedata;
|
||||
|
||||
static savebuffer_t *current_savebuffer;
|
||||
|
||||
// Block UINT32s to attempt to ensure that the correct data is
|
||||
// being sent and received
|
||||
#define ARCHIVEBLOCK_MISC 0x7FEEDEED
|
||||
|
|
@ -3839,6 +3842,11 @@ static void SavePolyfadeThinker(savebuffer_t *save, const thinker_t *th, const U
|
|||
WRITEINT32(save->p, ht->timer);
|
||||
}
|
||||
|
||||
static void WriteMobjPointer(mobj_t *mobj)
|
||||
{
|
||||
WRITEUINT32(current_savebuffer->p, SaveMobjnum(mobj));
|
||||
}
|
||||
|
||||
static void P_NetArchiveThinkers(savebuffer_t *save)
|
||||
{
|
||||
const thinker_t *th;
|
||||
|
|
@ -3846,6 +3854,8 @@ static void P_NetArchiveThinkers(savebuffer_t *save)
|
|||
|
||||
WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS);
|
||||
|
||||
P_SaveMobjPointers(WriteMobjPointer);
|
||||
|
||||
for (i = 0; i < NUM_THINKERLISTS; i++)
|
||||
{
|
||||
UINT32 numsaved = 0;
|
||||
|
|
@ -4538,6 +4548,10 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
|
|||
mobj->script_stringargs[j][len] = '\0';
|
||||
}
|
||||
}
|
||||
else if (mobj->spawnpoint)
|
||||
{
|
||||
P_CopyMapThingSpecialFieldsToMobj(mobj->spawnpoint, mobj);
|
||||
}
|
||||
if (diff2 & MD2_FLOORSPRITESLOPE)
|
||||
{
|
||||
pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj);
|
||||
|
|
@ -5234,6 +5248,11 @@ static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker)
|
|||
return &ht->thinker;
|
||||
}
|
||||
|
||||
static void ReadMobjPointer(mobj_t **mobj_p)
|
||||
{
|
||||
*mobj_p = LoadMobj(READUINT32(current_savebuffer->p));
|
||||
}
|
||||
|
||||
static void P_NetUnArchiveThinkers(savebuffer_t *save)
|
||||
{
|
||||
thinker_t *currentthinker;
|
||||
|
|
@ -5269,6 +5288,8 @@ static void P_NetUnArchiveThinkers(savebuffer_t *save)
|
|||
// we don't want the removed mobjs to come back
|
||||
P_InitThinkers();
|
||||
|
||||
P_LoadMobjPointers(ReadMobjPointer);
|
||||
|
||||
// clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity
|
||||
for (i = 0; i < numsectors; i++)
|
||||
{
|
||||
|
|
@ -5572,12 +5593,26 @@ static inline void P_UnArchivePolyObjects(savebuffer_t *save)
|
|||
P_UnArchivePolyObj(save, &PolyObjects[i]);
|
||||
}
|
||||
|
||||
static mobj_t *RelinkMobj(mobj_t **ptr)
|
||||
{
|
||||
UINT32 temp = (UINT32)(size_t)*ptr;
|
||||
*ptr = NULL;
|
||||
return P_SetTarget(ptr, P_FindNewPosition(temp));
|
||||
}
|
||||
|
||||
static void RelinkMobjVoid(mobj_t **ptr)
|
||||
{
|
||||
RelinkMobj(ptr);
|
||||
}
|
||||
|
||||
static void P_RelinkPointers(void)
|
||||
{
|
||||
thinker_t *currentthinker;
|
||||
mobj_t *mobj;
|
||||
UINT32 temp, i;
|
||||
|
||||
P_LoadMobjPointers(RelinkMobjVoid);
|
||||
|
||||
// use info field (value = oldposition) to relink mobjs
|
||||
for (currentthinker = thlist[THINK_MOBJ].next; currentthinker != &thlist[THINK_MOBJ];
|
||||
currentthinker = currentthinker->next)
|
||||
|
|
@ -5592,37 +5627,27 @@ static void P_RelinkPointers(void)
|
|||
|
||||
if (mobj->tracer)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->tracer;
|
||||
mobj->tracer = NULL;
|
||||
if (!P_SetTarget(&mobj->tracer, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->tracer))
|
||||
CONS_Debug(DBG_GAMELOGIC, "tracer not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->target)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->target;
|
||||
mobj->target = NULL;
|
||||
if (!P_SetTarget(&mobj->target, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->target))
|
||||
CONS_Debug(DBG_GAMELOGIC, "target not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->hnext)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->hnext;
|
||||
mobj->hnext = NULL;
|
||||
if (!P_SetTarget(&mobj->hnext, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->hnext))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->hprev)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->hprev;
|
||||
mobj->hprev = NULL;
|
||||
if (!P_SetTarget(&mobj->hprev, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->hprev))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hprev not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->itnext)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->itnext;
|
||||
mobj->itnext = NULL;
|
||||
if (!P_SetTarget(&mobj->itnext, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->itnext))
|
||||
CONS_Debug(DBG_GAMELOGIC, "itnext not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->terrain)
|
||||
|
|
@ -5636,23 +5661,17 @@ static void P_RelinkPointers(void)
|
|||
}
|
||||
if (mobj->terrainOverlay)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->terrainOverlay;
|
||||
mobj->terrainOverlay = NULL;
|
||||
if (!P_SetTarget(&mobj->terrainOverlay, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->terrainOverlay))
|
||||
CONS_Debug(DBG_GAMELOGIC, "terrainOverlay not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->punt_ref)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->punt_ref;
|
||||
mobj->punt_ref = NULL;
|
||||
if (!P_SetTarget(&mobj->punt_ref, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->punt_ref))
|
||||
CONS_Debug(DBG_GAMELOGIC, "punt_ref not found on %d\n", mobj->type);
|
||||
}
|
||||
if (mobj->owner)
|
||||
{
|
||||
temp = (UINT32)(size_t)mobj->owner;
|
||||
mobj->owner = NULL;
|
||||
if (!P_SetTarget(&mobj->owner, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&mobj->owner))
|
||||
CONS_Debug(DBG_GAMELOGIC, "owner not found on %d\n", mobj->type);
|
||||
}
|
||||
}
|
||||
|
|
@ -5664,37 +5683,27 @@ static void P_RelinkPointers(void)
|
|||
|
||||
if (players[i].skybox.viewpoint)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].skybox.viewpoint;
|
||||
players[i].skybox.viewpoint = NULL;
|
||||
if (!P_SetTarget(&players[i].skybox.viewpoint, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].skybox.viewpoint))
|
||||
CONS_Debug(DBG_GAMELOGIC, "skybox.viewpoint not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].skybox.centerpoint)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].skybox.centerpoint;
|
||||
players[i].skybox.centerpoint = NULL;
|
||||
if (!P_SetTarget(&players[i].skybox.centerpoint, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].skybox.centerpoint))
|
||||
CONS_Debug(DBG_GAMELOGIC, "skybox.centerpoint not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].awayview.mobj)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].awayview.mobj;
|
||||
players[i].awayview.mobj = NULL;
|
||||
if (!P_SetTarget(&players[i].awayview.mobj, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].awayview.mobj))
|
||||
CONS_Debug(DBG_GAMELOGIC, "awayview.mobj not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].followmobj)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].followmobj;
|
||||
players[i].followmobj = NULL;
|
||||
if (!P_SetTarget(&players[i].followmobj, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].followmobj))
|
||||
CONS_Debug(DBG_GAMELOGIC, "followmobj not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].follower)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].follower;
|
||||
players[i].follower = NULL;
|
||||
if (!P_SetTarget(&players[i].follower, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].follower))
|
||||
CONS_Debug(DBG_GAMELOGIC, "follower not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].currentwaypoint)
|
||||
|
|
@ -5726,72 +5735,52 @@ static void P_RelinkPointers(void)
|
|||
}
|
||||
if (players[i].hoverhyudoro)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].hoverhyudoro;
|
||||
players[i].hoverhyudoro = NULL;
|
||||
if (!P_SetTarget(&players[i].hoverhyudoro, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].hoverhyudoro))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hoverhyudoro not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].stumbleIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].stumbleIndicator;
|
||||
players[i].stumbleIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].stumbleIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].stumbleIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "stumbleIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].wavedashIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].wavedashIndicator;
|
||||
players[i].wavedashIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].wavedashIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].wavedashIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "wavedashIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].trickIndicator)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].trickIndicator;
|
||||
players[i].trickIndicator = NULL;
|
||||
if (!P_SetTarget(&players[i].trickIndicator, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].trickIndicator))
|
||||
CONS_Debug(DBG_GAMELOGIC, "trickIndicator not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].whip)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].whip;
|
||||
players[i].whip = NULL;
|
||||
if (!P_SetTarget(&players[i].whip, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].whip))
|
||||
CONS_Debug(DBG_GAMELOGIC, "whip not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].hand)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].hand;
|
||||
players[i].hand = NULL;
|
||||
if (!P_SetTarget(&players[i].hand, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].hand))
|
||||
CONS_Debug(DBG_GAMELOGIC, "hand not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].ringShooter)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].ringShooter;
|
||||
players[i].ringShooter = NULL;
|
||||
if (!P_SetTarget(&players[i].ringShooter, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].ringShooter))
|
||||
CONS_Debug(DBG_GAMELOGIC, "ringShooter not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].flickyAttacker)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].flickyAttacker;
|
||||
players[i].flickyAttacker = NULL;
|
||||
if (!P_SetTarget(&players[i].flickyAttacker, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].flickyAttacker))
|
||||
CONS_Debug(DBG_GAMELOGIC, "flickyAttacker not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].powerup.flickyController)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].powerup.flickyController;
|
||||
players[i].powerup.flickyController = NULL;
|
||||
if (!P_SetTarget(&players[i].powerup.flickyController, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].powerup.flickyController))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.flickyController not found on player %d\n", i);
|
||||
}
|
||||
if (players[i].powerup.barrier)
|
||||
{
|
||||
temp = (UINT32)(size_t)players[i].powerup.barrier;
|
||||
players[i].powerup.barrier = NULL;
|
||||
if (!P_SetTarget(&players[i].powerup.barrier, P_FindNewPosition(temp)))
|
||||
if (!RelinkMobj(&players[i].powerup.barrier))
|
||||
CONS_Debug(DBG_GAMELOGIC, "powerup.barrier not found on player %d\n", i);
|
||||
}
|
||||
}
|
||||
|
|
@ -6683,6 +6672,8 @@ void P_SaveGame(savebuffer_t *save)
|
|||
|
||||
void P_SaveNetGame(savebuffer_t *save, boolean resending)
|
||||
{
|
||||
current_savebuffer = save;
|
||||
|
||||
thinker_t *th;
|
||||
mobj_t *mobj;
|
||||
UINT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise
|
||||
|
|
@ -6759,6 +6750,8 @@ badloadgame:
|
|||
|
||||
boolean P_LoadNetGame(savebuffer_t *save, boolean reloading)
|
||||
{
|
||||
current_savebuffer = save;
|
||||
|
||||
CV_LoadNetVars(&save->p);
|
||||
|
||||
if (!P_NetUnArchiveMisc(save, reloading))
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "r_main.h"
|
||||
#include "r_fps.h"
|
||||
#include "d_clisrv.h" // UpdateChallenges
|
||||
#include "p_link.h"
|
||||
|
||||
// Object place
|
||||
#include "m_cheat.h"
|
||||
|
|
@ -299,8 +300,7 @@ void P_InitThinkers(void)
|
|||
skyboxcenterpnts[i] = skyboxviewpnts[i] = NULL;
|
||||
}
|
||||
|
||||
Obj_ResetUFOSpawners();
|
||||
Obj_ResetCheckpoints();
|
||||
P_InitMobjPointers();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue