From 074bce643a22432a2a59c5c1f6fe4532022992fe Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 20 Apr 2016 20:02:26 -0500 Subject: [PATCH 01/11] Fixed: A_SetAngle had accidentally had the "action" specifier removed --- wadsrc/static/actors/actor.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index fc51c6d5c..9222741bd 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -268,7 +268,7 @@ ACTOR Actor native //: Thinker native void A_DropWeaponPieces(class p1, class p2, class p3); action native A_PigPain (); native state A_MonsterRefire(int chance, state label); - native void A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); + action native A_SetAngle(float angle = 0, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetPitch(float pitch, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_SetRoll(float/*angle*/ roll, int flags = 0, int ptr = AAPTR_DEFAULT); native void A_ScaleVelocity(float scale, int ptr = AAPTR_DEFAULT); From c3eec6db4d4535798d32d393d62ae653f8553f3a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 20 Apr 2016 20:03:21 +0200 Subject: [PATCH 02/11] -fixed warnings --- src/p_saveg.cpp | 2 +- src/p_spec.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 55320e056..efcbb2406 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -453,7 +453,7 @@ void P_SerializeWorld (FArchive &arc) void P_SerializeWorldActors(FArchive &arc) { - int i, j; + int i; sector_t *sec; for (i = 0, sec = sectors; i < numsectors; i++, sec++) diff --git a/src/p_spec.cpp b/src/p_spec.cpp index fbbc77a04..af6a82083 100644 --- a/src/p_spec.cpp +++ b/src/p_spec.cpp @@ -893,7 +893,7 @@ void P_SetupPortals() { if (ss.mType == PORTS_STACKEDSECTORTHING && ss.mSkybox == s.mSkybox->target) { - s.mPartner = (&ss) - §orPortals[0]; + s.mPartner = unsigned((&ss) - §orPortals[0]); } } } From ba7260c1761c2f6846235bbc96650ab4eb728baa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Apr 2016 10:51:41 +0200 Subject: [PATCH 03/11] - fixed overflow issue with large damage values in P_RadiusAttack. --- src/p_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.cpp b/src/p_map.cpp index f5a19f269..c89418a32 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5178,8 +5178,8 @@ void P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bo } points *= thing->GetClass()->RDFactor; - // points and bombdamage should be the same sign - if (((int(points) * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) + // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) + if ((((double)int(points) * bombdamage) > 0) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) { // OK to damage; target is in direct path double vz; double thrust; From 27cc3d6289a6e1a8d26dfdb83eb430adf19e8d4e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Apr 2016 11:17:28 +0200 Subject: [PATCH 04/11] - fixed: ACS's GetActorLightLevel didn't check 3D floors. --- src/p_3dfloors.cpp | 2 +- src/p_acs.cpp | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/p_3dfloors.cpp b/src/p_3dfloors.cpp index 393bcafa6..8da672513 100644 --- a/src/p_3dfloors.cpp +++ b/src/p_3dfloors.cpp @@ -723,7 +723,7 @@ lightlist_t * P_GetPlaneLight(sector_t * sector, secplane_t * plane, bool unders TArray &lightlist = sector->e->XFloor.lightlist; double planeheight=plane->ZatPoint(sector->centerspot); - if(underside) planeheight--; + if(underside) planeheight-= EQUAL_EPSILON; for(i = 1; i < lightlist.Size(); i++) if (lightlist[i].plane.ZatPoint(sector->centerspot) <= planeheight) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 27adce19e..83ef42b9a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9346,7 +9346,26 @@ scriptwait: AActor *actor = SingleActorFromTID(STACK(1), activator); if (actor != NULL) { - STACK(1) = actor->Sector->lightlevel; + sector_t *sector = actor->Sector; + if (sector->e->XFloor.lightlist.Size()) + { + unsigned i; + TArray &lightlist = sector->e->XFloor.lightlist; + + STACK(1) = *lightlist.Last().p_lightlevel; + for (i = 1; i < lightlist.Size(); i++) + { + if (lightlist[i].plane.ZatPoint(actor) <= actor->Z()) + { + STACK(1) = *lightlist[i - 1].p_lightlevel; + break; + } + } + } + else + { + STACK(1) = actor->Sector->lightlevel; + } } else STACK(1) = 0; break; From ad9b9479ec424aeb59c7d22a17b085e51b0539af Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 20 Apr 2016 22:59:57 +0200 Subject: [PATCH 05/11] - Fixed erroneous P_UndoPlayerMorph calls. In some places, P_UndoPlayerMorph was called with the 'force' argument placed in the 'unmorphflag' parameter, so that 'forced' unmorphs would be not completely forceful. I hope no mod relied on this weirdness... --- src/g_shared/a_morph.cpp | 2 +- src/p_acs.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/g_shared/a_morph.cpp b/src/g_shared/a_morph.cpp index 3b3741a43..d0e807c3e 100644 --- a/src/g_shared/a_morph.cpp +++ b/src/g_shared/a_morph.cpp @@ -514,7 +514,7 @@ bool P_MorphedDeath(AActor *actor, AActor **morphed, int *morphedstyle, int *mor AActor *realme = actor->player->mo->tracer; int realstyle = actor->player->MorphStyle; int realhealth = actor->health; - if (P_UndoPlayerMorph(actor->player, actor->player, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED))) + if (P_UndoPlayerMorph(actor->player, actor->player, 0, !!(actor->player->MorphStyle & MORPH_UNDOBYDEATHFORCED))) { *morphed = realme; *morphedstyle = realstyle; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 83ef42b9a..e56aeb596 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -9455,7 +9455,7 @@ scriptwait: { if (activator->player) { - if (P_UndoPlayerMorph(activator->player, activator->player, force)) + if (P_UndoPlayerMorph(activator->player, activator->player, 0, force)) { changes++; } @@ -9481,7 +9481,7 @@ scriptwait: { if (actor->player) { - if (P_UndoPlayerMorph(activator->player, actor->player, force)) + if (P_UndoPlayerMorph(activator->player, actor->player, 0, force)) { changes++; } From ed070cfe06b2e4b91a0975fcb45c1cd2c08cf8b9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Apr 2016 13:01:57 +0200 Subject: [PATCH 06/11] - updated xlat/eternity.txt. --- wadsrc/static/xlat/eternity.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wadsrc/static/xlat/eternity.txt b/wadsrc/static/xlat/eternity.txt index 6d136d887..bca1a6769 100644 --- a/wadsrc/static/xlat/eternity.txt +++ b/wadsrc/static/xlat/eternity.txt @@ -220,3 +220,13 @@ enum 433 = 0, Ceiling_CrushStop(0) 434 = 0, Ceiling_CrushRaiseAndStay(0) 435 = 0, Ceiling_LowerAndCrush(0) +436 = 0, Ceiling_LowerAndCrushDist(0) +437 = 0, Ceiling_CrushAndRaiseDist(0) +438 = 0, Ceiling_CrushRaiseAndStayA(0) +439 = 0, Ceiling_CrushAndRaiseA(0) +440 = 0, Ceiling_CrushAndRaiseSilentA(0) +441 = 0, Ceiling_CrushAndRaiseSilentDist(0) +442 = 0, Ceiling_CrushRaiseAndStaySilA(0) +443 = 0, Generic_Crusher(0) +444 = 0, Teleport(0) +445 = 0, Teleport_NoFog(0) From 7b35f32f3de012ccb0ccabe9086cffddcfe0bd00 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 21 Apr 2016 15:28:51 +0200 Subject: [PATCH 07/11] - Added the 'GiveInventory' method to the actor. This will help cleaning up the item giving code. Returns a bool, in case the pickup failure might turn to be interesting in the future. --- src/actor.h | 4 ++++ src/p_mobj.cpp | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/actor.h b/src/actor.h index 8741a9597..a56d0d6d9 100644 --- a/src/actor.h +++ b/src/actor.h @@ -661,6 +661,10 @@ public: // Adds the item to this actor's inventory and sets its Owner. virtual void AddInventory (AInventory *item); + // Give an item to the actor and pick it up. + // Returns true if the item pickup succeeded. + virtual bool GiveInventory (PClassInventory *type, int amount, bool givecheat = false); + // Removes the item from the inventory list. virtual void RemoveInventory (AInventory *item); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 46bc320df..b7d887195 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -612,6 +612,62 @@ void AActor::AddInventory (AInventory *item) Inventory->InventoryID = InventoryID++; } +//============================================================================ +// +// AActor :: GiveInventory +// +//============================================================================ + +bool AActor::GiveInventory(PClassInventory *type, int amount, bool givecheat) +{ + bool result = true; + + AWeapon *savedPendingWeap = player != NULL ? player->PendingWeapon : NULL; + bool hadweap = player != NULL ? player->ReadyWeapon != NULL : true; + + AInventory *item; + if (!givecheat) + { + item = static_cast(Spawn (type)); + } + else + { + item = static_cast(Spawn (type, Pos(), NO_REPLACE)); + if (item == NULL) return false; + } + + // This shouldn't count for the item statistics! + item->ClearCounters(); + if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorPickup))) + { + static_cast(item)->SaveAmount *= amount; + } + else if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) + { + static_cast(item)->SaveAmount *= amount; + } + else + { + if (!givecheat) + item->Amount = amount; + else + item->Amount = MIN (amount, item->MaxAmount); + } + if (!item->CallTryPickup (this)) + { + item->Destroy (); + result = false; + } + // If the item was a weapon, don't bring it up automatically + // unless the player was not already using a weapon. + // Don't bring it up automatically if this is called by the give cheat. + if (!givecheat && player != NULL && savedPendingWeap != NULL && hadweap) + { + player->PendingWeapon = savedPendingWeap; + } + return result; +} + //============================================================================ // // AActor :: RemoveInventory From 6aca7604eb37ba8e436261015603b4c9a2f1d311 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 21 Apr 2016 16:00:34 +0200 Subject: [PATCH 08/11] - Clean the code by using AActor::GiveInventory. This fixes also a bug in FraggleScript GiveInventory, which tried to access the 'SaveAmount' member of 'ABasicArmorBonus' with the wrong cast. --- src/fragglescript/t_func.cpp | 27 +------------------ src/m_cheat.cpp | 51 ++++-------------------------------- src/p_acs.cpp | 46 ++------------------------------ src/p_conversation.cpp | 2 -- 4 files changed, 8 insertions(+), 118 deletions(-) diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index 4826a6ca4..5d4320a4f 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -2439,32 +2439,7 @@ static void FS_GiveInventory (AActor *actor, const char * type, int amount) return; } - AWeapon *savedPendingWeap = actor->player != NULL? actor->player->PendingWeapon : NULL; - bool hadweap = actor->player != NULL ? actor->player->ReadyWeapon != NULL : true; - - AInventory *item = static_cast(Spawn (info)); - - // This shouldn't count for the item statistics! - item->ClearCounters(); - if (info->IsDescendantOf (RUNTIME_CLASS(ABasicArmorPickup)) || - info->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) - { - static_cast(item)->SaveAmount *= amount; - } - else - { - item->Amount = amount; - } - if (!item->CallTryPickup (actor)) - { - item->Destroy (); - } - // If the item was a weapon, don't bring it up automatically - // unless the player was not already using a weapon. - if (savedPendingWeap != NULL && hadweap) - { - actor->player->PendingWeapon = savedPendingWeap; - } + actor->GiveInventory(info, amount); } //============================================================================ diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index c9b478161..d7622b3d4 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -575,47 +575,6 @@ const char *cht_Morph (player_t *player, PClassPlayerPawn *morphclass, bool quic return ""; } -void GiveSpawner (player_t *player, PClassInventory *type, int amount) -{ - if (player->mo == NULL || player->health <= 0) - { - return; - } - - AInventory *item = static_cast - (Spawn (type, player->mo->Pos(), NO_REPLACE)); - if (item != NULL) - { - if (amount > 0) - { - if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorPickup))) - { - if (static_cast(item)->SaveAmount != 0) - { - static_cast(item)->SaveAmount *= amount; - } - else - { - static_cast(item)->SaveAmount *= amount; - } - } - else if (type->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) - { - static_cast(item)->SaveAmount *= amount; - } - else - { - item->Amount = MIN (amount, item->MaxAmount); - } - } - item->ClearCounters(); - if (!item->CallTryPickup (player->mo)) - { - item->Destroy (); - } - } -} - void cht_Give (player_t *player, const char *name, int amount) { enum { ALL_NO, ALL_YES, ALL_YESYES } giveall; @@ -673,7 +632,7 @@ void cht_Give (player_t *player, const char *name, int amount) type = PClass::FindActor(gameinfo.backpacktype); if (type != NULL) { - GiveSpawner (player, static_cast(type), 1); + player->mo->GiveInventory(static_cast(type), 1, true); } if (!giveall) @@ -778,7 +737,7 @@ void cht_Give (player_t *player, const char *name, int amount) AWeapon *def = (AWeapon*)GetDefaultByType (type); if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { - GiveSpawner (player, static_cast(type), 1); + player->mo->GiveInventory(static_cast(type), 1, true); } } } @@ -805,7 +764,7 @@ void cht_Give (player_t *player, const char *name, int amount) // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { - GiveSpawner (player, static_cast(type), amount <= 0 ? def->MaxAmount : amount); + player->mo->GiveInventory(static_cast(type), amount <= 0 ? def->MaxAmount : amount, true); } } } @@ -827,7 +786,7 @@ void cht_Give (player_t *player, const char *name, int amount) // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { - GiveSpawner (player, static_cast(type), amount <= 0 ? def->MaxAmount : amount); + player->mo->GiveInventory(static_cast(type), amount <= 0 ? def->MaxAmount : amount, true); } } } @@ -847,7 +806,7 @@ void cht_Give (player_t *player, const char *name, int amount) } else { - GiveSpawner (player, static_cast(type), amount); + player->mo->GiveInventory(static_cast(type), amount, true); } return; } diff --git a/src/p_acs.cpp b/src/p_acs.cpp index e56aeb596..0437bc9f0 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1142,48 +1142,6 @@ static void ClearInventory (AActor *activator) } } -//============================================================================ -// -// DoGiveInv -// -// Gives an item to a single actor. -// -//============================================================================ - -static void DoGiveInv (AActor *actor, PClassActor *info, int amount) -{ - AWeapon *savedPendingWeap = actor->player != NULL - ? actor->player->PendingWeapon : NULL; - bool hadweap = actor->player != NULL ? actor->player->ReadyWeapon != NULL : true; - - AInventory *item = static_cast(Spawn (info)); - - // This shouldn't count for the item statistics! - item->ClearCounters(); - if (info->IsDescendantOf (RUNTIME_CLASS(ABasicArmorPickup))) - { - static_cast(item)->SaveAmount *= amount; - } - else if (info->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) - { - static_cast(item)->SaveAmount *= amount; - } - else - { - item->Amount = amount; - } - if (!item->CallTryPickup (actor)) - { - item->Destroy (); - } - // If the item was a weapon, don't bring it up automatically - // unless the player was not already using a weapon. - if (savedPendingWeap != NULL && hadweap && actor->player != NULL) - { - actor->player->PendingWeapon = savedPendingWeap; - } -} - //============================================================================ // // GiveInventory @@ -1218,12 +1176,12 @@ static void GiveInventory (AActor *activator, const char *type, int amount) for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i]) - DoGiveInv (players[i].mo, info, amount); + players[i].mo->GiveInventory(static_cast(info), amount); } } else { - DoGiveInv (activator, info, amount); + activator->GiveInventory(static_cast(info), amount); } } diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index e8aaa6912..64fe2cbab 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -102,8 +102,6 @@ struct TeaserSpeech static FRandom pr_randomspeech("RandomSpeech"); -void GiveSpawner (player_t *player, PClassActor *type); - TArray StrifeDialogues; typedef TMap FDialogueIDMap; // maps dialogue IDs to dialogue array index (for ACS) From 6cfd82f5009177c5a206677e3908b3abcdc0d307 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 21 Apr 2016 16:03:33 +0200 Subject: [PATCH 09/11] - Simplify more, found by code inspection. --- src/m_cheat.cpp | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/src/m_cheat.cpp b/src/m_cheat.cpp index d7622b3d4..ff9e2ac9a 100644 --- a/src/m_cheat.cpp +++ b/src/m_cheat.cpp @@ -603,26 +603,12 @@ void cht_Give (player_t *player, const char *name, int amount) { if (amount > 0) { - if (player->mo) - { - player->mo->health += amount; - player->health = player->mo->health; - } - else - { - player->health += amount; - } + player->mo->health += amount; + player->health = player->mo->health; } else { - if (player->mo != NULL) - { - player->health = player->mo->health = player->mo->GetMaxHealth(); - } - else - { - player->health = deh.GodHealth; - } + player->health = player->mo->health = player->mo->GetMaxHealth(); } } From afa3009f93cb8f41272a313140f2427f47ab3556 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Thu, 21 Apr 2016 16:07:41 +0200 Subject: [PATCH 10/11] - Fixed a GCC/Clang compiler error and a warning. --- src/p_ceiling.cpp | 2 +- src/r_main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 9c5d693a0..8a0c8f9ef 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -253,7 +253,7 @@ bool P_CreateCeiling(sector_t *sec, DCeiling::ECeiling type, line_t *line, int t // if ceiling already moving, don't start a second function on it if (sec->PlaneMoving(sector_t::ceiling)) { - return NULL; + return false; } // new door thinker diff --git a/src/r_main.cpp b/src/r_main.cpp index 1344ac453..f6a341f4e 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -693,7 +693,7 @@ void R_EnterPortal (PortalDrawseg* pds, int depth) fixed_t starty = viewy; fixed_t startz = viewz; DVector3 savedpath[2] = { ViewPath[0], ViewPath[1] }; - int savedvisibility = camera? camera->renderflags & RF_INVISIBLE : 0; + ActorRenderFlags savedvisibility = camera? camera->renderflags & RF_INVISIBLE : ActorRenderFlags::FromInt(0); CurrentPortalUniq++; From 382a6e8b9fb44cc97042fcc20fe054531c16caf0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 21 Apr 2016 22:59:07 +0200 Subject: [PATCH 11/11] - link actors to touching line portals, for use by the renderer. --- src/actor.h | 4 +- src/p_map.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++++ src/portal.cpp | 4 +- src/portal.h | 2 + src/r_defs.h | 12 ++++++ 5 files changed, 134 insertions(+), 3 deletions(-) diff --git a/src/actor.h b/src/actor.h index a56d0d6d9..10bbd119a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -965,6 +965,7 @@ public: void CheckSectorTransition(sector_t *oldsec); void UpdateRenderSectorList(); void ClearRenderSectorList(); + void ClearRenderLineList(); // info for drawing // NOTE: The first member variable *must* be snext. @@ -1101,7 +1102,8 @@ public: // a linked list of sectors where this object appears struct msecnode_t *touching_sectorlist; // phares 3/14/98 - struct msecnode_t *render_sectorlist; // same for cross-portal rendering + struct msecnode_t *render_sectorlist; // same for cross-sectorportal rendering + struct portnode_t *render_portallist; // and for cross-lineportal TObjPtr Inventory; // [RH] This actor's inventory diff --git a/src/p_map.cpp b/src/p_map.cpp index c89418a32..72746f2fb 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -44,6 +44,7 @@ #include "p_trace.h" #include "p_checkposition.h" #include "r_utility.h" +#include "p_blockmap.h" #include "s_sound.h" #include "decallib.h" @@ -6238,6 +6239,91 @@ void P_CreateSecNodeList(AActor *thing) } +//============================================================================= +// +// P_DelPortalnode +// +// Same for line portal nodes +// +//============================================================================= + +portnode_t *P_DelPortalnode(portnode_t *node) +{ + portnode_t* tp; // prev node on thing thread + portnode_t* tn; // next node on thing thread + portnode_t* sp; // prev node on sector thread + portnode_t* sn; // next node on sector thread + + if (node) + { + // Unlink from the Thing thread. The Thing thread begins at + // sector_list and not from AActor->touching_sectorlist. + + tp = node->m_tprev; + tn = node->m_tnext; + if (tp) + tp->m_tnext = tn; + if (tn) + tn->m_tprev = tp; + + // Unlink from the sector thread. This thread begins at + // sector_t->touching_thinglist. + + sp = node->m_sprev; + sn = node->m_snext; + if (sp) + sp->m_snext = sn; + else + node->m_portal->render_thinglist = sn; + if (sn) + sn->m_sprev = sp; + + // Return this node to the freelist (use the same one as for msecnodes, since both types are the same size.) + P_PutSecnode(reinterpret_cast(node)); + return tn; + } + return NULL; +} + + +//============================================================================= +// +// P_AddPortalnode +// +//============================================================================= + +portnode_t *P_AddPortalnode(FLinePortal *s, AActor *thing, portnode_t *nextnode) +{ + portnode_t *node; + + if (s == 0) + { + I_FatalError("AddSecnode of 0 for %s\n", thing->GetClass()->TypeName.GetChars()); + } + + node = reinterpret_cast(P_GetSecnode()); + + // killough 4/4/98, 4/7/98: mark new nodes unvisited. + node->visited = 0; + + node->m_portal = s; // portal + node->m_thing = thing; // mobj + node->m_tprev = NULL; // prev node on Thing thread + node->m_tnext = nextnode; // next node on Thing thread + if (nextnode) + nextnode->m_tprev = node; // set back link on Thing + + // Add new node at head of portal thread starting at s->touching_thinglist + + node->m_sprev = NULL; // prev node on portal thread + node->m_snext = s->render_thinglist; // next node on portal thread + if (s->render_thinglist) + node->m_snext->m_sprev = node; + s->render_thinglist = node; + return node; +} + + //========================================================================== // // Handle the lists used to render actors from other portal areas @@ -6249,6 +6335,27 @@ void AActor::UpdateRenderSectorList() static const double SPRITE_SPACE = 64.; if (Pos() != OldRenderPos && !(flags & MF_NOSECTOR)) { + // Only check if the map contains line portals + ClearRenderLineList(); + if (PortalBlockmap.containsLines && Pos().XY() != OldRenderPos.XY()) + { + int bx = GetBlockX(X()); + int by = GetBlockX(Y()); + FBoundingBox bb(X(), Y(), MIN(radius*1.5, 128.)); // Don't go further than 128 map units, even for large actors + // Are there any portals near the actor's position? + if (bx >= 0 && by >= 0 && bx < bmapwidth && by < bmapheight && PortalBlockmap(bx, by).neighborContainsLines) + { + // Go through the entire list. In most cases this is faster than setting up a blockmap iterator + for (auto &p : linePortals) + { + if (p.mType == PORTT_VISUAL) continue; + if (bb.inRange(p.mOrigin) && bb.BoxOnLineSide(p.mOrigin)) + { + render_portallist = P_AddPortalnode(&p, this, render_portallist); + } + } + } + } sector_t *sec = Sector; double lasth = -FLT_MAX; ClearRenderSectorList(); @@ -6284,6 +6391,14 @@ void AActor::ClearRenderSectorList() render_sectorlist = NULL; } +void AActor::ClearRenderLineList() +{ + portnode_t *node = render_portallist; + while (node) + node = P_DelPortalnode(node); + render_portallist = NULL; +} + //========================================================================== // diff --git a/src/portal.cpp b/src/portal.cpp index 3dfd9a050..6abd4e8da 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -119,8 +119,8 @@ static void BuildBlockmap() while (*list != -1) { line_t *ld = &lines[*list++]; - - if (ld->isLinePortal()) + FLinePortal *port = ld->getPortal(); + if (port && port->mType != PORTT_VISUAL) { PortalBlockmap.containsLines = true; block.portallines.Push(ld); diff --git a/src/portal.h b/src/portal.h index 9c05f23b7..bba674def 100644 --- a/src/portal.h +++ b/src/portal.h @@ -7,6 +7,7 @@ struct FPortalGroupArray; class ASkyViewpoint; +struct portnode_t; //============================================================================ // // This table holds the offsets for the different parts of a map @@ -189,6 +190,7 @@ struct FLinePortal DAngle mAngleDiff; double mSinRot; double mCosRot; + portnode_t *render_thinglist; void *mRenderData; }; diff --git a/src/r_defs.h b/src/r_defs.h index 9f04dc2aa..ad043a404 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1387,6 +1387,18 @@ struct msecnode_t bool visited; // killough 4/4/98, 4/7/98: used in search algorithms }; +// use the same memory layout as msecnode_t so both can be used from the same freelist. +struct portnode_t +{ + FLinePortal *m_portal; // a portal containing this object + AActor *m_thing; // this object + struct portnode_t *m_tprev; // prev msecnode_t for this thing + struct portnode_t *m_tnext; // next msecnode_t for this thing + struct portnode_t *m_sprev; // prev msecnode_t for this portal + struct portnode_t *m_snext; // next msecnode_t for this portal + bool visited; +}; + struct FPolyNode; struct FMiniBSP;