@@ -207,6 +207,15 @@ private void ReadModels(TRLevelReader reader)
207207 }
208208
209209 List < PlaceholderModel > animatedModels = _placeholderModels . FindAll ( m => m . Animation != TRConsts . NoAnimation ) ;
210+ if ( _dataType == TRModelDataType . PDP && _version == TRGameVersion . TR5 )
211+ {
212+ // TR5 PDP has entries for what seem like null models, with no animations, frames or meshes. These are not setup in the conventional way
213+ // per OG, with jumps in anim idx, so we address this here to avoid skewing other animation counts below.
214+ List < PlaceholderModel > invalidAnimModels = animatedModels . FindAll ( m => m . ID > ( uint ) TR5Type . Lara && m . Animation == 0 ) ;
215+ invalidAnimModels . ForEach ( m => m . Animation = TRConsts . NoAnimation ) ;
216+ animatedModels . RemoveAll ( invalidAnimModels . Contains ) ;
217+ }
218+
210219 for ( int i = 0 ; i < animatedModels . Count ; i ++ )
211220 {
212221 PlaceholderModel model = animatedModels [ i ] ;
@@ -511,6 +520,14 @@ private TRAnimFrame BuildFrame(ref int frameIndex, int numRotations)
511520 : GetSingleRotation ( rot0 ) ;
512521 }
513522
523+ if ( _dataType == TRModelDataType . PDP && _version > TRGameVersion . TR3 )
524+ {
525+ // Some TR4+ rots are marked as all despite only having one value set, so when we write
526+ // them back, we restore this mode to keep tests happy. If changing values otherwise, care
527+ // should be taken to set the mode to Auto.
528+ rot . Mode = rotMode ;
529+ }
530+
514531 switch ( rotMode )
515532 {
516533 case TRAngleMode . X :
@@ -548,16 +565,42 @@ private void TestTR5Changes(IEnumerable<TRModel> models)
548565 }
549566 }
550567
551- private void DeconstructModel ( T type , TRModel model )
568+ private PlaceholderModel CreateDeconstructedModel ( T type , TRModel model )
552569 {
553- PlaceholderModel placeholderModel = new ( )
570+ PlaceholderModel placeholder = new ( )
554571 {
555572 ID = ( uint ) ( object ) type ,
556- Animation = model . Animations . Count == 0 ? TRConsts . NoAnimation : ( ushort ) _placeholderAnimations . Count ,
557- FrameOffset = ( _dataType == TRModelDataType . PDP || _observer == null )
558- && model . Animations . Count == 0 ? 0 : ( uint ) _frames . Count * sizeof ( short ) ,
559573 NumMeshes = ( ushort ) model . Meshes . Count ,
560574 } ;
575+
576+ if ( model . Animations . Count == 0 )
577+ {
578+ if ( _dataType == TRModelDataType . PDP && _version == TRGameVersion . TR5 && model . Meshes . Count == 0 )
579+ {
580+ placeholder . Animation = 0 ;
581+ placeholder . IsNullTR5Model = true ;
582+ }
583+ else
584+ {
585+ placeholder . Animation = TRConsts . NoAnimation ;
586+ }
587+
588+ placeholder . FrameOffset = _dataType == TRModelDataType . PDP || _observer == null
589+ ? 0
590+ : ( uint ) _frames . Count * sizeof ( short ) ;
591+ }
592+ else
593+ {
594+ placeholder . Animation = ( ushort ) _placeholderAnimations . Count ;
595+ placeholder . FrameOffset = ( uint ) _frames . Count * sizeof ( short ) ;
596+ }
597+
598+ return placeholder ;
599+ }
600+
601+ private void DeconstructModel ( T type , TRModel model )
602+ {
603+ PlaceholderModel placeholderModel = CreateDeconstructedModel ( type , model ) ;
561604 _placeholderModels . Add ( placeholderModel ) ;
562605
563606 _trees . AddRange ( model . MeshTrees ) ;
@@ -880,8 +923,8 @@ private void WriteModels(TRLevelWriter writer, TRDictionary<T, TRModel> models)
880923
881924 writer . Write ( placeholderModel . ID ) ;
882925 writer . Write ( placeholderModel . NumMeshes ) ;
883- writer . Write ( startingMesh ) ;
884- writer . Write ( treePointer ) ;
926+ writer . Write ( placeholderModel . IsNullTR5Model ? ( ushort ) 0 : startingMesh ) ;
927+ writer . Write ( placeholderModel . IsNullTR5Model ? 0 : treePointer ) ;
885928 writer . Write ( placeholderModel . FrameOffset ) ;
886929 writer . Write ( placeholderModel . Animation ) ;
887930
@@ -897,6 +940,11 @@ private void WriteModels(TRLevelWriter writer, TRDictionary<T, TRModel> models)
897940
898941 private TRAngleMode GetMode ( TRAnimFrameRotation rot )
899942 {
943+ if ( rot . Mode != TRAngleMode . Auto )
944+ {
945+ return rot . Mode ;
946+ }
947+
900948 if ( rot . X == 0 && rot . Y == 0 )
901949 {
902950 // OG TR2+ levels (and TRR levels) use Z here, PDP uses X. Makes no difference
@@ -961,6 +1009,7 @@ class PlaceholderModel
9611009 public uint FrameOffset { get ; set ; }
9621010 public ushort Animation { get ; set ; }
9631011 public int AnimCount { get ; set ; }
1012+ public bool IsNullTR5Model { get ; set ; }
9641013 }
9651014
9661015 class PlaceholderAnimation
0 commit comments