diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 1ed89f783d..d8fdf13d20 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -3529,7 +3529,8 @@ enum APROP_ReactionTime = 37, APROP_MeleeRange = 38, APROP_ViewHeight = 39, - APROP_AttackZOffset = 40 + APROP_AttackZOffset = 40, + APROP_StencilColor = 41 }; // These are needed for ACS's APROP_RenderStyle @@ -3755,6 +3756,10 @@ void DLevelScript::DoSetActorProperty (AActor *actor, int property, int value) static_cast(actor)->AttackZOffset = value; break; + case APROP_StencilColor: + actor->SetShade(value); + break; + default: // do nothing. break; @@ -3852,6 +3857,7 @@ int DLevelScript::GetActorProperty (int tid, int property, const SDWORD *stack, case APROP_ActiveSound: return GlobalACSStrings.AddString(actor->ActiveSound, stack, stackdepth); case APROP_Species: return GlobalACSStrings.AddString(actor->GetSpecies(), stack, stackdepth); case APROP_NameTag: return GlobalACSStrings.AddString(actor->GetTag(), stack, stackdepth); + case APROP_StencilColor:return actor->fillcolor; default: return 0; } @@ -3898,6 +3904,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value) case APROP_MeleeRange: case APROP_ViewHeight: case APROP_AttackZOffset: + case APROP_StencilColor: return (GetActorProperty(tid, property, NULL, 0) == value); // Boolean values need to compare to a binary version of value @@ -7874,14 +7881,22 @@ scriptwait: case PCD_GETSECTORCEILINGZ: // Arguments are (tag, x, y). If you don't use slopes, then (x, y) don't // really matter and can be left as (0, 0) if you like. + // [Dusk] If tag = 0, then this returns the z height at whatever sector + // is in x, y. { - int secnum = P_FindSectorFromTag (STACK(3), -1); + int tag = STACK(3); + int secnum; + fixed_t x = STACK(2) << FRACBITS; + fixed_t y = STACK(1) << FRACBITS; fixed_t z = 0; + if (tag != 0) + secnum = P_FindSectorFromTag (tag, -1); + else + secnum = P_PointInSector (x, y) - sectors; + if (secnum >= 0) { - fixed_t x = STACK(2) << FRACBITS; - fixed_t y = STACK(1) << FRACBITS; if (pcd == PCD_GETSECTORFLOORZ) { z = sectors[secnum].floorplane.ZatPoint (x, y); diff --git a/src/p_user.cpp b/src/p_user.cpp index 90d0dd6cfc..ea7b315d80 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -65,6 +65,8 @@ CVAR (Bool, cl_noprediction, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) static player_t PredictionPlayerBackup; static BYTE PredictionActorBackup[sizeof(AActor)]; static TArray PredictionTouchingSectorsBackup; +static TArray PredictionSectorListBackup; +static TArray PredictionSector_sprev_Backup; // [GRB] Custom player classes TArray PlayerClasses; @@ -2661,15 +2663,41 @@ void P_PredictPlayer (player_t *player) player->cheats |= CF_PREDICTING; // The ordering of the touching_sectorlist needs to remain unchanged + // Also store a copy of all previous sector_thinglist nodes msecnode_t *mnode = act->touching_sectorlist; + msecnode_t *snode; + PredictionSector_sprev_Backup.Clear(); PredictionTouchingSectorsBackup.Clear (); while (mnode != NULL) { PredictionTouchingSectorsBackup.Push (mnode->m_sector); + + for (snode = mnode->m_sector->touching_thinglist; snode; snode = snode->m_snext) + { + if (snode->m_thing == act) + { + PredictionSector_sprev_Backup.Push(snode->m_sprev); + break; + } + } + mnode = mnode->m_tnext; } + // Keep an ordered list off all actors in the linked sector. + PredictionSectorListBackup.Clear(); + if (!(act->flags & MF_NOSECTOR)) + { + AActor *link = act->Sector->thinglist; + + while (link != NULL) + { + PredictionSectorListBackup.Push(link); + link = link->snext; + } + } + // Blockmap ordering also needs to stay the same, so unlink the block nodes // without releasing them. (They will be used again in P_UnpredictPlayer). FBlockNode *block = act->BlockNode; @@ -2701,6 +2729,7 @@ void P_UnPredictPlayer () if (player->cheats & CF_PREDICTING) { + unsigned int i; AActor *act = player->mo; AActor *savedcamera = player->camera; @@ -2710,23 +2739,80 @@ void P_UnPredictPlayer () // could cause it to change during prediction. player->camera = savedcamera; - act->UnlinkFromWorld (); - memcpy (&act->x, PredictionActorBackup, sizeof(AActor)-((BYTE *)&act->x-(BYTE *)act)); + act->UnlinkFromWorld(); + memcpy(&act->x, PredictionActorBackup, sizeof(AActor)-((BYTE *)&act->x - (BYTE *)act)); // Make the sector_list match the player's touching_sectorlist before it got predicted. - P_DelSeclist (sector_list); + P_DelSeclist(sector_list); sector_list = NULL; - for (unsigned int i = PredictionTouchingSectorsBackup.Size (); i-- > 0; ) + for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) { - sector_list = P_AddSecnode (PredictionTouchingSectorsBackup[i], act, sector_list); + sector_list = P_AddSecnode(PredictionTouchingSectorsBackup[i], act, sector_list); } // The blockmap ordering needs to remain unchanged, too. Right now, act has the right // pointers, so temporarily set its MF_NOBLOCKMAP flag so that LinkToWorld() does not // mess with them. - act->flags |= MF_NOBLOCKMAP; - act->LinkToWorld (); - act->flags &= ~MF_NOBLOCKMAP; + { + DWORD keepflags = act->flags; + act->flags |= MF_NOBLOCKMAP; + act->LinkToWorld(); + act->flags = keepflags; + } + + // Restore sector links. + if (!(act->flags & MF_NOSECTOR)) + { + sector_t *sec = act->Sector; + AActor *me, *next; + AActor **link;// , **prev; + + // The thinglist is just a pointer chain. We are restoring the exact same things, so we can NULL the head safely + sec->thinglist = NULL; + + for (i = PredictionSectorListBackup.Size(); i-- > 0;) + { + me = PredictionSectorListBackup[i]; + link = &sec->thinglist; + next = *link; + if ((me->snext = next)) + next->sprev = &me->snext; + me->sprev = link; + *link = me; + } + + msecnode_t *snode; + + // Restore sector thinglist order + for (i = PredictionTouchingSectorsBackup.Size(); i-- > 0;) + { + // If we were already the head node, then nothing needs to change + if (PredictionSector_sprev_Backup[i] == NULL) + continue; + + for (snode = PredictionTouchingSectorsBackup[i]->touching_thinglist; snode; snode = snode->m_snext) + { + if (snode->m_thing == act) + { + if (snode->m_sprev) + snode->m_sprev->m_snext = snode->m_snext; + else + snode->m_sector->touching_thinglist = snode->m_snext; + if (snode->m_snext) + snode->m_snext->m_sprev = snode->m_sprev; + + snode->m_sprev = PredictionSector_sprev_Backup[i]; + + // At the moment, we don't exist in the list anymore, but we do know what our previous node is, so we set its current m_snext->m_sprev to us. + if (snode->m_sprev->m_snext) + snode->m_sprev->m_snext->m_sprev = snode; + snode->m_snext = snode->m_sprev->m_snext; + snode->m_sprev->m_snext = snode; + break; + } + } + } + } // Now fix the pointers in the blocknode chain FBlockNode *block = act->BlockNode;