예제 #1
0
 private void InitDefault()
 {
     DirectionId  = 0;
     ScriptEvents = new string[10];
     for (int i = 0; i < 10; i++)
     {
         ScriptEvents[i] = "";
     }
     DetectEventTimeout       = 1;
     ActionRoamPathFlag       = 0xFF;
     StatusFlags              = (NoxEnums.MonsterStatus) 0;
     HealthMultiplier         = 1F;
     RetreatRatio             = 0.05F;
     ResumeRatio              = 0.5F;
     SightRange               = 300F;
     Aggressiveness           = 0F;
     DefaultAction            = 0;
     EscortObjName            = "";
     KnownSpells              = new List <MonsterXfer.SpellEntry>();
     ReactionCastingDelayMin  = 15;
     ReactionCastingDelayMax  = 30;
     BuffCastingDelayMin      = 120;
     BuffCastingDelayMax      = 180;
     DebuffCastingDelayMin    = 45;
     DebuffCastingDelayMax    = 60;
     OffensiveCastingDelayMin = 30;
     OffensiveCastingDelayMax = 60;
     BlinkCastingDelayMin     = 150;
     BlinkCastingDelayMax     = 300;
     LockPathDistance         = 30F;
     SpellPowerLevel          = 3;
     AimSkillLevel            = 0.5F;
     Immortal                = false;
     TrapSpell1              = "SPELL_INVALID";
     TrapSpell2              = "SPELL_INVALID";
     TrapSpell3              = "SPELL_INVALID";
     ShopkeeperInfo          = new MonsterXfer.ShopkeeperInfoStruct();
     MagicNumber             = 0xDEADFACE;
     AddedSubclass           = 0;
     Health                  = 1;
     SetDefaultResumeRatio   = true;
     SetDefaultRetreatRatio  = true;
     SetDefaultMonsterStatus = true;
     LearnDefaultSpells      = true;
     MaidenBodyColors        = new Color[6];
     MaidenVoiceSet          = "Maiden";
     BuffList                = new MonsterXfer.BuffEntry[0];
     PoisonLevel             = 0;
 }
예제 #2
0
        /// <summary>
        /// Возвращает стандартный Xfer для указанного монстра
        /// </summary>
        public MonsterXfer(string monsterID)
        {
            ThingDb.Thing tt = ThingDb.thingdb.Things[monsterID];
            bool isShopkeeper = tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.SHOPKEEPER];
            bool isFemaleNPC = tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.FEMALE_NPC];
            bool isWoundNPC = tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.WOUNDED_NPC];
            bool isFriendly = isShopkeeper || isFemaleNPC || isWoundNPC || (tt.Name == "AirshipCaptain");

            Direction = DirectionEncoded.South;
            ScriptEvents = new string[10];
            for (int i = 0; i < 10; i++) ScriptEvents[i] = "";
            DetectEventTimeout = 1;
            ActionRoamPathFlag = 0xFF;
            StatusFlags = (NoxEnums.MonsterStatus) 0;
            HealthMultiplier = 1F;
            RetreatRatio = 0.05F;
            ResumeRatio = 0.5F;
            SightRange = 300F;
            Aggressiveness = 0F;
            if (!isFriendly) Aggressiveness = 0.83F;
            DefaultAction = 0;
            EscortObjName = "";
            KnownSpells = new List<MonsterXfer.SpellEntry>();
            ReactionCastingDelayMin = 15;
            ReactionCastingDelayMax = 30;
            BuffCastingDelayMin = 120;
            BuffCastingDelayMax = 180;
            DebuffCastingDelayMin = 45;
            DebuffCastingDelayMax = 60;
            OffensiveCastingDelayMin = 30;
            OffensiveCastingDelayMax = 60;
            BlinkCastingDelayMin = 150;
            BlinkCastingDelayMax = 300;
            LockPathDistance = 30F;
            SpellPowerLevel = 3;
            AimSkillLevel = 0.5F;
            Immortal = false;
            TrapSpell1 = "SPELL_INVALID";
            TrapSpell2 = "SPELL_INVALID";
            TrapSpell3 = "SPELL_INVALID";
            ShopkeeperInfo = new MonsterXfer.ShopkeeperInfoStruct();
            if (isShopkeeper)
            {
                ShopkeeperInfo.ShopkeeperGreetingText = "";
                ShopkeeperInfo.ShopItems = new MonsterXfer.ShopItemInfo[0];
            }
            MagicNumber = 0xDEADFACE;
            AddedSubclass = 0;
            Health = 1;
            SetDefaultResumeRatio = true;
            SetDefaultRetreatRatio = true;
            SetDefaultMonsterStatus = true;
            LearnDefaultSpells = true;
            MaidenBodyColors = new Color[6];
            MaidenVoiceSet = "Maiden";
            if (isFemaleNPC)
            {
                for (int i = 0; i < 6; i++) MaidenBodyColors[i] = Color.FromArgb(0xD2, 0xAE, 0x79);
            }
            WoundedNPCVoiceSet = monsterID;
            BuffList = new MonsterXfer.BuffEntry[0];
            PoisonLevel = 0;
            if (MonsterDb.MonsterDict.ContainsKey(monsterID))
            {
                MonsterDb.MonsterInfo info = MonsterDb.MonsterDict[monsterID];
                StatusFlags = GetFlagsFromString(info.Status);
                Health = (short) info.Health;
                RetreatRatio = info.RetreatRatio;
                ResumeRatio = info.ResumeRatio;
            }
        }
예제 #3
0
        public static MonsterXfer FromStream(Stream mstream, ThingDb.Thing tt, short ParsingRule)
        {
            MonsterXfer result = new MonsterXfer();

            NoxBinaryReader br = new NoxBinaryReader(mstream);
            result.Direction = (DirectionEncoded) br.ReadUInt64();
            result.ScriptEvents = new string[10];
            // Читаем имена обработчиков скриптовых событий
            for (int i = 0; i < 10; i++)
            {
                if (i == 2)
                    result.DetectEventTimeout = br.ReadUInt16();

                result.ScriptEvents[i] = br.ReadScriptEventString();
            }
            // Пропуск (0)
            if (ParsingRule >= 11)
                br.ReadInt32();
            if (ParsingRule >= 31)
            {
                result.ActionRoamPathFlag = br.ReadByte();
                if (ParsingRule < 51)
                    result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt16();
                else
                    result.StatusFlags = (NoxEnums.MonsterStatus) br.ReadUInt32();

                result.HealthMultiplier = br.ReadSingle();
                result.RetreatRatio = br.ReadSingle();
                result.ResumeRatio = br.ReadSingle();
                result.SightRange = br.ReadSingle();
                if (ParsingRule < 33)
                    br.BaseStream.Seek(2, SeekOrigin.Current);
                result.Aggressiveness = br.ReadSingle();
                if (ParsingRule < 34)
                    result.DefaultAction = br.ReadInt32();
                result.EscortObjName = br.ReadString();
                if (ParsingRule >= 34)
                {
                    int spells = br.ReadInt32();
                    result.KnownSpells = new List<SpellEntry>();
                    string spellName = null;
                    uint spellFlags = 0;

                    for (int i = 0; i < spells; i++)
                    {
                        spellName = br.ReadString();
                        spellFlags = br.ReadUInt32();
                        if (ThingDb.thingdb.Spells.Keys.Contains(spellName))
                            result.KnownSpells.Add(new SpellEntry(spellName, spellFlags));
                    }
                }
                else
                    br.BaseStream.Seek(0x224, SeekOrigin.Current);
                // Задержки между заклинаниями
                if (ParsingRule < 46)
                {
                    result.ReactionCastingDelayMin = (ushort) br.ReadByte();
                    result.ReactionCastingDelayMax = (ushort) br.ReadByte();
                    if (ParsingRule <= 32) br.ReadInt32();
                    result.BuffCastingDelayMin = (ushort) br.ReadByte();
                    result.BuffCastingDelayMax = (ushort) br.ReadByte();
                    if (ParsingRule <= 32) br.ReadInt32();
                    result.DebuffCastingDelayMin = (ushort) br.ReadByte();
                    result.DebuffCastingDelayMax = (ushort) br.ReadByte();
                    if (ParsingRule <= 32) br.ReadInt32();
                    result.OffensiveCastingDelayMin = (ushort) br.ReadByte();
                    result.OffensiveCastingDelayMax = (ushort) br.ReadByte();
                    if (ParsingRule <= 32) br.ReadInt32();
                    result.BlinkCastingDelayMin = (ushort) br.ReadByte();
                    result.BlinkCastingDelayMax = (ushort) br.ReadByte();
                    if (ParsingRule <= 32) br.ReadInt32();
                }
                else
                {
                    result.ReactionCastingDelayMin = br.ReadUInt16();
                    result.ReactionCastingDelayMax = br.ReadUInt16();
                    result.BuffCastingDelayMin = br.ReadUInt16();
                    result.BuffCastingDelayMax = br.ReadUInt16();
                    result.DebuffCastingDelayMin = br.ReadUInt16();
                    result.DebuffCastingDelayMax = br.ReadUInt16();
                    result.OffensiveCastingDelayMin = br.ReadUInt16();
                    result.OffensiveCastingDelayMax = br.ReadUInt16();
                    result.BlinkCastingDelayMin = br.ReadUInt16();
                    result.BlinkCastingDelayMax = br.ReadUInt16();
                }
                if (ParsingRule > 32)
                    result.LockPathDistance = br.ReadSingle();

                if (ParsingRule >= 33)
                {
                    result.SpellPowerLevel = br.ReadInt32();
                    result.AimSkillLevel = br.ReadSingle();
                    if (ParsingRule < 42)
                    {
                        if (br.ReadInt16() == 0)
                            result.Immortal = true;
                    }
                    if (ParsingRule < 53)
                    {
                        int spellIndex = br.ReadInt32();
                        result.TrapSpell1 = ThingDb.thingdb.Spells.Values[spellIndex].Name;
                        spellIndex = br.ReadInt32();
                        result.TrapSpell2 = ThingDb.thingdb.Spells.Values[spellIndex].Name;
                        spellIndex = br.ReadInt32();
                        result.TrapSpell3 = ThingDb.thingdb.Spells.Values[spellIndex].Name;
                    }
                    else
                    {
                        result.TrapSpell1 = br.ReadString();
                        result.TrapSpell2 = br.ReadString();
                        result.TrapSpell3 = br.ReadString();
                    }
                }
                if (ParsingRule >= 34)
                {
                    string action = br.ReadString();
                    result.DefaultAction = Array.IndexOf(NoxEnums.AIActionStrings, action);
                }
                if (ParsingRule >= 41)
                {
                    // здесь придётся читать просто огромное кол-во инфы
                    // однако она используется очень редко, обычно entryType = 4; forced = 0
                    short entryType = br.ReadInt16();
                    if (entryType <= 4)
                    {
                        byte forced = 1;
                        if (entryType >= 2)
                            forced = br.ReadByte();
                        if (forced == 1 || entryType < 2)
                        {
                            return result;
                            // TODO для ПОЛНОЙ совместимости, придётся
                        }
                    }
                }
                if (ParsingRule >= 42)
                {
                    result.Immortal = br.ReadBoolean();
                }
                if (ParsingRule >= 43 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.SHOPKEEPER])
                {
                    // Информация о содержании магазина
                    ShopkeeperInfoStruct si = new ShopkeeperInfoStruct();
                    if (ParsingRule >= 50)
                        si.BuyValueMultiplier = br.ReadSingle();
                    if (ParsingRule >= 61)
                        si.SellValueMultiplier = br.ReadSingle();
                    if (ParsingRule >= 48)
                        si.ShopkeeperGreetingText = br.ReadString();
                    byte items = br.ReadByte();
                    si.ShopItems = new ShopItemInfo[items];
                    for (int i = 0; i < items; i++)
                    {
                        ShopItemInfo item = new ShopItemInfo();
                        if (ParsingRule < 50) br.ReadInt32();
                        item.Count = br.ReadByte();
                        item.Name = br.ReadString();
                        if (ParsingRule >= 47)
                        {
                            item.SpellID = br.ReadString();
                            item.Ench1 = br.ReadString();
                            item.Ench2 = br.ReadString();
                            item.Ench3 = br.ReadString();
                            item.Ench4 = br.ReadString();
                        }
                        si.ShopItems[i] = item;
                    }
                    result.ShopkeeperInfo = si;
                }
                if (ParsingRule >= 44)
                    result.MagicNumber = br.ReadUInt32();
                if (ParsingRule >= 45)
                    result.AddedSubclass = br.ReadUInt32();
                if (ParsingRule >= 49)
                    result.Health = br.ReadInt16();
                if (ParsingRule >= 51)
                {
                    result.SetDefaultResumeRatio = br.ReadBoolean();
                    result.SetDefaultRetreatRatio = br.ReadBoolean();
                    result.SetDefaultMonsterStatus = br.ReadBoolean();
                    result.LearnDefaultSpells = br.ReadBoolean();
                }
                if (ParsingRule >= 54 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.FEMALE_NPC])
                {
                    result.MaidenBodyColors = new Color[6];
                    byte R, G, B;
                    for (int i = 0; i < 6; i++)
                    {
                        R = br.ReadByte();
                        G = br.ReadByte();
                        B = br.ReadByte();
                        result.MaidenBodyColors[i] = Color.FromArgb(R, G, B);
                    }
                    if (ParsingRule >= 55)
                        result.MaidenVoiceSet = br.ReadString();
                }
                if (ParsingRule >= 62)
                {
                    short entryType = br.ReadInt16();
                    if (entryType > 2 || entryType <= 0) return result;

                    byte count = br.ReadByte();
                    result.BuffList = new BuffEntry[count];
                    while (count > 0)
                    {
                        BuffEntry be = new BuffEntry();
                        be.Name = br.ReadString();
                        be.Power = br.ReadByte();
                        be.Duration = br.ReadInt32();
                        if (be.Name == ENCHANT_SHIELD && entryType >= 2)
                            be.ShieldHealth = br.ReadInt32();

                        result.BuffList[count] = be;
                        count--;
                    }
                    Array.Reverse(result.BuffList);
                }
                if (ParsingRule >= 63 && tt.Subclass[(int) ThingDb.Thing.SubclassBitIndex.WOUNDED_NPC])
                    result.WoundedNPCVoiceSet = br.ReadString();
                if (ParsingRule >= 64)
                    result.PoisonLevel = br.ReadByte();
            }
            return result;
        }
예제 #4
0
        public override bool FromStream(Stream mstream, short ParsingRule, ThingDb.Thing thing)
        {
            NoxBinaryReader br = new NoxBinaryReader(mstream);

            DirectionId  = (byte)Array.IndexOf(NOX_DIRECT_LONG, br.ReadUInt64());
            ScriptEvents = new string[10];
            // Read script event handler names
            for (int i = 0; i < 10; i++)
            {
                if (i == 2)
                {
                    DetectEventTimeout = br.ReadUInt16();
                }

                ScriptEvents[i] = br.ReadScriptEventString();
            }
            // Skip (0)
            if (ParsingRule >= 11)
            {
                br.ReadInt32();
            }
            if (ParsingRule >= 31)
            {
                ActionRoamPathFlag = br.ReadByte();
                if (ParsingRule < 51)
                {
                    StatusFlags = (NoxEnums.MonsterStatus)br.ReadUInt16();
                }
                else
                {
                    StatusFlags = (NoxEnums.MonsterStatus)br.ReadUInt32();
                }

                HealthMultiplier = br.ReadSingle();
                RetreatRatio     = br.ReadSingle();
                ResumeRatio      = br.ReadSingle();
                SightRange       = br.ReadSingle();
                if (ParsingRule < 33)
                {
                    br.BaseStream.Seek(2, SeekOrigin.Current);
                }
                Aggressiveness = br.ReadSingle();
                if (ParsingRule < 34)
                {
                    DefaultAction = br.ReadInt32();
                }
                EscortObjName = br.ReadString();
                if (ParsingRule >= 34)
                {
                    int spells = br.ReadInt32();
                    KnownSpells = new List <SpellEntry>();
                    string spellName  = null;
                    uint   spellFlags = 0;

                    for (int i = 0; i < spells; i++)
                    {
                        spellName  = br.ReadString();
                        spellFlags = br.ReadUInt32();
                        if (ThingDb.Spells.Keys.Contains(spellName))
                        {
                            KnownSpells.Add(new SpellEntry(spellName, spellFlags));
                        }
                    }
                }
                else
                {
                    br.BaseStream.Seek(0x224, SeekOrigin.Current);
                }
                // Spell usage delay values
                if (ParsingRule < 46)
                {
                    ReactionCastingDelayMin = (ushort)br.ReadByte();
                    ReactionCastingDelayMax = (ushort)br.ReadByte();
                    if (ParsingRule <= 32)
                    {
                        br.ReadInt32();
                    }
                    BuffCastingDelayMin = (ushort)br.ReadByte();
                    BuffCastingDelayMax = (ushort)br.ReadByte();
                    if (ParsingRule <= 32)
                    {
                        br.ReadInt32();
                    }
                    DebuffCastingDelayMin = (ushort)br.ReadByte();
                    DebuffCastingDelayMax = (ushort)br.ReadByte();
                    if (ParsingRule <= 32)
                    {
                        br.ReadInt32();
                    }
                    OffensiveCastingDelayMin = (ushort)br.ReadByte();
                    OffensiveCastingDelayMax = (ushort)br.ReadByte();
                    if (ParsingRule <= 32)
                    {
                        br.ReadInt32();
                    }
                    BlinkCastingDelayMin = (ushort)br.ReadByte();
                    BlinkCastingDelayMax = (ushort)br.ReadByte();
                    if (ParsingRule <= 32)
                    {
                        br.ReadInt32();
                    }
                }
                else
                {
                    ReactionCastingDelayMin  = br.ReadUInt16();
                    ReactionCastingDelayMax  = br.ReadUInt16();
                    BuffCastingDelayMin      = br.ReadUInt16();
                    BuffCastingDelayMax      = br.ReadUInt16();
                    DebuffCastingDelayMin    = br.ReadUInt16();
                    DebuffCastingDelayMax    = br.ReadUInt16();
                    OffensiveCastingDelayMin = br.ReadUInt16();
                    OffensiveCastingDelayMax = br.ReadUInt16();
                    BlinkCastingDelayMin     = br.ReadUInt16();
                    BlinkCastingDelayMax     = br.ReadUInt16();
                }
                if (ParsingRule > 32)
                {
                    LockPathDistance = br.ReadSingle();
                }

                if (ParsingRule >= 33)
                {
                    SpellPowerLevel = br.ReadInt32();
                    AimSkillLevel   = br.ReadSingle();
                    if (ParsingRule < 42)
                    {
                        if (br.ReadInt16() == 0)
                        {
                            Immortal = true;
                        }
                    }
                    if (ParsingRule < 53)
                    {
                        int spellIndex = br.ReadInt32();
                        TrapSpell1 = ThingDb.Spells.Values[spellIndex].Name;
                        spellIndex = br.ReadInt32();
                        TrapSpell2 = ThingDb.Spells.Values[spellIndex].Name;
                        spellIndex = br.ReadInt32();
                        TrapSpell3 = ThingDb.Spells.Values[spellIndex].Name;
                    }
                    else
                    {
                        TrapSpell1 = br.ReadString();
                        TrapSpell2 = br.ReadString();
                        TrapSpell3 = br.ReadString();
                    }
                }
                if (ParsingRule >= 34)
                {
                    string action = br.ReadString();
                    DefaultAction = Array.IndexOf(NoxEnums.AIActionStrings, action);
                }
                if (ParsingRule >= 41)
                {
                    // large, complex structure dealing with AI-specific data
                    // it is only used on saved games, normally entryType = 4; forced = 0
                    short entryType = br.ReadInt16();
                    if (entryType <= 4)
                    {
                        byte forced = 1;
                        if (entryType >= 2)
                        {
                            forced = br.ReadByte();
                        }
                        if (forced == 1 || entryType < 2)
                        {
                            return(false);
                            // TODO implement for full compatibility
                        }
                    }
                }
                if (ParsingRule >= 42)
                {
                    Immortal = br.ReadBoolean();
                }
                if (ParsingRule >= 43 && thing.Subclass[(int)ThingDb.Thing.SubclassBitIndex.SHOPKEEPER])
                {
                    // Shop contents
                    ShopkeeperInfoStruct si = new ShopkeeperInfoStruct();
                    if (ParsingRule >= 50)
                    {
                        si.BuyValueMultiplier = br.ReadSingle();
                    }
                    if (ParsingRule >= 61)
                    {
                        si.SellValueMultiplier = br.ReadSingle();
                    }
                    if (ParsingRule >= 48)
                    {
                        si.ShopkeeperGreetingText = br.ReadString();
                    }
                    byte items = br.ReadByte();
                    si.ShopItems = new ShopItemInfo[items];
                    for (int i = 0; i < items; i++)
                    {
                        ShopItemInfo item = new ShopItemInfo();
                        if (ParsingRule < 50)
                        {
                            br.ReadInt32();
                        }
                        item.Count = br.ReadByte();
                        item.Name  = br.ReadString();
                        if (ParsingRule >= 47)
                        {
                            item.SpellID = br.ReadString();
                            item.Ench1   = br.ReadString();
                            item.Ench2   = br.ReadString();
                            item.Ench3   = br.ReadString();
                            item.Ench4   = br.ReadString();
                        }
                        si.ShopItems[i] = item;
                    }
                    ShopkeeperInfo = si;
                }
                if (ParsingRule >= 44)
                {
                    MagicNumber = br.ReadUInt32();
                }
                if (ParsingRule >= 45)
                {
                    AddedSubclass = br.ReadUInt32();
                }
                if (ParsingRule >= 49)
                {
                    Health = br.ReadInt16();
                }
                if (ParsingRule >= 51)
                {
                    SetDefaultResumeRatio   = br.ReadBoolean();
                    SetDefaultRetreatRatio  = br.ReadBoolean();
                    SetDefaultMonsterStatus = br.ReadBoolean();
                    LearnDefaultSpells      = br.ReadBoolean();
                }
                if (ParsingRule >= 54 && thing.Subclass[(int)ThingDb.Thing.SubclassBitIndex.FEMALE_NPC])
                {
                    MaidenBodyColors = new Color[6];
                    byte R, G, B;
                    for (int i = 0; i < 6; i++)
                    {
                        R = br.ReadByte();
                        G = br.ReadByte();
                        B = br.ReadByte();
                        MaidenBodyColors[i] = Color.FromArgb(R, G, B);
                    }
                    if (ParsingRule >= 55)
                    {
                        MaidenVoiceSet = br.ReadString();
                    }
                }
                if (ParsingRule >= 62)
                {
                    short entryType = br.ReadInt16();
                    if (entryType > 2 || entryType <= 0)
                    {
                        return(false);
                    }

                    byte count = br.ReadByte();
                    BuffList = new BuffEntry[count];
                    while (count > 0)
                    {
                        BuffEntry be = new BuffEntry();
                        be.Name     = br.ReadString();
                        be.Power    = br.ReadByte();
                        be.Duration = br.ReadInt32();
                        if (be.Name == ENCHANT_SHIELD && entryType >= 2)
                        {
                            be.ShieldHealth = br.ReadInt32();
                        }

                        BuffList[count] = be;
                        count--;
                    }
                    Array.Reverse(BuffList);
                }
                if (ParsingRule >= 63 && thing.Subclass[(int)ThingDb.Thing.SubclassBitIndex.WOUNDED_NPC])
                {
                    WoundedNPCVoiceSet = br.ReadString();
                }
                if (ParsingRule >= 64)
                {
                    PoisonLevel = br.ReadByte();
                }
            }
            return(true);
        }