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);
    }
示例#2
0
    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);
    }