diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index b7f8ab856..9e55ae994 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -729,6 +729,7 @@ set( NOT_COMPILED_SOURCE_FILES games/blood/src/mirrors.cpp games/blood/src/misc.cpp games/blood/src/nnexts.cpp + games/blood/src/nnsprinsect.cpp games/blood/src/osdcmd.cpp games/blood/src/player.cpp games/blood/src/prediction.cpp diff --git a/source/games/blood/all.cpp b/source/games/blood/all.cpp index 6435ae4ce..27d4dc7a0 100644 --- a/source/games/blood/all.cpp +++ b/source/games/blood/all.cpp @@ -47,6 +47,7 @@ #include "src/messages.cpp" #include "src/mirrors.cpp" #include "src/misc.cpp" +#include "src/nnsprinsect.cpp" #include "src/nnexts.cpp" #include "src/osdcmd.cpp" #include "src/player.cpp" diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index bf8fefb20..b0be85e96 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -9090,8 +9090,9 @@ void SerializeNNExts(FSerializer& arc) .Array("impactspriteslist", gImpactSpritesList, gImpactSpritesCount) ("eventredirects", gEventRedirectsUsed) ("trconditioncount", gTrackingCondsCount) - .Array("trcondition", gCondition, gTrackingCondsCount) - .EndObject(); + .Array("trcondition", gCondition, gTrackingCondsCount); + gSprNSect.Serialize(arc); + arc.EndObject(); } } diff --git a/source/games/blood/src/nnexts.h b/source/games/blood/src/nnexts.h index 108e65a87..80bb74c97 100644 --- a/source/games/blood/src/nnexts.h +++ b/source/games/blood/src/nnexts.h @@ -411,6 +411,9 @@ inline bool aiInPatrolState(int nAiStateType) { // ------------------------------------------------------------------------- // bool readyForCrit(DBloodActor* pHunter, DBloodActor* pVictim); void clampSprite(DBloodActor* actor, int which = 3); +int getSpritesNearWalls(int nSrcSect, int* spriOut, int nMax, int nDist); +bool isMovableSector(int nType); +bool isMovableSector(sectortype* pSect); #endif inline bool valueIsBetween(int val, int min, int max) diff --git a/source/games/blood/src/nnsprinsect.cpp b/source/games/blood/src/nnsprinsect.cpp new file mode 100644 index 000000000..23cc37385 --- /dev/null +++ b/source/games/blood/src/nnsprinsect.cpp @@ -0,0 +1,222 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010-2019 EDuke32 developers and contributors +Copyright (C) 2019 Nuke.YKT +Copyright (C) NoOne + +This file is part of NBlood. + +NBlood is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 2 +as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +//------------------------------------------------------------------------- + +#include "serializer.h" +#include "maptypes.h" + +#ifdef NOONE_EXTENSIONS + +BEGIN_BLD_NS + +TArray getSpritesNearWalls(sectortype* pSrcSect, int nDist); + +// - CLASSES ------------------------------------------------------------------ + +// SPRITES_NEAR_SECTORS +// Intended for move sprites that is close to the outside walls with +// TranslateSector and/or zTranslateSector similar to Powerslave(Exhumed) way +// -------------------------------------------------------------------------- +class SPRINSECT +{ +public: + static const int kMaxSprNear = 256; + static const int kWallDist = 16; + + struct SPRITES + { + unsigned int nSector; + TArray> pActors; // this is a weak reference! + }; +private: + TArray db; +public: + void Free() { db.Clear(); } + void Init(int nDist = kWallDist); // used in trInit to collect the sprites before translation + void Serialize(FSerializer& pSave); + TArray>* GetSprPtr(int nSector); + +}; + + +// SPRITES_NEAR_SECTORS +// Intended for move sprites that is close to the outside walls with +// TranslateSector and/or zTranslateSector similar to Powerslave(Exhumed) way +// -------------------------------------------------------------------------- +SPRINSECT gSprNSect; + +void SPRINSECT::Init(int nDist) +{ + Free(); + + int j; + for(auto§ : sector) + { + if (!isMovableSector(sect.type)) + continue; + + switch (sect.type) { + case kSectorZMotionSprite: + case kSectorSlideMarked: + case kSectorRotateMarked: + continue; + // only allow non-marked sectors + default: + break; + } + + auto collected = getSpritesNearWalls(§, nDist); + + // exclude sprites that is not allowed + for (j = collected.Size() - 1; j >= 0; j--) + { + auto pActor = collected[j]; + if ((pActor->spr.cstat & CSTAT_SPRITE_MOVE_MASK) && pActor->insector()) + { + // if *next* sector is movable, exclude to avoid fighting + if (!isMovableSector(pActor->sector()->type)) + { + switch (pActor->spr.statnum) + { + default: + continue; + case kStatMarker: + case kStatPathMarker: + if (pActor->spr.flags & 0x1) continue; + [[fallthrough]]; + case kStatDude: + break; + } + } + } + + collected.Delete(j); + } + + if (collected.Size()) + { + db.Resize(db.Size() + 1); + + SPRITES& pEntry = db.Last(); + pEntry.pActors.Resize(collected.Size()); + for (unsigned ii = 0; ii < collected.Size(); ii++) + pEntry.pActors[ii] = collected[ii]; + pEntry.nSector = sectnum(§); + } + } +} + +TArray>* SPRINSECT::GetSprPtr(int nSector) +{ + for (auto &spre : db) + { + if (spre.nSector == (unsigned int)nSector && spre.pActors.Size() > 0) + return &spre.pActors; + } + return nullptr; +} + + +FSerializer& Serialize(FSerializer& arc, const char* key, SPRINSECT::SPRITES& obj, SPRINSECT::SPRITES* defval) +{ + if (arc.BeginObject(key)) + { + arc("sector", obj.nSector) + ("actors", obj.pActors) + .EndObject(); + } + return arc; +} + +void SPRINSECT::Serialize(FSerializer& arc) +{ + arc("db", db); +} + + + +bool isMovableSector(int nType) +{ + return (nType && nType != kSectorDamage && nType != kSectorTeleport && nType != kSectorCounter); +} + +bool isMovableSector(sectortype* pSect) +{ + if (isMovableSector(pSect->type) && pSect->hasX()) + { + return (pSect->xs().busy && !pSect->xs().unused1); + } + return false; +} + +TArray getSpritesNearWalls(sectortype* pSrcSect, int nDist) +{ + int i, c = 0, nWall, nSect, swal, ewal; + int xi, yi, wx, wy, lx, ly, sx, sy, qx, qy, num, den; + TArray skip; + TArray out; + + swal = pSrcSect->wallptr; + ewal = swal + pSrcSect->wallnum - 1; + + for (i = swal; i <= ewal; i++) + { + nSect = wall[i].nextsector; + if (nSect < 0) + continue; + + nWall = i; + wx = wall[nWall].wall_int_pos().X; + wy = wall[nWall].wall_int_pos().Y; + lx = wall[wall[nWall].point2].wall_int_pos().X - wx; + ly = wall[wall[nWall].point2].wall_int_pos().Y - wy; + + BloodSectIterator it(nSect); + while(auto ac = it.Next()) + { + if (skip.Find(ac)) + continue; + + sx = ac->spr.pos.X; qx = sx - wx; + sy = ac->spr.pos.Y; qy = sy - wy; + num = DMulScale(qx, lx, qy, ly, 4); + den = DMulScale(lx, lx, ly, ly, 4); + + if (num > 0 && num < den) + { + xi = wx + Scale(lx, num, den); + yi = wy + Scale(ly, num, den); + if (approxDist(xi - sx, yi - sy) <= nDist) + { + skip.Push(ac); + out.Push(ac); + } + } + } + } + return out; +} + +END_BLD_NS + +#endif \ No newline at end of file diff --git a/source/games/blood/src/triggers.cpp b/source/games/blood/src/triggers.cpp index 64d8f9e09..e8ae9f0df 100644 --- a/source/games/blood/src/triggers.cpp +++ b/source/games/blood/src/triggers.cpp @@ -866,6 +866,15 @@ void TranslateSector(sectortype* pSector, int a2, int a3, int a4, int a5, int a6 }); }; + +#ifdef NOONE_EXTENSIONS + // fix Y arg in RotatePoint for reverse (green) moving sprites? + int sprDy = (gModernMap) ? a5 : a4; +#else + int sprDy = a4; +#endif + + if (bAllWalls) { for (auto& wal : wallsofsector(pSector)) @@ -929,7 +938,7 @@ void TranslateSector(sectortype* pSector, int a2, int a3, int a4, int a5, int a6 else if (actor->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) { if (ang) - RotatePoint((int*)&x, (int*)&y, -ang, a4, a4); + RotatePoint((int*)&x, (int*)&y, -ang, a4, sprDy); viewBackupSpriteLoc(actor); actor->spr.ang = (actor->spr.ang - v14) & 2047; actor->spr.pos.X = x - (vc - a4); @@ -951,6 +960,47 @@ void TranslateSector(sectortype* pSector, int a2, int a3, int a4, int a5, int a6 } } } + +#ifdef NOONE_EXTENSIONS + // translate sprites near outside walls + //////////////////////////////////////////////////////////// + + if (gModernMap) + { + auto ptr = gSprNSect.GetSprPtr(sectnum(pSector)); + if (ptr) + { + for (auto& ac : *ptr) + { + if (ac == nullptr) + continue; + + x = ac->basePoint.X; + y = ac->basePoint.Y; + if (ac->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD) + { + if (ang) + RotatePoint(&x, &y, ang, a4, a5); + viewBackupSpriteLoc(ac); + ac->spr.ang = (ac->spr.ang + v14) & 2047; + ac->spr.pos.X = x + vc - a4; + ac->spr.pos.Y = y + v8 - a5; + } + else if (ac->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE) + { + if (ang) + RotatePoint(&x, &y, -ang, a4, sprDy); + viewBackupSpriteLoc(ac); + ac->spr.ang = (ac->spr.ang - v14) & 2047; + ac->spr.pos.X = x - (vc - a4); + ac->spr.pos.Y = y - (v8 - a5); + } + } + } + } + ///////////////////// +#endif + } //--------------------------------------------------------------------------- @@ -962,11 +1012,20 @@ void TranslateSector(sectortype* pSector, int a2, int a3, int a4, int a5, int a6 void ZTranslateSector(sectortype* pSector, XSECTOR* pXSector, int a3, int a4) { viewInterpolateSector(pSector); - int dz = pXSector->onFloorZ - pXSector->offFloorZ; - if (dz != 0) + + int dfz = pXSector->onFloorZ - pXSector->offFloorZ; + int dcz = pXSector->onCeilZ - pXSector->offCeilZ; + +#ifdef NOONE_EXTENSIONS + // get pointer to sprites near outside walls before translation + /////////////////////////////////////////////////////////////// + auto ptr1 = (gModernMap && (dfz || dcz))? gSprNSect.GetSprPtr(sectnum(pSector)) : nullptr; +#endif + + if (dfz != 0) { int oldZ = pSector->floorz; - pSector->setfloorz((pSector->baseFloor = pXSector->offFloorZ + MulScale(dz, GetWaveValue(a3, a4), 16))); + pSector->setfloorz((pSector->baseFloor = pXSector->offFloorZ + MulScale(dfz, GetWaveValue(a3, a4), 16))); pSector->velFloor += (pSector->floorz - oldZ) << 8; BloodSectIterator it(pSector); @@ -989,12 +1048,31 @@ void ZTranslateSector(sectortype* pSector, XSECTOR* pXSector, int a3, int a4) actor->spr.pos.Z += pSector->floorz - oldZ; } } + + +#ifdef NOONE_EXTENSIONS + // translate sprites near outside walls (floor) + //////////////////////////////////////////////////////////// + if (ptr1) + { + for(auto& ac : *ptr1) + { + if (ac && (ac->spr.cstat & CSTAT_SPRITE_MOVE_FORWARD)) + { + viewBackupSpriteLoc(ac); + ac->spr.pos.Z += pSector->floorz - oldZ; + } + } + } + ///////////////////// +#endif + } - dz = pXSector->onCeilZ - pXSector->offCeilZ; - if (dz != 0) + + if (dcz != 0) { int oldZ = pSector->ceilingz; - pSector->setceilingz((pSector->baseCeil = pXSector->offCeilZ + MulScale(dz, GetWaveValue(a3, a4), 16))); + pSector->setceilingz((pSector->baseCeil = pXSector->offCeilZ + MulScale(dcz, GetWaveValue(a3, a4), 16))); pSector->velCeil += (pSector->ceilingz - oldZ) << 8; BloodSectIterator it(pSector); @@ -1008,6 +1086,26 @@ void ZTranslateSector(sectortype* pSector, XSECTOR* pXSector, int a3, int a4) actor->spr.pos.Z += pSector->ceilingz - oldZ; } } + + +#ifdef NOONE_EXTENSIONS + // translate sprites near outside walls (ceil) + //////////////////////////////////////////////////////////// + if (ptr1) + { + for (auto& ac : *ptr1) + { + if (ac && (ac->spr.cstat & CSTAT_SPRITE_MOVE_REVERSE)) + { + viewBackupSpriteLoc(ac); + ac->spr.pos.Z += pSector->ceilingz - oldZ; + } + } + } + + ///////////////////// +#endif + } } @@ -2153,15 +2251,49 @@ void trProcessBusy(void) // //--------------------------------------------------------------------------- +static void UpdateBasePoints(sectortype* pSector) +{ +#ifdef NOONE_EXTENSIONS + if (gModernMap) + { + // must set basepoint for outside sprites as well + auto ptr1 = gSprNSect.GetSprPtr(sectnum(pSector)); + if (ptr1) + { + for (auto& ac : *ptr1) + ac->basePoint = ac->spr.pos; + } + } +#endif + + for (auto& wal : wallsofsector(pSector)) + { + wal.baseWall = wal.pos; + } + BloodSectIterator it(pSector); + while (auto actor = it.Next()) + { + actor->basePoint = actor->spr.pos; + } + +} + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + void InitGenerator(DBloodActor*); void trInit(TArray& actors) { +#ifdef NOONE_EXTENSIONS + if (gModernMap) + gSprNSect.Init(); // collect sprites near outside walls +#endif + gBusy.Clear(); - for (auto& wal : wall) - { - wal.baseWall = wal.pos; - } for (auto actor : actors) { if (!actor->exists()) continue; @@ -2170,6 +2302,7 @@ void trInit(TArray& actors) } for (auto& wal : wall) { + wal.baseWall = wal.pos; if (wal.hasX()) { XWALL* pXWall = &wal.xw(); @@ -2209,15 +2342,7 @@ void trInit(TArray& actors) auto marker0 = pXSector->marker0; auto marker1 = pXSector->marker1; TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); - for (auto& wal : wallsofsector(pSector)) - { - wal.baseWall = wal.pos; - } - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - actor->basePoint = actor->spr.pos; - } + UpdateBasePoints(pSector); TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, marker1->spr.pos.X, marker1->spr.pos.Y, marker1->spr.ang, pSector->type == kSectorSlide); ZTranslateSector(pSector, pXSector, pXSector->busy, 1); break; @@ -2227,19 +2352,12 @@ void trInit(TArray& actors) { auto marker0 = pXSector->marker0; TranslateSector(pSector, 0, -65536, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); - for (auto& wal : wallsofsector(pSector)) - { - wal.baseWall = wal.pos; - } - BloodSectIterator it(pSector); - while (auto actor = it.Next()) - { - actor->basePoint = actor->spr.pos; - } + UpdateBasePoints(pSector); TranslateSector(pSector, 0, pXSector->busy, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.pos.X, marker0->spr.pos.Y, 0, marker0->spr.pos.X, marker0->spr.pos.Y, marker0->spr.ang, pSector->type == kSectorRotate); ZTranslateSector(pSector, pXSector, pXSector->busy, 1); break; } + case kSectorPath: InitPath(pSector, pXSector); break;