diff --git a/src/actor.h b/src/actor.h index 8f317b71aa..88dfd3c4eb 100644 --- a/src/actor.h +++ b/src/actor.h @@ -959,11 +959,14 @@ public: // Triggers SECSPAC_Exit/SECSPAC_Enter and related events if oldsec != current sector void CheckSectorTransition(sector_t *oldsec); + void UpdateRenderSectorList(); + void ClearRenderSectorList(); // info for drawing // NOTE: The first member variable *must* be snext. AActor *snext, **sprev; // links in sector (if needed) DVector3 __Pos; // double underscores so that it won't get used by accident. Access to this should be exclusively through the designated access functions. + DVector3 OldRenderPos; DRotator Angles; DVector3 Vel; @@ -1094,6 +1097,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 + TObjPtr Inventory; // [RH] This actor's inventory DWORD InventoryID; // A unique ID to keep track of inventory items diff --git a/src/g_hexen/a_wraith.cpp b/src/g_hexen/a_wraith.cpp index 24ae22afd6..460fa65032 100644 --- a/src/g_hexen/a_wraith.cpp +++ b/src/g_hexen/a_wraith.cpp @@ -127,8 +127,8 @@ DEFINE_ACTION_FUNCTION(AActor, A_WraithFX2) angle = -angle; } angle += self->Angles.Yaw; - mo->Vel.X = ((pr_wraithfx2() << 7) + 1) * angle.Cos(); - mo->Vel.Y = ((pr_wraithfx2() << 7) + 1) * angle.Sin(); + mo->Vel.X = ((pr_wraithfx2() / 512.) + 1) * angle.Cos(); + mo->Vel.Y = ((pr_wraithfx2() / 512.) + 1) * angle.Sin(); mo->Vel.Z = 0; mo->target = self; mo->Floorclip = 10; diff --git a/src/nodebuild.cpp b/src/nodebuild.cpp index c56ee697ea..d1a8737ecd 100644 --- a/src/nodebuild.cpp +++ b/src/nodebuild.cpp @@ -811,15 +811,6 @@ void FNodeBuilder::SplitSegs (DWORD set, node_t &node, DWORD splitseg, DWORD &ou unsigned int vertnum; int seg2; - if (seg->loopnum) - { - Printf (" Split seg %u (%d,%d)-(%d,%d) of sector %td in loop %d\n", - set, - Vertices[seg->v1].x>>16, Vertices[seg->v1].y>>16, - Vertices[seg->v2].x>>16, Vertices[seg->v2].y>>16, - seg->frontsector - sectors, seg->loopnum); - } - frac = InterceptVector (node, *seg); newvert.x = Vertices[seg->v1].x; newvert.y = Vertices[seg->v1].y; diff --git a/src/p_local.h b/src/p_local.h index a5336a9ee1..1a89154956 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -350,7 +350,8 @@ void P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, void P_DelSector_List(); void P_DelSeclist(msecnode_t *); // phares 3/16/98 -msecnode_t* P_DelSecnode(msecnode_t *); +msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist); +msecnode_t* P_DelSecnode(msecnode_t *, msecnode_t *sector_t::*head); void P_CreateSecNodeList(AActor*); // phares 3/14/98 double P_GetMoveFactor(const AActor *mo, double *frictionp); // phares 3/6/98 double P_GetFriction(const AActor *mo, double *frictionfactor); diff --git a/src/p_map.cpp b/src/p_map.cpp index 8254ac5bb0..33f69f2011 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -5555,6 +5555,7 @@ int P_PushUp(AActor *thing, FChangePosition *cpos) intersect->SetZ(oldz); return 2; } + intersect->UpdateRenderSectorList(); } thing->CheckPortalTransition(true); return 0; @@ -5602,6 +5603,7 @@ int P_PushDown(AActor *thing, FChangePosition *cpos) intersect->SetZ(oldz); return 2; } + intersect->UpdateRenderSectorList(); } } thing->CheckPortalTransition(true); @@ -5634,6 +5636,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) { thing->SetZ(thing->floorz); P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); } } else if ((thing->Z() != oldfloorz && !(thing->flags & MF_NOLIFTDROP))) @@ -5642,6 +5645,7 @@ void PIT_FloorDrop(AActor *thing, FChangePosition *cpos) { thing->AddZ(-oldfloorz + thing->floorz); P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); } } if (thing->player && thing->player->mo == thing) @@ -5689,10 +5693,12 @@ void PIT_FloorRaise(AActor *thing, FChangePosition *cpos) { default: P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); break; case 1: P_DoCrunch(thing, cpos); P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); break; case 2: P_DoCrunch(thing, cpos); @@ -5735,6 +5741,7 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) { thing->SetZ(thing->floorz); } + thing->UpdateRenderSectorList(); switch (P_PushDown(thing, cpos)) { case 2: @@ -5744,9 +5751,11 @@ void PIT_CeilingLower(AActor *thing, FChangePosition *cpos) thing->SetZ(thing->floorz); P_DoCrunch(thing, cpos); P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); break; default: P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); break; } } @@ -5782,6 +5791,7 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) thing->SetZ(thing->ceilingz - thing->Height); } P_CheckFakeFloorTriggers(thing, oldz); + thing->UpdateRenderSectorList(); } else if ((thing->flags2 & MF2_PASSMOBJ) && !isgood && thing->Top() < thing->ceilingz) { @@ -5789,6 +5799,7 @@ void PIT_CeilingRaise(AActor *thing, FChangePosition *cpos) if (!P_TestMobjZ(thing, true, &onmobj) && onmobj->Z() <= thing->Z()) { thing->SetZ(MIN(thing->ceilingz - thing->Height, onmobj->Top())); + thing->UpdateRenderSectorList(); } } if (thing->player && thing->player->mo == thing) @@ -6023,7 +6034,7 @@ void P_PutSecnode(msecnode_t *node) // //============================================================================= -msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode) +msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode, msecnode_t *&sec_thinglist) { msecnode_t *node; @@ -6061,10 +6072,10 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode) // Add new node at head of sector thread starting at s->touching_thinglist node->m_sprev = NULL; // prev node on sector thread - node->m_snext = s->touching_thinglist; // next node on sector thread - if (s->touching_thinglist) + node->m_snext = sec_thinglist; // next node on sector thread + if (sec_thinglist) node->m_snext->m_sprev = node; - s->touching_thinglist = node; + sec_thinglist = node; return node; } @@ -6078,7 +6089,7 @@ msecnode_t *P_AddSecnode(sector_t *s, AActor *thing, msecnode_t *nextnode) // //============================================================================= -msecnode_t *P_DelSecnode(msecnode_t *node) +msecnode_t *P_DelSecnode(msecnode_t *node, msecnode_t *sector_t::*listhead) { msecnode_t* tp; // prev node on thing thread msecnode_t* tn; // next node on thing thread @@ -6105,7 +6116,7 @@ msecnode_t *P_DelSecnode(msecnode_t *node) if (sp) sp->m_snext = sn; else - node->m_sector->touching_thinglist = sn; + node->m_sector->*listhead = sn; if (sn) sn->m_sprev = sp; @@ -6145,7 +6156,7 @@ void P_DelSector_List() void P_DelSeclist(msecnode_t *node) { while (node) - node = P_DelSecnode(node); + node = P_DelSecnode(node, §or_t::touching_thinglist); } //============================================================================= @@ -6189,7 +6200,7 @@ void P_CreateSecNodeList(AActor *thing) // allowed to move to this position, then the sector_list // will be attached to the Thing's AActor at touching_sectorlist. - sector_list = P_AddSecnode(ld->frontsector, thing, sector_list); + sector_list = P_AddSecnode(ld->frontsector, thing, sector_list, ld->frontsector->touching_thinglist); // Don't assume all lines are 2-sided, since some Things // like MT_TFOG are allowed regardless of whether their radius takes @@ -6199,12 +6210,12 @@ void P_CreateSecNodeList(AActor *thing) // Use sidedefs instead of 2s flag to determine two-sidedness. if (ld->backsector) - sector_list = P_AddSecnode(ld->backsector, thing, sector_list); + sector_list = P_AddSecnode(ld->backsector, thing, sector_list, ld->backsector->touching_thinglist); } // Add the sector of the (x,y) point to sector_list. - sector_list = P_AddSecnode(thing->Sector, thing, sector_list); + sector_list = P_AddSecnode(thing->Sector, thing, sector_list, thing->Sector->touching_thinglist); // Now delete any nodes that won't be used. These are the ones where // m_thing is still NULL. @@ -6216,7 +6227,7 @@ void P_CreateSecNodeList(AActor *thing) { if (node == sector_list) sector_list = node->m_tnext; - node = P_DelSecnode(node); + node = P_DelSecnode(node, §or_t::touching_thinglist); } else { @@ -6225,6 +6236,54 @@ void P_CreateSecNodeList(AActor *thing) } } + +//========================================================================== +// +// Handle the lists used to render actors from other portal areas +// +//========================================================================== + +void AActor::UpdateRenderSectorList() +{ + static const double SPRITE_SPACE = 64.; + if (Pos() != OldRenderPos) + { + sector_t *sec = Sector; + double lasth = -FLT_MAX; + ClearRenderSectorList(); + while (!sec->PortalBlocksMovement(sector_t::ceiling)) + { + double planeh = sec->SkyBoxes[sector_t::ceiling]->specialf1; + if (planeh < lasth) break; // broken setup. + if (Top() + SPRITE_SPACE < planeh) break; + lasth = planeh; + DVector2 newpos = Pos() + sec->SkyBoxes[sector_t::ceiling]->Scale; + sec = P_PointInSector(newpos); + render_sectorlist = P_AddSecnode(sec, this, render_sectorlist, sec->render_thinglist); + } + lasth = FLT_MAX; + while (!sec->PortalBlocksMovement(sector_t::floor)) + { + double planeh = sec->SkyBoxes[sector_t::floor]->specialf1; + if (planeh > lasth) break; // broken setup. + if (Z() - SPRITE_SPACE > planeh) break; + lasth = planeh; + DVector2 newpos = Pos() + sec->SkyBoxes[sector_t::floor]->Scale; + sec = P_PointInSector(newpos); + render_sectorlist = P_AddSecnode(sec, this, render_sectorlist, sec->render_thinglist); + } + } +} + +void AActor::ClearRenderSectorList() +{ + msecnode_t *node = render_sectorlist; + while (node) + node = P_DelSecnode(node, §or_t::render_thinglist); + render_sectorlist = NULL; +} + + //========================================================================== // // diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index f018be55b5..18caa2f3c1 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3752,6 +3752,9 @@ void AActor::Tick () if (!CheckNoDelay()) return; // freed itself // cycle through states, calling action functions at transitions + + UpdateRenderSectorList(); + if (tics != -1) { // [RH] Use tics <= 0 instead of == 0 so that spawnstates @@ -4011,6 +4014,7 @@ AActor *AActor::StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t a } actor->SetXYZ(pos); + actor->OldRenderPos = { FLT_MAX, FLT_MAX, FLT_MAX }; actor->picnum.SetInvalid(); actor->health = actor->SpawnHealth(); @@ -4322,12 +4326,15 @@ void AActor::Deactivate (AActor *activator) } } + // // P_RemoveMobj // void AActor::Destroy () { + ClearRenderSectorList(); + // [RH] Destroy any inventory this actor is carrying DestroyAllInventory (); diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index e8703dde1d..731d2e9a4f 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -544,7 +544,7 @@ void P_SerializePolyobjs (FArchive &arc) arc << seg << po_NumPolyobjs; for(i = 0, po = polyobjs; i < po_NumPolyobjs; i++, po++) { - arc << po->tag << po->Angle << po->StartSpot.pos << po->interpolation << po->bBlocked; + arc << po->tag << po->Angle << po->StartSpot.pos << po->interpolation << po->bBlocked << po->bHasPortals; } } else @@ -578,6 +578,14 @@ void P_SerializePolyobjs (FArchive &arc) { po->bBlocked = false; } + if (SaveVersion >= 4538) + { + arc << po->bHasPortals; + } + else + { + po->bHasPortals = 0; + } po->RotatePolyobj (angle, true); delta -= po->StartSpot.pos; diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 148dcbea85..718e54e9b6 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -1510,6 +1510,7 @@ void P_LoadSectors (MapData *map, FMissingTextureTracker &missingtex) tagManager.AddSectorTag(i, LittleShort(ms->tag)); ss->thinglist = NULL; ss->touching_thinglist = NULL; // phares 3/14/98 + ss->render_thinglist = NULL; ss->seqType = defSeqType; ss->SeqName = NAME_None; ss->nextsec = -1; //jff 2/26/98 add fields to support locking out diff --git a/src/p_udmf.cpp b/src/p_udmf.cpp index 017f73cf15..20852a5858 100644 --- a/src/p_udmf.cpp +++ b/src/p_udmf.cpp @@ -1291,6 +1291,7 @@ public: sec->SetAlpha(sector_t::ceiling, 1.); sec->thinglist = NULL; sec->touching_thinglist = NULL; // phares 3/14/98 + sec->render_thinglist = NULL; sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL) ? 0 : -1; sec->nextsec = -1; //jff 2/26/98 add fields to support locking out sec->prevsec = -1; // stair retriggering until build completes diff --git a/src/p_user.cpp b/src/p_user.cpp index 30a849b846..4860440704 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -2860,8 +2860,6 @@ void P_PredictPlayer (player_t *player) } } -extern msecnode_t *P_AddSecnode (sector_t *s, AActor *thing, msecnode_t *nextnode); - void P_UnPredictPlayer () { player_t *player = &players[consoleplayer]; @@ -2922,7 +2920,7 @@ void P_UnPredictPlayer () sector_list = NULL; for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) { - sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list); + sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list, PredictionTouchingSectorsBackup[i]->touching_thinglist); } act->touching_sectorlist = sector_list; // Attach to thing sector_list = NULL; // clear for next time @@ -2934,7 +2932,7 @@ void P_UnPredictPlayer () { if (node == sector_list) sector_list = node->m_tnext; - node = P_DelSecnode(node); + node = P_DelSecnode(node, §or_t::touching_thinglist); } else { diff --git a/src/po_man.cpp b/src/po_man.cpp index f2029026d0..d2faa6690f 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -425,6 +425,11 @@ bool EV_RotatePoly (line_t *line, int polyNum, int speed, int byteAngle, { // poly is already in motion break; } + if (poly->bHasPortals == 2) + { + // cannot do rotations on linked polyportals. + break; + } pe = new DRotatePoly(poly->tag); poly->specialdata = pe; poly->bBlocked = false; @@ -476,6 +481,7 @@ void DMovePoly::Tick () m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); m_Speedv = m_Angle.ToVector(m_Speed); } + poly->UpdateLinks(); } } } @@ -555,6 +561,7 @@ void DMovePolyTo::Tick () m_Speed = m_Dist * (m_Speed < 0 ? -1 : 1); m_Speedv = m_Target - poly->StartSpot.pos; } + poly->UpdateLinks(); } } } @@ -649,6 +656,7 @@ void DPolyDoor::Tick () Destroy (); } } + poly->UpdateLinks(); } else { @@ -735,6 +743,12 @@ bool EV_OpenPolyDoor(line_t *line, int polyNum, double speed, DAngle angle, int { // poly is already moving break; } + if (poly->bHasPortals == 2 && type == PODOOR_SWING) + { + // cannot do rotations on linked polyportals. + break; + } + pd = new DPolyDoor(poly->tag, type); poly->specialdata = pd; if (type == PODOOR_SLIDE) @@ -899,6 +913,36 @@ void FPolyObj::ThrustMobj (AActor *actor, side_t *side) // //========================================================================== +void FPolyObj::UpdateLinks() +{ + if (bHasPortals == 2) + { + TMap processed; + for (unsigned i = 0; i < Linedefs.Size(); i++) + { + if (Linedefs[i]->isLinePortal()) + { + FLinePortal *port = Linedefs[i]->getPortal(); + if (port->mType == PORTT_LINKED) + { + DVector2 old = port->mDisplacement; + port->mDisplacement = port->mDestination->v2->fPos() - port->mOrigin->v1->fPos(); + FLinePortal *port2 = port->mDestination->getPortal(); + if (port2) port2->mDisplacement = -port->mDisplacement; + int destgroup = port->mDestination->frontsector->PortalGroup; + bool *done = processed.CheckKey(destgroup); + if (!done || !*done) + { + processed[destgroup] = true; + DVector2 delta = port->mDisplacement - old; + Displacements.MoveGroup(destgroup, delta); + } + } + } + } + } +} + void FPolyObj::UpdateBBox () { for(unsigned i=0;iisLinePortal()) + { + // Fixme: this still needs to figure out if the polyobject move made the player cross the portal line. + if (P_TryMove(mobj, mobj->Pos(), false)) + { + continue; + } + } // We have a two-sided linedef so we should only check one side // so that the thrust from both sides doesn't cancel each other out. // Best use the one facing the player and ignore the back side. @@ -1496,6 +1549,8 @@ static void SpawnPolyobj (int index, int tag, int type) { continue; } + po->bBlocked = false; + po->bHasPortals = 0; side_t *sd = &sides[i]; @@ -1563,6 +1618,12 @@ static void SpawnPolyobj (int index, int tag, int type) if (l->validcount != validcount) { + FLinePortal *port = l->getPortal(); + if (port && (port->mDefFlags & PORTF_PASSABLE)) + { + int type = port->mType == PORTT_LINKED ? 2 : 1; + if (po->bHasPortals < type) po->bHasPortals = (BYTE)type; + } l->validcount = validcount; po->Linedefs.Push(l); diff --git a/src/po_man.h b/src/po_man.h index 2b9c8afeff..9bc8532552 100644 --- a/src/po_man.h +++ b/src/po_man.h @@ -63,6 +63,7 @@ struct FPolyObj int crush; // should the polyobj attempt to crush mobjs? bool bHurtOnTouch; // should the polyobj hurt anything it touches? bool bBlocked; + BYTE bHasPortals; // 1 for any portal, 2 for a linked portal (2 must block rotations.) int seqType; double Size; // polyobj size (area of POLY_AREAUNIT == size of FRACUNIT) FPolyNode *subsectorlinks; @@ -82,6 +83,7 @@ struct FPolyObj void CreateSubsectorLinks(); void ClearSubsectorLinks(); void CalcCenter(); + void UpdateLinks(); static void ClearAllSubsectorLinks(); private: diff --git a/src/portal.cpp b/src/portal.cpp index 3ce45c6361..1be08fc857 100644 --- a/src/portal.cpp +++ b/src/portal.cpp @@ -384,8 +384,7 @@ void P_UpdatePortal(FLinePortal *port) } else { - port->mDisplacement.X = port->mDestination->v2->fX() - port->mOrigin->v1->fX(); - port->mDisplacement.Y = port->mDestination->v2->fY() - port->mOrigin->v1->fY(); + port->mDisplacement = port->mDestination->v2->fPos() - port->mOrigin->v1->fPos(); } } } diff --git a/src/portal.h b/src/portal.h index 2868521bcb..0aa9a2ef20 100644 --- a/src/portal.h +++ b/src/portal.h @@ -64,6 +64,14 @@ struct FDisplacementTable return data[x + size*y].pos; } + void MoveGroup(int grp, DVector2 delta) + { + for (int i = 1; i < size; i++) + { + data[grp + size*i].pos -= delta; + data[i + grp*size].pos += delta; + } + } }; extern FDisplacementTable Displacements; diff --git a/src/r_defs.h b/src/r_defs.h index eb604ff6f4..c096680d94 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -1102,6 +1102,7 @@ public: // list of mobjs that are at least partially in the sector // thinglist is a subset of touching_thinglist struct msecnode_t *touching_thinglist; // phares 3/14/98 + struct msecnode_t *render_thinglist; // for cross-portal rendering. double gravity; // [RH] Sector gravity (1.0 is normal) FNameNoInit damagetype; // [RH] Means-of-death for applied damage diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 0977505fdc..929d4073d7 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -949,6 +949,7 @@ void R_SetupFrame (AActor *actor) { iview->otic = nowtic; iview->Old = iview->New; + r_NoInterpolate = true; } } else diff --git a/src/version.h b/src/version.h index 5c0d46e9ef..c5161643ae 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4537 +#define SAVEVER 4538 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)