internal static ActionSequence LoadSequence(SavedD20ActionSequence savedSequence) { var sequence = new ActionSequence { d20ActArray = savedSequence.Actions.Select(LoadAction).ToList(), IsPerforming = savedSequence.IsPerforming, IsInterrupted = savedSequence.IsInterrupted, d20aCurIdx = savedSequence.CurrentActionIndex, tbStatus = LoadTurnStatus(savedSequence.TurnStatus), performerLoc = savedSequence.PerformerLocation, ignoreLos = savedSequence.IgnoreLineOfSight, spellPktBody = ActiveSpellLoader.LoadActiveSpell(savedSequence.Spell) }; if (!savedSequence.Performer.IsNull) { sequence.performer = GameSystems.Object.GetObject(savedSequence.Performer); if (sequence.performer == null) { throw new CorruptSaveException( $"Failed to restore action sequence performer {savedSequence.Performer}"); } } return(sequence); }
internal static SavedD20ActionSequence[] SaveSequences(List <ActionSequence> sequences) { var result = new SavedD20ActionSequence[sequences.Count]; for (var i = 0; i < result.Length; i++) { var sequence = sequences[i]; result[i] = new SavedD20ActionSequence { Actions = sequence.d20ActArray.Select(SaveAction).ToArray(), IsPerforming = sequence.IsPerforming, IsInterrupted = sequence.IsInterrupted, CurrentActionIndex = sequence.d20aCurIdx, TurnStatus = SaveTurnStatus(sequence.tbStatus), PerformerLocation = sequence.performerLoc, IgnoreLineOfSight = sequence.ignoreLos, Spell = ActiveSpellSaver.SaveActiveSpell(sequence.spellPktBody, false), Performer = sequence.performer?.id ?? ObjectId.CreateNull(), PreviousSequenceIndex = sequence.prevSeq != null?sequences.IndexOf(sequence.prevSeq) : -1, InterruptedSequenceIndex = sequence.interruptSeq != null?sequences.IndexOf(sequence.interruptSeq) : -1, }; } return(result); }
public static SavedD20ActionSequence Load(BinaryReader reader) { var result = new SavedD20ActionSequence(); // NOTE: It's stupid, but ToEE completely ignores the action structs that are embedded into the // action sequence struct, and will actually duplicate the actions after the action sequence array. reader.BaseStream.Seek(32 * 0x58, SeekOrigin.Current); var actionCount = reader.ReadInt32(); result.Actions = new SavedD20Action[actionCount]; result.CurrentActionIndex = reader.ReadInt32(); reader.ReadInt32(); // Previous Sequence (pointer, transient data) reader.ReadInt32(); // Interrupt Sequence (pointer, transient data) var flags = reader.ReadInt32(); result.IsPerforming = ((flags & 1) != 0); result.IsInterrupted = ((flags & 2) != 0); if ((flags & ~3) != 0) { throw new CorruptSaveException($"Invalid action sequence flags: 0x{flags:X}"); } result.TurnStatus = SavedD20TurnBasedStatus.Load(reader); reader.ReadInt64(); // Skip transient performer object handle result.PerformerLocation = reader.ReadLocationAndOffsets(); reader.ReadInt64(); // Skip transient target object handle // Skip the spell packet body, because ToEE was lazy and just saved the structure directly, // the packet only contains invalid object handles (since they are transient) and not the object ids // that are required to restore the handles. Instead of fixing this by saving information after the // sequences, ToEE saves the spell packets in action_sequencespellpackets.bin instead. reader.ReadBytes(0xAE8); reader.ReadInt32(); // Transient action pointer result.IgnoreLineOfSight = reader.ReadInt32() != 0; return(result); }