- actor lists refactored.

No more shorts, no more static arrays.
This was one of the biggest blockers for unlimiting the engine.
This commit is contained in:
Christoph Oelckers 2021-12-04 22:04:16 +01:00
parent 87ac9bee44
commit f855b1020f
37 changed files with 641 additions and 730 deletions

View file

@ -1013,6 +1013,7 @@ set (PCH_SOURCES
build/src/mdsprite.cpp build/src/mdsprite.cpp
build/src/polymost.cpp build/src/polymost.cpp
core/actorlist.cpp
core/automap.cpp core/automap.cpp
core/cheats.cpp core/cheats.cpp
core/cheathandler.cpp core/cheathandler.cpp

View file

@ -238,10 +238,6 @@ extern int16_t pskybits_override;
// (or -1 if freelist is empty): // (or -1 if freelist is empty):
EXTERN int16_t tailspritefree; EXTERN int16_t tailspritefree;
EXTERN int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
EXTERN int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
EXTERN int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
EXTERN uint8_t gotpic[(MAXTILES+7)>>3]; EXTERN uint8_t gotpic[(MAXTILES+7)>>3];
extern FixedBitArray<MAXSECTORS> gotsector; extern FixedBitArray<MAXSECTORS> gotsector;
@ -321,7 +317,6 @@ typedef struct artheader_t {
int32_t engineInit(void); int32_t engineInit(void);
void engineUnInit(void); void engineUnInit(void);
void initspritelists(void);
struct SpawnSpriteDef struct SpawnSpriteDef
{ {
@ -484,19 +479,7 @@ int32_t lintersect(int32_t originX, int32_t originY, int32_t originZ,
int32_t lineStartX, int32_t lineStartY, int32_t lineEndX, int32_t lineEndY, int32_t lineStartX, int32_t lineStartY, int32_t lineEndX, int32_t lineEndY,
int32_t *intersectionX, int32_t *intersectionY, int32_t *intersectionZ); int32_t *intersectionX, int32_t *intersectionY, int32_t *intersectionZ);
int32_t insertsprite(int16_t sectnum, int16_t statnum, bool frominit = false);
int32_t deletesprite(int16_t spritenum);
int32_t changespritesect(int16_t spritenum, int16_t newsectnum);
int32_t changespritestat(int16_t spritenum, int16_t newstatnum);
int32_t setspritez(int16_t spritenum, const vec3_t *) ATTRIBUTE((nonnull(2)));
int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs); int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs);
inline int32_t spriteheightofs(int16_t i, int32_t *height, int32_t alsotileyofs)
{
return spriteheightofsptr((uspriteptr_t)&sprite[i], height, alsotileyofs);
}
int videoCaptureScreen(); int videoCaptureScreen();
@ -593,19 +576,11 @@ static inline int64_t compat_maybe_truncate_to_int32(int64_t val)
return enginecompatibility_mode != ENGINECOMPATIBILITY_NONE ? (int32_t)val : val; return enginecompatibility_mode != ENGINECOMPATIBILITY_NONE ? (int32_t)val : val;
} }
static inline int32_t setspritez_old(int16_t spritenum, int32_t x, int32_t y, int32_t z)
{
const vec3_t vector = { x, y, z };
return setspritez(spritenum, &vector);
}
extern int32_t rintersect(int32_t x1, int32_t y1, int32_t z1, extern int32_t rintersect(int32_t x1, int32_t y1, int32_t z1,
int32_t vx_, int32_t vy_, int32_t vz, int32_t vx_, int32_t vy_, int32_t vz,
int32_t x3, int32_t y3, int32_t x4, int32_t y4, int32_t x3, int32_t y3, int32_t x4, int32_t y4,
int32_t *intx, int32_t *inty, int32_t *intz); int32_t *intx, int32_t *inty, int32_t *intz);
extern void(*initspritelists_replace)(void);
extern int32_t(*changespritesect_replace)(int16_t spritenum, int16_t newsectnum);
void updateModelInterpolation(); void updateModelInterpolation();
@ -704,7 +679,4 @@ inline walltype* sectortype::lastWall() const
} }
#include "iterators.h"
#endif // build_h_ #endif // build_h_

View file

@ -59,8 +59,12 @@ END_BLD_NS
//40 bytes //40 bytes
class DCoreActor; class DCoreActor;
struct walltype; struct walltype;
struct sectortype struct sectortype
{ {
DCoreActor* firstEntry, * lastEntry;
int16_t wallptr, wallnum; int16_t wallptr, wallnum;
int32_t ceilingz, floorz; int32_t ceilingz, floorz;
uint16_t ceilingstat, floorstat; uint16_t ceilingstat, floorstat;

View file

@ -223,195 +223,6 @@ static int32_t engineLoadTables(void)
return 0; return 0;
} }
////////// SPRITE LIST MANIPULATION FUNCTIONS //////////
///// sector lists of sprites /////
// insert sprite at the head of sector list, change sectnum
static void do_insertsprite_at_headofsect(int16_t spritenum, int16_t sectnum)
{
int16_t const ohead = headspritesect[sectnum];
prevspritesect[spritenum] = -1;
nextspritesect[spritenum] = ohead;
if (ohead >= 0)
prevspritesect[ohead] = spritenum;
headspritesect[sectnum] = spritenum;
sprite[spritenum].sectnum = sectnum;
}
// remove sprite 'deleteme' from its sector list
static void do_deletespritesect(int16_t deleteme)
{
int32_t const sectnum = sprite[deleteme].sectnum;
int32_t const prev = prevspritesect[deleteme];
int32_t const next = nextspritesect[deleteme];
if (headspritesect[sectnum] == deleteme)
headspritesect[sectnum] = next;
if (prev >= 0)
nextspritesect[prev] = next;
if (next >= 0)
prevspritesect[next] = prev;
}
///// now, status lists /////
// insert sprite at head of status list, change .statnum
static void do_insertsprite_at_headofstat(int16_t spritenum, int16_t statnum)
{
int16_t const ohead = headspritestat[statnum];
prevspritestat[spritenum] = -1;
nextspritestat[spritenum] = ohead;
if (ohead >= 0)
prevspritestat[ohead] = spritenum;
headspritestat[statnum] = spritenum;
sprite[spritenum].statnum = statnum;
}
// insertspritestat (internal)
static int32_t insertspritestat(int16_t statnum)
{
if ((statnum >= MAXSTATUS) || (headspritestat[MAXSTATUS] == -1))
return -1; //list full
// remove one sprite from the statnum-freelist
int16_t const blanktouse = headspritestat[MAXSTATUS];
headspritestat[MAXSTATUS] = nextspritestat[blanktouse];
// make back-link of the new freelist head point to nil
if (headspritestat[MAXSTATUS] >= 0)
prevspritestat[headspritestat[MAXSTATUS]] = -1;
else if (enginecompatibility_mode == ENGINECOMPATIBILITY_NONE)
tailspritefree = -1;
do_insertsprite_at_headofstat(blanktouse, statnum);
return blanktouse;
}
// remove sprite 'deleteme' from its status list
static void do_deletespritestat(int16_t deleteme)
{
int32_t const sectnum = sprite[deleteme].statnum;
int32_t const prev = prevspritestat[deleteme];
int32_t const next = nextspritestat[deleteme];
if (headspritestat[sectnum] == deleteme)
headspritestat[sectnum] = next;
if (prev >= 0)
nextspritestat[prev] = next;
if (next >= 0)
prevspritestat[next] = prev;
}
//
// insertsprite
//
int32_t insertsprite(int16_t sectnum, int16_t statnum, bool frominit)
{
// TODO: guard against bad sectnum?
int32_t const newspritenum = insertspritestat(statnum);
// Build's default init of sprites is insantity².
if (newspritenum >= 0)
{
// Make sure it's clear.
if (!frominit) sprite[newspritenum].clear();
assert(validSectorIndex(sectnum));
do_insertsprite_at_headofsect(newspritenum, sectnum);
Numsprites++;
}
sprite[newspritenum].time = leveltimer++;
return newspritenum;
}
//
// deletesprite
//
int32_t deletesprite(int16_t spritenum)
{
assert((sprite[spritenum].statnum == MAXSTATUS)
== (sprite[spritenum].sectnum == MAXSECTORS));
if (sprite[spritenum].statnum == MAXSTATUS)
return -1; // already not in the world
do_deletespritestat(spritenum);
do_deletespritesect(spritenum);
// (dummy) insert at tail of sector freelist, compat
// for code that checks sectnum==MAXSECTOR
sprite[spritenum].sectnum = MAXSECTORS;
// insert at tail of status freelist
if (enginecompatibility_mode != ENGINECOMPATIBILITY_NONE)
do_insertsprite_at_headofstat(spritenum, MAXSTATUS);
else
{
prevspritestat[spritenum] = tailspritefree;
nextspritestat[spritenum] = -1;
if (tailspritefree >= 0)
nextspritestat[tailspritefree] = spritenum;
else
headspritestat[MAXSTATUS] = spritenum;
sprite[spritenum].statnum = MAXSTATUS;
tailspritefree = spritenum;
}
Numsprites--;
return 0;
}
//
// changespritesect
//
int32_t (*changespritesect_replace)(int16_t spritenum, int16_t newsectnum) = NULL;
int32_t changespritesect(int16_t spritenum, int16_t newsectnum)
{
if (changespritesect_replace)
return changespritesect_replace(spritenum, newsectnum);
// XXX: NOTE: MAXSECTORS is allowed
if ((newsectnum < 0 || newsectnum > MAXSECTORS) || (sprite[spritenum].sectnum == MAXSECTORS))
return -1;
if (sprite[spritenum].sectnum == newsectnum)
return 0;
do_deletespritesect(spritenum);
do_insertsprite_at_headofsect(spritenum, newsectnum);
return 0;
}
//
// changespritestat
//
int32_t changespritestat(int16_t spritenum, int16_t newstatnum)
{
// XXX: NOTE: MAXSTATUS is allowed
if ((newstatnum < 0 || newstatnum > MAXSTATUS) || (sprite[spritenum].statnum == MAXSTATUS))
return -1; // can't set the statnum of a sprite not in the world
if (sprite[spritenum].statnum == newstatnum)
return 0; // sprite already has desired statnum
do_deletespritestat(spritenum);
do_insertsprite_at_headofstat(spritenum, newstatnum);
return 0;
}
// //
// lintersect (internal) // lintersect (internal)
// //
@ -629,60 +440,6 @@ int32_t engineInit(void)
return 0; return 0;
} }
//
// initspritelists
//
void (*initspritelists_replace)(void) = NULL;
void initspritelists(void)
{
leveltimer = 0;
if (initspritelists_replace)
{
initspritelists_replace();
return;
}
int32_t i;
// initial list state for statnum lists:
//
// statnum 0: nil
// statnum 1: nil
// . . .
// statnum MAXSTATUS-1: nil
// "statnum MAXSTATUS": nil <- 0 <-> 1 <-> 2 <-> ... <-> MAXSPRITES-1 -> nil
//
// That is, the dummy MAXSTATUS statnum has all sprites.
for (i=0; i<MAXSECTORS; i++) //Init doubly-linked sprite sector lists
headspritesect[i] = -1;
headspritesect[MAXSECTORS] = 0;
for (i=0; i<MAXSPRITES; i++)
{
prevspritesect[i] = i-1;
nextspritesect[i] = i+1;
sprite[i].sectnum = MAXSECTORS;
}
prevspritesect[0] = -1;
nextspritesect[MAXSPRITES-1] = -1;
for (i=0; i<MAXSTATUS; i++) //Init doubly-linked sprite status lists
headspritestat[i] = -1;
headspritestat[MAXSTATUS] = 0;
for (i=0; i<MAXSPRITES; i++)
{
prevspritestat[i] = i-1;
nextspritestat[i] = i+1;
sprite[i].statnum = MAXSTATUS;
}
prevspritestat[0] = -1;
nextspritestat[MAXSPRITES-1] = -1;
tailspritefree = MAXSPRITES-1;
Numsprites = 0;
}
// //
// inside // inside
@ -1396,28 +1153,6 @@ int tilehasmodelorvoxel(int const tilenume, int pal)
} }
void SetActor(DCoreActor* actor, const vec3_t* newpos)
{
auto tempsector = actor->sector();
actor->s().setpos(*newpos);
updatesector(newpos->x, newpos->y, &tempsector);
if (tempsector && tempsector != actor->sector())
ChangeActorSect(actor, tempsector);
}
void SetActorZ(DCoreActor* actor, const vec3_t* newpos)
{
auto tempsector = actor->sector();
actor->s().setpos(*newpos);
updatesectorz(newpos->x, newpos->y, newpos->z, &tempsector);
if (tempsector && tempsector != actor->sector())
ChangeActorSect(actor, tempsector);
}
CCMD(updatesectordebug) CCMD(updatesectordebug)
{ {
int sect = 319; int sect = 319;

446
source/core/actorlist.cpp Normal file
View file

@ -0,0 +1,446 @@
/*
** actorlist.cpp
** Implements the linked stat/sector actor lists
**
**---------------------------------------------------------------------------
** Copyright 2021 Christoph Oelckers
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <deque>
#include "build.h"
#include "coreactor.h"
#include "gamefuncs.h"
// Doubly linked ring list of Actors
std::deque<DCoreActor*> freeList; // only needed until we can get rid of the sprite array.
ActorStatList statList[MAXSTATUS];
//==========================================================================
//
//
//
//==========================================================================
CVAR(Bool, safe_spritelist, false, CVAR_ARCHIVE)
static bool isSafe()
{
return isBlood() || safe_spritelist;
}
//==========================================================================
//
//
//
//==========================================================================
TArray<DCoreActor*> checked;
static bool ValidateStatList(int statnum)
{
checked.Clear();
for (auto entry = statList[statnum].firstEntry; entry; entry = entry->nextStat)
{
assert(!checked.Contains(entry));
checked.Push(entry);
assert(entry->prevStat != nullptr || statList[statnum].firstEntry == entry);
assert(entry->nextStat != nullptr || statList[statnum].lastEntry == entry);
assert(entry->prevStat == nullptr || entry->prevStat->nextStat == entry);
assert(entry->nextStat == nullptr || entry->nextStat->prevStat == entry);
}
return true;
}
//==========================================================================
//
//
//
//==========================================================================
static void AddStatTail(DCoreActor* actor, int statnum)
{
assert(actor->prevStat == nullptr && actor->nextStat == nullptr);
auto tail = statList[statnum].lastEntry;
assert(tail == nullptr || tail->nextStat == nullptr);
assert(ValidateStatList(statnum));
actor->prevStat = tail;
if (tail) tail->nextStat = actor;
else statList[statnum].firstEntry = actor;
statList[statnum].lastEntry = actor;
assert(ValidateStatList(statnum));
actor->s().statnum = statnum;
actor->link_stat = statnum;
//GC::WriteBarrier(tail);
//GC::WriteBarrier(actor);
}
//==========================================================================
//
//
//
//==========================================================================
static void AddStatHead(DCoreActor* actor, int statnum)
{
assert(actor->prevStat == nullptr && actor->nextStat == nullptr);
auto head = statList[statnum].firstEntry;
assert(head == nullptr || head->prevStat == nullptr);
assert(ValidateStatList(statnum));
actor->nextStat = head;
if (head) head->prevStat = actor;
else statList[statnum].lastEntry = actor;
assert(ValidateStatList(statnum));
statList[statnum].firstEntry = actor;
actor->s().statnum = statnum;
actor->link_stat = statnum;
//GC::WriteBarrier(head);
//GC::WriteBarrier(actor);
}
//==========================================================================
//
//
//
//==========================================================================
static void RemoveActorStat(DCoreActor* actor)
{
DCoreActor* prev = actor->prevStat;
DCoreActor* next = actor->nextStat;
auto& firstEntry = statList[actor->link_stat].firstEntry;
auto& lastEntry = statList[actor->link_stat].lastEntry;
auto prevp = prev ? &prev->nextStat : &firstEntry;
auto nextp = next ? &next->prevStat : &lastEntry;
assert(*prevp == actor);
assert(*nextp == actor);
assert(ValidateStatList(actor->link_stat));
*prevp = next;
*nextp = prev;
assert(ValidateStatList(actor->link_stat));
actor->nextStat = actor->prevStat = nullptr;
actor->s().statnum = MAXSTATUS;
actor->link_stat = MAXSTATUS;
/*
GC::WriteBarrier(prev, next);
GC::WriteBarrier(next, prev);
*/
}
//==========================================================================
//
//
//
//==========================================================================
static void InsertActorStat(DCoreActor* actor, int stat, bool tail)
{
assert(actor->prevStat == nullptr && actor->nextStat == nullptr);
assert(stat >= 0 && stat <= MAXSTATUS);
if (isSafe() || tail) AddStatTail(actor, stat);
else AddStatHead(actor, stat);
}
//==========================================================================
//
//
//
//==========================================================================
int ChangeActorStat(DCoreActor* actor, int statnum, bool tail)
{
int oldstat = actor->link_stat;
assert(statnum >= 0 && statnum < MAXSTATUS);
assert(actor->s().statnum >= 0 && actor->s().statnum < MAXSTATUS);
RemoveActorStat(actor);
InsertActorStat(actor, statnum, tail);
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
static bool ValidateSectList(sectortype* sect, DCoreActor *checkme = nullptr)
{
assert(sect);
checked.Clear();
assert(sect->firstEntry == nullptr || sect->firstEntry->prevSect == nullptr);
assert(sect->lastEntry == nullptr || sect->lastEntry->nextSect == nullptr);
for (auto entry = sect->firstEntry; entry; entry = entry->nextSect)
{
assert(entry != checkme);
assert(!checked.Contains(entry));
checked.Push(entry);
assert(entry->prevSect != nullptr || sect->firstEntry == entry);
assert(entry->nextSect != nullptr || sect->lastEntry == entry);
assert(entry->prevSect == nullptr || entry->prevSect->nextSect == entry);
assert(entry->nextSect == nullptr || entry->nextSect->prevSect == entry);
}
return true;
}
//==========================================================================
//
//
//
//==========================================================================
static void AddSectTail(DCoreActor *actor, sectortype* sect)
{
assert(actor->prevSect == nullptr && actor->nextSect == nullptr);
auto tail = sect->lastEntry;
assert(tail == nullptr || tail->nextSect == nullptr);
assert(ValidateSectList(sect));
actor->prevSect = tail;
if (tail) tail->nextSect = actor;
else sect->firstEntry = actor;
sect->lastEntry = actor;
assert(ValidateSectList(sect));
actor->s().setsector(sect);
actor->link_sector = sect;
//GC::WriteBarrier(tail);
//GC::WriteBarrier(actor);
}
//==========================================================================
//
//
//
//==========================================================================
static void AddSectHead(DCoreActor *actor, sectortype* sect)
{
assert(actor->prevSect == nullptr && actor->nextSect == nullptr);
auto head = sect->firstEntry;
assert(head == nullptr || head->prevSect == nullptr);
assert(ValidateSectList(sect));
actor->nextSect = head;
if (head) head->prevSect = actor;
else sect->lastEntry = actor;
sect->firstEntry = actor;
assert(ValidateSectList(sect));
actor->s().sectnum = sectnum(sect);
actor->link_sector = sect;
//GC::WriteBarrier(head);
//GC::WriteBarrier(actor);
}
//==========================================================================
//
//
//
//==========================================================================
static void RemoveActorSect(DCoreActor* actor)
{
if (actor->link_sector == nullptr)
{
assert(actor->prevSect == nullptr && actor->nextSect == nullptr);
return;
}
DCoreActor *prev = actor->prevSect;
DCoreActor *next = actor->nextSect;
auto& firstEntry = actor->link_sector->firstEntry;
auto& lastEntry = actor->link_sector->lastEntry;
auto prevp = prev ? &prev->nextSect : &firstEntry;
auto nextp = next ? &next->prevSect : &lastEntry;
assert(*prevp == actor);
assert(*nextp == actor);
assert(ValidateSectList(actor->link_sector));
*prevp = next;
*nextp = prev;
assert(ValidateSectList(actor->link_sector, actor));
actor->nextSect = actor->prevSect = nullptr;
actor->s().setsector(nullptr);
actor->link_sector = nullptr;
/*
GC::WriteBarrier(prev, next);
GC::WriteBarrier(next, prev);
*/
}
//==========================================================================
//
//
//
//==========================================================================
static void InsertActorSect(DCoreActor* actor, sectortype* sector, bool tail)
{
assert(actor->prevSect == nullptr && actor->nextSect == nullptr);
if (!sector)
{
actor->link_sector = nullptr;
actor->s().setsector(nullptr);
return;
}
if (isSafe() || tail) AddSectTail(actor, sector);
else AddSectHead(actor, sector);
}
//==========================================================================
//
//
//
//==========================================================================
void ChangeActorSect(DCoreActor* actor, sectortype* sect, bool tail)
{
if (sect == nullptr) return;
auto old_sect = actor->link_sector;
assert(actor->s().insector());
RemoveActorSect(actor);
InsertActorSect(actor, sect, tail);
}
//==========================================================================
//
//
//
//==========================================================================
DCoreActor* InsertActor(sectortype* sector, int stat, bool tail)
{
if (freeList.empty())
{
I_Error("Out of sprites!"); // we cannot deal with this - and most of the calling code never checks...
return nullptr;
}
auto actor = freeList.back();
freeList.pop_back();
spritetype* pSprite = &actor->s();
pSprite->clear();
InsertActorStat(actor, stat, tail);
InsertActorSect(actor, sector, tail);
Numsprites++;
actor->s().time = leveltimer++;
return actor;
}
//==========================================================================
//
//
//
//==========================================================================
int DeleteActor(DCoreActor* actor)
{
auto sp = &actor->s();
assert(sp->statnum >= 0 && sp->statnum < MAXSTATUS);
int stat = actor->link_stat;
RemoveActorStat(actor);
auto sect = actor->link_sector;
if (sect)
{
RemoveActorSect(actor);
}
else
{
assert(actor->prevSect == nullptr && actor->nextSect == nullptr);
}
Numsprites--;
freeList.push_front(actor);
return 0;
}
//==========================================================================
//
//
//
//==========================================================================
void InitSpriteLists()
{
for (auto& stat : statList)
{
stat.firstEntry = stat.lastEntry = nullptr;
}
for (auto& sect : sectors())
{
sect.firstEntry = sect.lastEntry = nullptr;
}
freeList.clear();
for(auto& actor : actorArray)
{
actor->prevSect = actor->prevStat = actor->nextSect = actor->nextStat = nullptr;
freeList.push_front(actor);
}
Numsprites = 0;
}
//==========================================================================
//
//
//
//==========================================================================
void SetActor(DCoreActor* actor, const vec3_t* newpos)
{
auto tempsector = actor->sector();
actor->s().setpos(*newpos);
updatesector(newpos->x, newpos->y, &tempsector);
if (tempsector && tempsector != actor->sector())
ChangeActorSect(actor, tempsector);
}
void SetActorZ(DCoreActor* actor, const vec3_t* newpos)
{
auto tempsector = actor->sector();
actor->s().setpos(*newpos);
updatesectorz(newpos->x, newpos->y, newpos->z, &tempsector);
if (tempsector && tempsector != actor->sector())
ChangeActorSect(actor, tempsector);
}

View file

@ -2,7 +2,6 @@
#include <stdint.h> #include <stdint.h>
#include "build.h" #include "build.h"
#include "iterators.h"
class DCoreActor class DCoreActor
{ {
@ -12,6 +11,12 @@ protected:
public: public:
// These two are needed because we cannot rely on the ones in the sprites for unlinking.
int link_stat;
sectortype* link_sector;
DCoreActor* prevStat, * nextStat;
DCoreActor* prevSect, * nextSect;
bool exists() const bool exists() const
{ {
return (unsigned)s().statnum < MAXSTATUS; return (unsigned)s().statnum < MAXSTATUS;
@ -209,51 +214,80 @@ struct TCollision : public CollisionBase
}; };
struct ActorStatList
{
DCoreActor* firstEntry, * lastEntry;
};
extern ActorStatList statList[MAXSTATUS];
// Iterator wrappers that return an actor pointer, not an index. // Iterator wrappers that return an actor pointer, not an index.
template<class TActor> template<class TActor>
class TStatIterator : public StatIterator class TStatIterator
{ {
DCoreActor* next;
public: public:
TStatIterator(int stat) : StatIterator(stat) TStatIterator(int stat)
{ {
next = statList[stat].firstEntry;
}
void Reset(int stat)
{
next = statList[stat].firstEntry;
} }
TActor* Next() TActor* Next()
{ {
int n = NextIndex(); auto n = next;
return n >= 0 ? static_cast<TActor*>(actorArray[n]) : nullptr; if (next) next = next->nextStat;
return static_cast<TActor*>(n);
} }
TActor* Peek() TActor* Peek()
{ {
int n = PeekIndex(); return static_cast<TActor*>(next);
return n >= 0 ? static_cast<TActor*>(actorArray[n]) : nullptr;
} }
}; };
template<class TActor> template<class TActor>
class TSectIterator : public SectIterator class TSectIterator
{ {
DCoreActor* next;
public: public:
TSectIterator(int stat) : SectIterator(stat) //[[deprecated]]
TSectIterator(int stat)
{ {
next = sector[stat].firstEntry;
} }
TSectIterator(sectortype* stat) : SectIterator(stat) TSectIterator(sectortype* stat)
{ {
next = stat->firstEntry;
} }
//[[deprecated]]
void Reset(int stat)
{
next = sector[stat].firstEntry;
}
void Reset(sectortype* stat)
{
next = stat->firstEntry;
}
TActor* Next() TActor* Next()
{ {
int n = NextIndex(); auto n = next;
return n >= 0 ? static_cast<TActor*>(actorArray[n]) : nullptr; if (next) next = next->nextSect;
return static_cast<TActor*>(n);
} }
TActor* Peek() TActor* Peek()
{ {
int n = PeekIndex(); return static_cast<TActor*>(next);
return n >= 0 ? static_cast<TActor*>(actorArray[n]) : nullptr;
} }
}; };
@ -288,16 +322,15 @@ public:
using CoreSectIterator = TSectIterator<DCoreActor>; using CoreSectIterator = TSectIterator<DCoreActor>;
// Only to be used by initial actor spawns!
void InsertActorSect(DCoreActor* actor, sectortype* sector, bool tail = false);
void InsertActorStat(DCoreActor* actor, int stat, bool tail = false);
inline void ChangeActorStat(DCoreActor* actor, int stat) DCoreActor* InsertActor(sectortype* sector, int stat, bool forcetail = false);
{ int DeleteActor(DCoreActor* actor);
changespritestat(actor->GetSpriteIndex(), stat); void ChangeActorSect(DCoreActor* actor, sectortype* sector, bool forcetail = false);
} int ChangeActorStat(DCoreActor* actor, int nStatus, bool forcetail = false);
void InitSpriteLists();
inline void ChangeActorSect(DCoreActor* actor, sectortype* sect)
{
changespritesect(actor->GetSpriteIndex(), sector.IndexOf(sect));
}
void SetActorZ(DCoreActor* actor, const vec3_t* newpos); void SetActorZ(DCoreActor* actor, const vec3_t* newpos);

View file

@ -78,6 +78,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "hw_voxels.h" #include "hw_voxels.h"
#include "hw_palmanager.h" #include "hw_palmanager.h"
#include "razefont.h" #include "razefont.h"
#include "coreactor.h"
CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Bool, autoloadlights, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CVAR(Bool, autoloadbrightmaps, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -1376,7 +1377,7 @@ void GameInterface::loadPalette()
void GameInterface::FreeLevelData() void GameInterface::FreeLevelData()
{ {
// Make sure that there is no more level to toy around with. // Make sure that there is no more level to toy around with.
initspritelists(); InitSpriteLists();
numsectors = numwalls = 0; numsectors = numwalls = 0;
currentLevel = nullptr; currentLevel = nullptr;
} }

View file

@ -1,84 +0,0 @@
#pragma once
class StatIterator
{
int next;
public:
StatIterator(int stat)
{
assert(stat >= 0 && stat < MAXSTATUS);
next = headspritestat[stat];
}
void Reset(int stat)
{
assert(stat >= 0 && stat < MAXSTATUS);
next = headspritestat[stat];
}
int NextIndex()
{
int n = next;
if (n >= 0) next = nextspritestat[next];
return n;
}
int PeekIndex()
{
return next;
}
// These are only used by one particularly screwy loop in Blood's nnexts.cpp.
static int First(int stat)
{
return headspritestat[stat];
}
static int NextFor(int spr)
{
return nextspritestat[spr];
}
};
class SectIterator
{
int next;
public:
SectIterator(int stat)
{
assert(validSectorIndex(stat));
next = headspritesect[stat];
}
SectIterator(sectortype* sect)
{
assert(sect);
next = headspritesect[sector.IndexOf(sect)];
}
void Reset(int stat)
{
assert(validSectorIndex(stat));
next = headspritesect[stat];
}
void Reset(sectortype* sect)
{
assert(sect);
next = headspritesect[sector.IndexOf(sect)];
}
int NextIndex()
{
int n = next;
if (n >= 0) next = nextspritesect[next];
return n;
}
int PeekIndex()
{
return next;
}
};

View file

@ -387,7 +387,7 @@ void insertAllSprites(SpawnSpriteDef& sprites)
removeit = true; removeit = true;
} }
insertsprite(spr.sectnum, spr.statnum, true); //insertsprite(spr.sectnum, spr.statnum, true);
if (removeit) if (removeit)
{ {
@ -407,7 +407,7 @@ void insertAllSprites(SpawnSpriteDef& sprites)
{ {
// Now remove it for real! // Now remove it for real!
spr.statnum = 0; spr.statnum = 0;
deletesprite(i); //deletesprite(i);
} }
} }
} }
@ -468,7 +468,6 @@ void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang,
// Now that we know the map's size, set up the globals. // Now that we know the map's size, set up the globals.
allocateMapArrays(numsprites); allocateMapArrays(numsprites);
initspritelists(); // may not be used in Blood!
sprites.sprites.Resize(numsprites); sprites.sprites.Resize(numsprites);
memset(sprites.sprites.Data(), 0, numsprites * sizeof(spritetype)); memset(sprites.sprites.Data(), 0, numsprites * sizeof(spritetype));
@ -549,7 +548,6 @@ void loadMapBackup(const char* filename)
else else
{ {
engineLoadBoard(filename, 0, &pos, &scratch, &scratch2, scratch3); engineLoadBoard(filename, 0, &pos, &scratch, &scratch2, scratch3);
initspritelists();
} }
} }

View file

@ -666,20 +666,11 @@ void SerializeMap(FSerializer& arc)
activeSprites.Set(i); activeSprites.Set(i);
} }
} }
// simplify the data a bit for better compression.
for (int i = 0; i < MAXSPRITES; i++)
{
if (nextspritestat[i] == i + 1) nextspritestat[i] = -2;
if (nextspritesect[i] == i + 1) nextspritesect[i] = -2;
if (prevspritestat[i] == i - 1) prevspritestat[i] = -2;
if (prevspritesect[i] == i - 1) prevspritesect[i] = -2;
}
} }
else else
{ {
memset(sprite, 0, sizeof(sprite[0]) * MAXSPRITES); memset(sprite, 0, sizeof(sprite[0]) * MAXSPRITES);
initspritelists(); InitSpriteLists();
zsp = sprite[0]; zsp = sprite[0];
} }
@ -692,12 +683,6 @@ void SerializeMap(FSerializer& arc)
("sectors", sector, sectorbackup) ("sectors", sector, sectorbackup)
("numwalls", numwalls) ("numwalls", numwalls)
("walls", wall, wallbackup) ("walls", wall, wallbackup)
.Array("headspritestat", headspritestat, MAXSTATUS + 1)
.Array("nextspritestat", nextspritestat, MAXSPRITES)
.Array("prevspritestat", prevspritestat, MAXSPRITES)
.Array("headspritesect", headspritesect, MAXSECTORS + 1)
.Array("nextspritesect", nextspritesect, MAXSPRITES)
.Array("prevspritesect", prevspritesect, MAXSPRITES)
("tailspritefree", tailspritefree) ("tailspritefree", tailspritefree)
("myconnectindex", myconnectindex) ("myconnectindex", myconnectindex)
@ -729,15 +714,6 @@ void SerializeMap(FSerializer& arc)
arc.EndObject(); arc.EndObject();
} }
// Undo the simplification.
for (int i = 0; i < MAXSPRITES; i++)
{
if (nextspritestat[i] == -2) nextspritestat[i] = i + 1;
if (nextspritesect[i] == -2) nextspritesect[i] = i + 1;
if (prevspritestat[i] == -2) prevspritestat[i] = i - 1;
if (prevspritesect[i] == -2) prevspritesect[i] = i - 1;
}
if (arc.isReading()) if (arc.isReading())
{ {
setWallSectors(); setWallSectors();

View file

@ -82,12 +82,18 @@ void EndLevel(void)
TArray<DBloodActor*> SpawnActors(BloodSpawnSpriteDef& sprites) TArray<DBloodActor*> SpawnActors(BloodSpawnSpriteDef& sprites)
{ {
TArray<DBloodActor*> spawns(sprites.sprites.Size(), true); TArray<DBloodActor*> spawns(sprites.sprites.Size(), true);
initspritelists(); InitSpriteLists();
int j = 0;
for (unsigned i = 0; i < sprites.sprites.Size(); i++) for (unsigned i = 0; i < sprites.sprites.Size(); i++)
{ {
RemoveSpriteStat(i); if (sprites.sprites[i].statnum == MAXSTATUS)
auto actor = &bloodActors[i]; {
spawns[i] = actor; spawns.Pop();
continue;
}
auto sprt = &sprites.sprites[i];
auto actor = InsertSprite(sprt->sector(), sprt->statnum);
spawns[j++] = actor;
actor->Clear(); actor->Clear();
actor->s() = sprites.sprites[i]; actor->s() = sprites.sprites[i];
if (sprites.sprext.Size()) actor->sx() = sprites.sprext[i]; if (sprites.sprext.Size()) actor->sx() = sprites.sprext[i];
@ -99,11 +105,7 @@ TArray<DBloodActor*> SpawnActors(BloodSpawnSpriteDef& sprites)
actor->addX(); actor->addX();
actor->x() = sprites.xspr[i]; actor->x() = sprites.xspr[i];
} }
InsertSpriteSect(i, actor->s().sectnum);
InsertSpriteStat(i, actor->s().statnum);
} }
Numsprites = spawns.Size();
return spawns; return spawns;
} }
@ -507,8 +509,6 @@ void GameInterface::app_init()
gGameOptions.nMonsterSettings = !userConfig.nomonsters; gGameOptions.nMonsterSettings = !userConfig.nomonsters;
ReadAllRFS(); ReadAllRFS();
HookReplaceFunctions();
levelLoadDefaults(); levelLoadDefaults();
//--------- //---------

View file

@ -177,14 +177,4 @@ inline void GetActorExtents(DBloodActor* actor, int* top, int* bottom)
GetSpriteExtents(&actor->s(), top, bottom); GetSpriteExtents(&actor->s(), top, bottom);
} }
inline void ChangeActorStat(DBloodActor* actor, int stat)
{
ChangeSpriteStat(actor->GetSpriteIndex(), stat);
}
inline void ChangeActorSect(DBloodActor* actor, sectortype* stat)
{
ChangeSpriteSect(actor->GetSpriteIndex(), sectnum(stat));
}
END_BLD_NS END_BLD_NS

View file

@ -41,6 +41,31 @@ BEGIN_BLD_NS
DBloodActor bloodActors[kMaxSprites]; DBloodActor bloodActors[kMaxSprites];
DBloodActor* InsertSprite(sectortype* pSector, int nStat)
{
auto act = static_cast<DBloodActor*>(::InsertActor(pSector, nStat));
auto pSprite = &act->s();
pSprite->cstat = 128;
pSprite->clipdist = 32;
pSprite->xrepeat = pSprite->yrepeat = 64;
return act;
}
int DeleteSprite(DBloodActor* actor)
{
auto sp = &actor->s();
FVector3 pos = GetSoundPos(&actor->s().pos);
soundEngine->RelinkSound(SOURCE_Actor, actor, nullptr, &pos);
#ifdef NOONE_EXTENSIONS
for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == actor) ctrl.qavScene.initiator = nullptr;
#endif
::DeleteActor(actor);
return 0;
}
bool gModernMap = false; bool gModernMap = false;
unsigned int gStatCount[kMaxStatus + 1]; unsigned int gStatCount[kMaxStatus + 1];
@ -55,191 +80,6 @@ void dbCrypt(char *pPtr, int nLength, int nKey)
} }
} }
void InsertSpriteSect(int nSprite, int nSector)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
assert(validSectorIndex(nSector));
int nOther = headspritesect[nSector];
if (nOther >= 0)
{
prevspritesect[nSprite] = prevspritesect[nOther];
nextspritesect[nSprite] = -1;
nextspritesect[prevspritesect[nOther]] = nSprite;
prevspritesect[nOther] = nSprite;
}
else
{
prevspritesect[nSprite] = nSprite;
nextspritesect[nSprite] = -1;
headspritesect[nSector] = nSprite;
}
sprite[nSprite].sectnum = nSector;
}
void RemoveSpriteSect(int nSprite)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
int nSector = sprite[nSprite].sectnum;
assert(validSectorIndex(nSector));
int nOther = nextspritesect[nSprite];
if (nOther < 0)
{
nOther = headspritesect[nSector];
}
prevspritesect[nOther] = prevspritesect[nSprite];
if (headspritesect[nSector] != nSprite)
{
nextspritesect[prevspritesect[nSprite]] = nextspritesect[nSprite];
}
else
{
headspritesect[nSector] = nextspritesect[nSprite];
}
sprite[nSprite].sectnum = MAXSECTORS;
}
void InsertSpriteStat(int nSprite, int nStat)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
assert(nStat >= 0 && nStat <= kMaxStatus);
int nOther = headspritestat[nStat];
if (nOther >= 0)
{
prevspritestat[nSprite] = prevspritestat[nOther];
nextspritestat[nSprite] = -1;
nextspritestat[prevspritestat[nOther]] = nSprite;
prevspritestat[nOther] = nSprite;
}
else
{
prevspritestat[nSprite] = nSprite;
nextspritestat[nSprite] = -1;
headspritestat[nStat] = nSprite;
}
sprite[nSprite].statnum = nStat;
gStatCount[nStat]++;
}
void RemoveSpriteStat(int nSprite)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
int nStat = sprite[nSprite].statnum;
assert(nStat >= 0 && nStat <= kMaxStatus);
int nOther = nextspritestat[nSprite];
if (nOther < 0)
{
nOther = headspritestat[nStat];
}
prevspritestat[nOther] = prevspritestat[nSprite];
if (headspritestat[nStat] != nSprite)
{
nextspritestat[prevspritestat[nSprite]] = nextspritestat[nSprite];
}
else
{
headspritestat[nStat] = nextspritestat[nSprite];
}
sprite[nSprite].statnum = MAXSTATUS;
gStatCount[nStat]--;
}
void qinitspritelists(void) // Replace
{
for (int i = 0; i <= MAXSECTORS; i++)
{
headspritesect[i] = -1;
}
for (int i = 0; i <= kMaxStatus; i++)
{
headspritestat[i] = -1;
}
for (int i = 0; i < kMaxSprites; i++)
{
sprite[i].sectnum = -1;
InsertSpriteStat(i, kMaxStatus);
}
memset(gStatCount, 0, sizeof(gStatCount));
Numsprites = 0;
}
DBloodActor* InsertSprite(sectortype* pSector, int nStat)
{
int nSprite = headspritestat[kMaxStatus];
assert(nSprite < kMaxSprites);
if (nSprite < 0)
{
I_Error("Out of sprites!"); // we cannot deal with this - and most of the calling code never checks...
return nullptr;
}
RemoveSpriteStat(nSprite);
DBloodActor* actor = &bloodActors[nSprite];
actor->Clear();
spritetype *pSprite = &actor->s();
memset(pSprite, 0, sizeof(spritetype));
InsertSpriteStat(nSprite, nStat);
InsertSpriteSect(nSprite, sectnum(pSector));
pSprite->cstat = 128;
pSprite->clipdist = 32;
pSprite->xrepeat = pSprite->yrepeat = 64;
actor->SetOwner(nullptr);
Numsprites++;
sprite[nSprite].time = leveltimer++;
return actor;
}
inline int DeleteSprite(DBloodActor* actor)
{
auto sp = &actor->s();
FVector3 pos = GetSoundPos(&actor->s().pos);
soundEngine->RelinkSound(SOURCE_Actor, actor, nullptr, &pos);
assert(sp->statnum >= 0 && sp->statnum < kMaxStatus);
RemoveSpriteStat(actor->GetSpriteIndex());
assert(sp->insector());
RemoveSpriteSect(actor->GetSpriteIndex());
InsertSpriteStat(actor->GetSpriteIndex(), kMaxStatus);
#ifdef NOONE_EXTENSIONS
for (auto& ctrl : gPlayerCtrl) if (ctrl.qavScene.initiator == actor) ctrl.qavScene.initiator = nullptr;
#endif
Numsprites--;
return 0;
}
int ChangeSpriteSect(int nSprite, int nSector)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
assert(validSectorIndex(nSector));
assert(sprite[nSprite].insector());
RemoveSpriteSect(nSprite);
InsertSpriteSect(nSprite, nSector);
return 0;
}
int qchangespritesect(short nSprite, short nSector)
{
return ChangeSpriteSect(nSprite, nSector);
}
int ChangeSpriteStat(int nSprite, int nStatus)
{
assert(nSprite >= 0 && nSprite < kMaxSprites);
assert(nStatus >= 0 && nStatus < kMaxStatus);
assert(sprite[nSprite].statnum >= 0 && sprite[nSprite].statnum < kMaxStatus);
assert(sprite[nSprite].insector());
RemoveSpriteStat(nSprite);
InsertSpriteStat(nSprite, nStatus);
return 0;
}
void dbInit(void)
{
initspritelists();
}
bool drawtile2048, encrypted; bool drawtile2048, encrypted;
MAPHEADER2 byte_19AE44; MAPHEADER2 byte_19AE44;
@ -436,7 +276,6 @@ void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sect
#endif #endif
* pSector = &sector[mapHeader.sect]; * pSector = &sector[mapHeader.sect];
dbInit();
if (encrypted) if (encrypted)
{ {
fr.Read(&byte_19AE44, 128); fr.Read(&byte_19AE44, 128);
@ -904,6 +743,5 @@ void qloadboard(const char* filename, char flags, vec3_t* dapos, int16_t* daang)
Blood::BloodSpawnSpriteDef sprites; Blood::BloodSpawnSpriteDef sprites;
sectortype* sp; sectortype* sp;
Blood::dbLoadMap(filename, &dapos->x, &dapos->y, &dapos->z, daang, &sp, nullptr, sprites); Blood::dbLoadMap(filename, &dapos->x, &dapos->y, &dapos->z, daang, &sp, nullptr, sprites);
Blood::dbInit(); // clean up immediately.
} }

View file

@ -115,18 +115,9 @@ void DeleteLight(int32_t s);
#endif #endif
void InsertSpriteSect(int nSprite, int nSector);
void RemoveSpriteSect(int nSprite);
void InsertSpriteStat(int nSprite, int nStat);
void RemoveSpriteStat(int nSprite);
void qinitspritelists(void);
DBloodActor* InsertSprite(sectortype* pSector, int nStat); DBloodActor* InsertSprite(sectortype* pSector, int nStat);
int DeleteSprite(DBloodActor* actor); int DeleteSprite(DBloodActor* actor);
int ChangeSpriteSect(int nSprite, int nSector);
int qchangespritesect(short nSprite, short nSector);
int ChangeSpriteStat(int nSprite, int nStatus);
void dbInit(void);
void PropagateMarkerReferences(void);
unsigned int dbReadMapCRC(const char *pPath); unsigned int dbReadMapCRC(const char *pPath);
void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sectortype** pSector, unsigned int* pCRC, BloodSpawnSpriteDef& sprites); void dbLoadMap(const char* pPath, int* pX, int* pY, int* pZ, short* pAngle, sectortype** pSector, unsigned int* pCRC, BloodSpawnSpriteDef& sprites);

View file

@ -43,7 +43,6 @@ void setPortalFlags(int mode);
void processSpritesOnOtherSideOfPortal(int x, int y, int interpolation); void processSpritesOnOtherSideOfPortal(int x, int y, int interpolation);
void DrawMirrors(int x, int y, int z, fixed_t a, fixed_t horiz, int smooth, int viewPlayer); void DrawMirrors(int x, int y, int z, fixed_t a, fixed_t horiz, int smooth, int viewPlayer);
int qanimateoffs(int a1, int a2); int qanimateoffs(int a1, int a2);
void HookReplaceFunctions();
struct PLAYER; struct PLAYER;

View file

@ -61,13 +61,4 @@ int qanimateoffs(int a1, int a2)
return offset; return offset;
} }
void qinitspritelists();
int32_t qchangespritesect(int16_t nSprite, int16_t nSector);
void HookReplaceFunctions(void)
{
initspritelists_replace = qinitspritelists;
changespritesect_replace = qchangespritesect;
}
END_BLD_NS END_BLD_NS

View file

@ -78,7 +78,7 @@ void deletesprite(DDukeActor *const actor)
S_StopSound(actor->s->lotag, actor); S_StopSound(actor->s->lotag, actor);
else else
S_RelinkActorSound(actor, nullptr); S_RelinkActorSound(actor, nullptr);
::deletesprite(actor->GetSpriteIndex()); ::DeleteActor(actor);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -56,11 +56,6 @@ inline int bossguy(DDukeActor* pSprite)
// old interface versions of already changed functions // old interface versions of already changed functions
inline void deletesprite(int num)
{
deletesprite(&hittype[num]);
}
int movesprite_ex_d(DDukeActor* actor, int xchange, int ychange, int zchange, unsigned int cliptype, Collision& result); int movesprite_ex_d(DDukeActor* actor, int xchange, int ychange, int zchange, unsigned int cliptype, Collision& result);
int movesprite_ex_r(DDukeActor* actor, int xchange, int ychange, int zchange, unsigned int cliptype, Collision& result); int movesprite_ex_r(DDukeActor* actor, int xchange, int ychange, int zchange, unsigned int cliptype, Collision& result);

View file

@ -935,15 +935,27 @@ static void SpawnPortals()
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static TArray<DDukeActor*> spawnactors(SpawnSpriteDef& spawns) static TArray<DDukeActor*> spawnactors(SpawnSpriteDef& sprites)
{ {
insertAllSprites(spawns); TArray<DDukeActor*> spawns(sprites.sprites.Size(), true);
TArray<DDukeActor*> actorlist; InitSpriteLists();
for(unsigned i = 0; i < spawns.sprites.Size(); i++) int j = 0;
for (unsigned i = 0; i < sprites.sprites.Size(); i++)
{ {
if (hittype[i].exists()) actorlist.Push(&hittype[i]); if (sprites.sprites[i].statnum == MAXSTATUS)
{
spawns.Pop();
continue;
}
auto sprt = &sprites.sprites[i];
auto actor = static_cast<DDukeActor*>(InsertActor(sprt->sector(), sprt->statnum));
spawns[j++] = actor;
*actor->s = sprites.sprites[i];
if (sprites.sprext.Size()) actor->sx() = sprites.sprext[i];
else actor->sx() = {};
actor->sm() = {};
} }
return actorlist; return spawns;
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View file

@ -53,12 +53,10 @@ DDukeActor* EGS(sectortype* whatsectp, int s_x, int s_y, int s_z, int s_pn, int8
{ {
// sector pointer must be strictly validated here or the engine will crash. // sector pointer must be strictly validated here or the engine will crash.
if (whatsectp == nullptr || !validSectorIndex(sectnum(whatsectp))) return nullptr; if (whatsectp == nullptr || !validSectorIndex(sectnum(whatsectp))) return nullptr;
int const i = insertsprite(sectnum(whatsectp), s_ss); auto act = static_cast<DDukeActor*>(::InsertActor(whatsectp, s_ss));
if (i < 0) if (act == nullptr) return nullptr;
I_Error(" Too many sprites spawned.");
auto act = &hittype[i];
auto s = act->s; auto s = act->s;
s->x = s_x; s->x = s_x;

View file

@ -220,11 +220,7 @@ Collision MoveCreature(DExhumedActor* nSprite);
Collision MoveCreatureWithCaution(DExhumedActor* actor); Collision MoveCreatureWithCaution(DExhumedActor* actor);
void WheresMyMouth(int nPlayer, vec3_t* pos, sectortype** sectnum); void WheresMyMouth(int nPlayer, vec3_t* pos, sectortype** sectnum);
int GetActorHeight(DExhumedActor* nSprite); int GetActorHeight(DExhumedActor* nSprite);
DExhumedActor* insertActor(int, int); DExhumedActor* insertActor(sectortype* s, int st);
inline DExhumedActor* insertActor(sectortype* s, int st)
{
return insertActor(sector.IndexOf(s), st);
}
DExhumedActor* GrabBody(); DExhumedActor* GrabBody();
DExhumedActor* GrabBodyGunSprite(); DExhumedActor* GrabBodyGunSprite();
void FuncCreatureChunk(int a, int, int nRun); void FuncCreatureChunk(int a, int, int nRun);

View file

@ -503,12 +503,11 @@ void DeleteActor(DExhumedActor* actor)
FVector3 pos = GetSoundPos(&actor->s().pos); FVector3 pos = GetSoundPos(&actor->s().pos);
soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos); soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos);
deletesprite(actor->GetSpriteIndex());
actor->s().ox = 0x80000000;
if (actor == bestTarget) { if (actor == bestTarget) {
bestTarget = nullptr; bestTarget = nullptr;
} }
::DeleteActor(actor);
} }

View file

@ -63,19 +63,31 @@ uint8_t bIsVersion6 = true;
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static TArray<DExhumedActor*> spawnactors(SpawnSpriteDef& spawns) static TArray<DExhumedActor*> spawnactors(SpawnSpriteDef& sprites)
{ {
insertAllSprites(spawns); TArray<DExhumedActor*> spawns(sprites.sprites.Size(), true);
TArray<DExhumedActor*> actorlist; InitSpriteLists();
for (unsigned i = 0; i < spawns.sprites.Size(); i++) int j = 0;
for (unsigned i = 0; i < sprites.sprites.Size(); i++)
{ {
if (exhumedActors[i].exists()) actorlist.Push(&exhumedActors[i]); if (sprites.sprites[i].statnum == MAXSTATUS)
{
spawns.Pop();
continue;
}
auto sprt = &sprites.sprites[i];
auto actor = insertActor(sprt->sector(), sprt->statnum);
spawns[j++] = actor;
actor->Clear();
actor->s() = sprites.sprites[i];
if (sprites.sprext.Size()) actor->sx() = sprites.sprext[i];
else actor->sx() = {};
actor->sm() = {};
} }
return actorlist; return spawns;
} }
uint8_t LoadLevel(MapRecord* map) uint8_t LoadLevel(MapRecord* map)
{ {
if (map->gameflags & LEVEL_EX_COUNTDOWN) if (map->gameflags & LEVEL_EX_COUNTDOWN)
@ -87,9 +99,6 @@ uint8_t LoadLevel(MapRecord* map)
nEnergyTowers = 0; nEnergyTowers = 0;
} }
initspritelists();
// init stuff // init stuff
{ {
StopAllSounds(); StopAllSounds();

View file

@ -469,10 +469,9 @@ int GetActorHeight(DExhumedActor* actor)
return tileHeight(actor->s().picnum) * actor->s().yrepeat * 4; return tileHeight(actor->s().picnum) * actor->s().yrepeat * 4;
} }
DExhumedActor* insertActor(int sect, int stat) DExhumedActor* insertActor(sectortype* s, int st)
{ {
int ndx = insertsprite(sect, stat); return static_cast<DExhumedActor*>(::InsertActor(s, st));
return ndx >= 0 ? &exhumedActors[ndx] : nullptr;
} }

View file

@ -588,7 +588,7 @@ int AutoBreakWall(WALLp wallp, int hit_x, int hit_y, int hit_z, int ang, int typ
{ {
vec3_t hit_pos = { hit_x, hit_y, hit_z }; vec3_t hit_pos = { hit_x, hit_y, hit_z };
// need correct location for spawning shrap // need correct location for spawning shrap
auto breakActor = InsertActor(0, STAT_DEFAULT); auto breakActor = insertActor(0, STAT_DEFAULT);
auto bsp = &breakActor->s(); auto bsp = &breakActor->s();
bsp->cstat = 0; bsp->cstat = 0;
bsp->extra = 0; bsp->extra = 0;

View file

@ -1155,7 +1155,7 @@ void BunnyHatch(DSWActor* actor)
for (int i = 0; i < MAX_BUNNYS; i++) for (int i = 0; i < MAX_BUNNYS; i++)
{ {
auto actorNew = InsertActor(sp->sector(), STAT_DEFAULT); auto actorNew = insertActor(sp->sector(), STAT_DEFAULT);
np = &actorNew->s(); np = &actorNew->s();
np->clear(); np->clear();
np->x = sp->x; np->x = sp->x;
@ -1218,7 +1218,7 @@ DSWActor* BunnyHatch2(DSWActor* actor)
SPRITEp wp = &actor->s(); SPRITEp wp = &actor->s();
auto actorNew = InsertActor(wp->sector(), STAT_DEFAULT); auto actorNew = insertActor(wp->sector(), STAT_DEFAULT);
auto np = &actorNew->s(); auto np = &actorNew->s();
np->clear(); np->clear();
np->x = wp->x; np->x = wp->x;

View file

@ -547,7 +547,7 @@ DSWActor* CopySprite(sprt const* tsp, sectortype* newsector)
{ {
SPRITEp sp; SPRITEp sp;
auto actorNew = InsertActor(newsector, STAT_FAF_COPY); auto actorNew = insertActor(newsector, STAT_FAF_COPY);
sp = &actorNew->s(); sp = &actorNew->s();
sp->x = tsp->x; sp->x = tsp->x;
@ -1277,7 +1277,7 @@ PostDraw(void)
while (auto actor = it.Next()) while (auto actor = it.Next())
{ {
actor->clearUser(); actor->clearUser();
deletesprite(actor->GetSpriteIndex()); ::DeleteActor(actor);
} }
} }

View file

@ -293,6 +293,26 @@ void InitLevelGlobals2(void)
// //
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void spawnactors(SpawnSpriteDef& sprites)
{
InitSpriteLists();
for (unsigned i = 0; i < sprites.sprites.Size(); i++)
{
if (sprites.sprites[i].statnum == MAXSTATUS)
{
continue;
}
auto sprt = &sprites.sprites[i];
auto actor = insertActor(sprt->sector(), sprt->statnum);
actor->Clear();
actor->s() = sprites.sprites[i];
if (sprites.sprext.Size()) actor->sx() = sprites.sprext[i];
else actor->sx() = {};
actor->sm() = {};
}
}
void InitLevel(MapRecord *maprec) void InitLevel(MapRecord *maprec)
{ {
Terminate3DSounds(); Terminate3DSounds();
@ -330,7 +350,7 @@ void InitLevel(MapRecord *maprec)
int cursect; int cursect;
SpawnSpriteDef sprites; SpawnSpriteDef sprites;
engineLoadBoard(maprec->fileName, SW_SHAREWARE ? 1 : 0, &Player[0].pos, &ang, &cursect, sprites); engineLoadBoard(maprec->fileName, SW_SHAREWARE ? 1 : 0, &Player[0].pos, &ang, &cursect, sprites);
insertAllSprites(sprites); spawnactors(sprites);
Player[0].cursector = &sector[cursect]; Player[0].cursector = &sector[cursect];
SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name);

View file

@ -2103,11 +2103,7 @@ void SetSpikeActive(DSWActor*); // spike.c
#define NTAG_SEARCH_HI 2 #define NTAG_SEARCH_HI 2
#define NTAG_SEARCH_LO_HI 3 #define NTAG_SEARCH_LO_HI 3
DSWActor* InsertActor(int sectnum, int statnum); DSWActor* insertActor(sectortype* sect, int statnum);
inline DSWActor* InsertActor(sectortype* sect, int statnum)
{
return InsertActor(sectnum(sect), statnum);
}
void AudioUpdate(void); // stupid void AudioUpdate(void); // stupid

View file

@ -54,7 +54,7 @@ BEGIN_SW_NS
void CopyQuakeSpotToOn(SPRITEp sp) void CopyQuakeSpotToOn(SPRITEp sp)
{ {
auto actorNew = InsertActor(sp->sector(), STAT_QUAKE_SPOT); auto actorNew = insertActor(sp->sector(), STAT_QUAKE_SPOT);
auto np = &actorNew->s(); auto np = &actorNew->s();
memcpy(np, sp, sizeof(SPRITE)); memcpy(np, sp, sizeof(SPRITE));
@ -237,7 +237,7 @@ void SpawnQuake(sectortype* sect, int x, int y, int z,
short tics, short amt, int radius) short tics, short amt, int radius)
{ {
auto actorNew = InsertActor(sect, STAT_QUAKE_ON); auto actorNew = insertActor(sect, STAT_QUAKE_ON);
auto sp = &actorNew->s(); auto sp = &actorNew->s();
sp->x = x; sp->x = x;

View file

@ -1216,7 +1216,7 @@ void RipperHatch(DSWActor* actor)
for (int i = 0; i < MAX_RIPPERS; i++) for (int i = 0; i < MAX_RIPPERS; i++)
{ {
auto actorNew = InsertActor(wp->sector(), STAT_DEFAULT); auto actorNew = insertActor(wp->sector(), STAT_DEFAULT);
np = &actorNew->s(); np = &actorNew->s();
np->clear(); np->clear();
ClearOwner(actorNew); ClearOwner(actorNew);

View file

@ -1234,7 +1234,7 @@ void Ripper2Hatch(DSWActor* actor)
for (int i = 0; i < MAX_RIPPER2S; i++) for (int i = 0; i < MAX_RIPPER2S; i++)
{ {
auto actorNew = InsertActor(wp->sector(), STAT_DEFAULT); auto actorNew = insertActor(wp->sector(), STAT_DEFAULT);
np = &actorNew->s(); np = &actorNew->s();
np->clear(); np->clear();
ClearOwner(actorNew); ClearOwner(actorNew);

View file

@ -54,15 +54,11 @@ SAVE save;
bool FAF_DebugView = false; bool FAF_DebugView = false;
DSWActor* InsertActor(int sectnum, int stat) DSWActor* insertActor(sectortype* sect, int statnum)
{ {
short spnum; auto pActor = static_cast<DSWActor*>(::InsertActor(sect, statnum));
spnum = insertsprite(sectnum, stat);
auto pActor = &swActors[spnum];
auto pSprite = &pActor->s(); auto pSprite = &pActor->s();
PRODUCTION_ASSERT(spnum >= 0);
pSprite->x = pSprite->y = pSprite->z = 0; pSprite->x = pSprite->y = pSprite->z = 0;
pSprite->cstat = 0; pSprite->cstat = 0;
pSprite->picnum = 0; pSprite->picnum = 0;

View file

@ -774,7 +774,7 @@ void KillActor(DSWActor* actor)
FVector3 pos = GetSoundPos(&actor->s().pos); FVector3 pos = GetSoundPos(&actor->s().pos);
soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos); soundEngine->RelinkSound(SOURCE_Actor, &actor->s(), nullptr, &pos);
deletesprite(actor->GetSpriteIndex()); ::DeleteActor(actor);
// shred your garbage // shred your garbage
sp->clear(); sp->clear();
@ -918,7 +918,7 @@ DSWActor* SpawnActor(int stat, int id, STATEp state, sectortype* sect, int x, in
ASSERT(!Prediction); ASSERT(!Prediction);
auto spawnedActor = InsertActor(sect, stat); auto spawnedActor = insertActor(sect, stat);
sp = &spawnedActor->s(); sp = &spawnedActor->s();
@ -983,7 +983,7 @@ bool ActorTestSpawn(DSWActor* actor)
auto sp = &actor->s(); auto sp = &actor->s();
if (sp->statnum == STAT_DEFAULT && sp->lotag == TAG_SPAWN_ACTOR) if (sp->statnum == STAT_DEFAULT && sp->lotag == TAG_SPAWN_ACTOR)
{ {
auto actorNew = InsertActor(sp->sector(), STAT_DEFAULT); auto actorNew = insertActor(sp->sector(), STAT_DEFAULT);
int t = actorNew->s().time; // must be preserved! int t = actorNew->s().time; // must be preserved!
actorNew->s() = *sp; actorNew->s() = *sp;
actorNew->s().time = t; actorNew->s().time = t;
@ -2570,7 +2570,7 @@ void SpriteSetup(void)
change_actor_stat(actor, STAT_CLIMB_MARKER); change_actor_stat(actor, STAT_CLIMB_MARKER);
// make a QUICK_LADDER sprite automatically // make a QUICK_LADDER sprite automatically
auto ns = InsertActor(sp->sector(), STAT_QUICK_LADDER); auto ns = insertActor(sp->sector(), STAT_QUICK_LADDER);
auto np = &ns->s(); auto np = &ns->s();
np->cstat = 0; np->cstat = 0;
@ -3618,7 +3618,7 @@ int ActorCoughItem(DSWActor* actor)
{ {
case SAILORGIRL_R0: case SAILORGIRL_R0:
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = np->extra = 0; np->cstat = np->extra = 0;
np->x = sp->x; np->x = sp->x;
@ -3659,7 +3659,7 @@ int ActorCoughItem(DSWActor* actor)
return 0; return 0;
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = np->extra = 0; np->cstat = np->extra = 0;
np->x = sp->x; np->x = sp->x;
@ -3687,7 +3687,7 @@ int ActorCoughItem(DSWActor* actor)
return 0; return 0;
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = np->extra = 0; np->cstat = np->extra = 0;
np->x = sp->x; np->x = sp->x;
@ -3718,7 +3718,7 @@ int ActorCoughItem(DSWActor* actor)
return 0; return 0;
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = 0; np->cstat = 0;
np->extra = 0; np->extra = 0;
@ -3781,7 +3781,7 @@ int ActorCoughItem(DSWActor* actor)
return 0; return 0;
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = np->extra = 0; np->cstat = np->extra = 0;
np->x = sp->x; np->x = sp->x;
@ -3839,7 +3839,7 @@ int ActorCoughItem(DSWActor* actor)
case PACHINKO4: case PACHINKO4:
ASSERT(sp->insector()); ASSERT(sp->insector());
actorNew = InsertActor(sp->sector(), STAT_SPAWN_ITEMS); actorNew = insertActor(sp->sector(), STAT_SPAWN_ITEMS);
np = &actorNew->s(); np = &actorNew->s();
np->cstat = np->extra = 0; np->cstat = np->extra = 0;
np->x = sp->x; np->x = sp->x;

View file

@ -313,7 +313,7 @@ DSWActor* TrackClonePoint(DSWActor* actor)
{ {
SPRITEp sp = &actor->s(), np; SPRITEp sp = &actor->s(), np;
auto actorNew = InsertActor(sp->sector(), sp->statnum); auto actorNew = insertActor(sp->sector(), sp->statnum);
np = &actorNew->s(); np = &actorNew->s();

View file

@ -151,7 +151,7 @@ void SpawnVis(DSWActor* parentActor, sectortype* sect, int x, int y, int z, int
} }
} }
auto actorNew = InsertActor(psp->sector(), STAT_VIS_ON); auto actorNew = insertActor(psp->sector(), STAT_VIS_ON);
sp = &actorNew->s(); sp = &actorNew->s();
SetOwner(parentActor, actorNew); SetOwner(parentActor, actorNew);
@ -170,7 +170,7 @@ void SpawnVis(DSWActor* parentActor, sectortype* sect, int x, int y, int z, int
if (sect->floorpal == PALETTE_FOG) if (sect->floorpal == PALETTE_FOG)
return; return;
auto actorNew = InsertActor(sect, STAT_VIS_ON); auto actorNew = insertActor(sect, STAT_VIS_ON);
sp = &actorNew->s(); sp = &actorNew->s();
sp->x = x; sp->x = x;

View file

@ -16069,7 +16069,7 @@ DSWActor* SpawnWallHole(sectortype* hit_sect, walltype* hit_wall, int hit_x, int
short w,nw,wall_ang; short w,nw,wall_ang;
SPRITEp sp; SPRITEp sp;
auto actor = InsertActor(hit_sect, STAT_DEFAULT); auto actor = insertActor(hit_sect, STAT_DEFAULT);
sp = &actor->s(); sp = &actor->s();
sp->xrepeat = sp->yrepeat = 16; sp->xrepeat = sp->yrepeat = 16;
sp->cstat = 0; sp->cstat = 0;
@ -18602,7 +18602,7 @@ void QueueHole(sectortype* hit_sect, walltype* hit_wall, int hit_x, int hit_y, i
return; return;
if (HoleQueue[HoleQueueHead] == nullptr) if (HoleQueue[HoleQueueHead] == nullptr)
HoleQueue[HoleQueueHead] = spawnedActor = InsertActor(hit_sect, STAT_HOLE_QUEUE); HoleQueue[HoleQueueHead] = spawnedActor = insertActor(hit_sect, STAT_HOLE_QUEUE);
else else
spawnedActor = HoleQueue[HoleQueueHead]; spawnedActor = HoleQueue[HoleQueueHead];