/// <summary> /// Writes the log. /// </summary> /// <param name="context">The context.</param> /// <param name="stream">The stream.</param> /// <param name="callback">The callback for UI updates.</param> public void WriteLog(IExecutionContext context, Stream stream, ProgressCallback callback) { SortedList oidInfo = new SortedList(); IList CombatWaitMessage = new ArrayList(); Hashtable styleIcons = new Hashtable(); Hashtable plrInfo = new Hashtable(); weapons = new StoC_0x02_InventoryUpdate.Item[4]; PlayerInfo playerInfo = null; // = new PlayerInfo(); int playerOid = -1; string nameKey = ""; string statKey = ""; string plrName = ""; string plrClass = ""; int plrLevel = 0; int countBC = 0; using (StreamWriter s = new StreamWriter(stream)) { foreach (PacketLog log in context.LogManager.Logs) { for (int i = 0; i < log.Count; i++) { if (callback != null && (i & 0xFFF) == 0) // update progress every 4096th packet { callback(i, log.Count - 1); } Packet pak = log[i]; // Enter region (get new self OID) if (pak is StoC_0x20_PlayerPositionAndObjectID) { StoC_0x20_PlayerPositionAndObjectID plr = (StoC_0x20_PlayerPositionAndObjectID)pak; playerOid = plr.PlayerOid; oidInfo.Clear(); oidInfo[plr.PlayerOid] = new ObjectInfo(eObjectType.player, "You", 0); s.WriteLine("{0, -16} playerOid:0x{1:X4}", pak.Time.ToString(), playerOid); } // Fill objects OID else if (pak is StoC_0xD4_PlayerCreate) { StoC_0xD4_PlayerCreate player = (StoC_0xD4_PlayerCreate)pak; oidInfo[player.Oid] = new ObjectInfo(eObjectType.player, player.Name, player.Level); } else if (pak is StoC_0x4B_PlayerCreate_172) { StoC_0x4B_PlayerCreate_172 player = (StoC_0x4B_PlayerCreate_172)pak; oidInfo[player.Oid] = new ObjectInfo(eObjectType.player, player.Name, player.Level); } else if (pak is StoC_0x12_CreateMovingObject) { StoC_0x12_CreateMovingObject obj = (StoC_0x12_CreateMovingObject)pak; oidInfo[obj.ObjectOid] = new ObjectInfo(eObjectType.movingObject, obj.Name, 0); } else if (pak is StoC_0x6C_KeepComponentOverview) { StoC_0x6C_KeepComponentOverview keep = (StoC_0x6C_KeepComponentOverview)pak; oidInfo[keep.Uid] = new ObjectInfo(eObjectType.keep, string.Format("keepId:0x{0:X4} componentId:{1}", keep.KeepId, keep.ComponentId), 0); } else if (pak is StoC_0xDA_NpcCreate) { StoC_0xDA_NpcCreate npc = (StoC_0xDA_NpcCreate)pak; oidInfo[npc.Oid] = new ObjectInfo(eObjectType.npc, npc.Name, npc.Level); } else if (pak is StoC_0xD9_ItemDoorCreate) { StoC_0xD9_ItemDoorCreate item = (StoC_0xD9_ItemDoorCreate)pak; eObjectType type = eObjectType.staticObject; if (item.ExtraBytes > 0) { type = eObjectType.door; } oidInfo[item.Oid] = new ObjectInfo(type, item.Name, 0); } // Fill current weapons else if (pak is StoC_0x02_InventoryUpdate) { StoC_0x02_InventoryUpdate invPack = (StoC_0x02_InventoryUpdate)pak; if (invPack.PreAction == 1 || invPack.PreAction == 0) { VisibleSlots = invPack.VisibleSlots; for (int j = 0; j < invPack.SlotsCount; j++) { StoC_0x02_InventoryUpdate.Item item = (StoC_0x02_InventoryUpdate.Item)invPack.Items[j]; switch (item.slot) { case 10: weapons[0] = item; break; case 11: weapons[1] = item; break; case 12: weapons[2] = item; break; case 13: weapons[3] = item; break; default: break; } } } } // Fill character stats else if (pak is StoC_0x16_VariousUpdate) { // name, level, class StoC_0x16_VariousUpdate stat = (StoC_0x16_VariousUpdate)pak; if (stat.SubCode == 3) { StoC_0x16_VariousUpdate.PlayerUpdate subData = (StoC_0x16_VariousUpdate.PlayerUpdate)stat.SubData; nameKey = "N:" + subData.playerName + "L:" + subData.playerLevel; statKey = ""; plrName = subData.playerName; plrLevel = subData.playerLevel; plrClass = subData.className; s.WriteLine("{0, -16} 0x16:3 nameKey:{1} plrName:{2} {3} {4}", pak.Time.ToString(), nameKey, plrName, plrLevel, plrClass); } // mainhand spec, mainhand DPS else if (stat.SubCode == 5) { StoC_0x16_VariousUpdate.PlayerStateUpdate subData = (StoC_0x16_VariousUpdate.PlayerStateUpdate)stat.SubData; string key = string.Format("WD:{0}.{1}WS:{2}", subData.weaponDamageHigh, subData.weaponDamageLow, (subData.weaponSkillHigh << 8) + subData.weaponSkillLow); if (nameKey != "") { if (plrInfo.ContainsKey(nameKey + key)) { playerInfo = (PlayerInfo)plrInfo[nameKey + key]; } else { playerInfo = new PlayerInfo(); playerInfo.name = plrName; playerInfo.level = plrLevel; playerInfo.className = plrClass; playerInfo.weaponDamage = string.Format("{0,2}.{1,-3}", subData.weaponDamageHigh, subData.weaponDamageLow); playerInfo.weaponSkill = (subData.weaponSkillHigh << 8) + subData.weaponSkillLow; plrInfo.Add(nameKey + key, playerInfo); } plrInfo[nameKey + key] = playerInfo; } statKey = key; s.WriteLine("{0, -16} 0x16:5 S:{1} {2} {3} {4} {5}", pak.Time.ToString(), statKey, playerInfo.name, playerInfo.level, playerInfo.weaponDamage, playerInfo.weaponSkill); } // Fill styles if (stat.SubCode == 1) { StoC_0x16_VariousUpdate.SkillsUpdate subData = (StoC_0x16_VariousUpdate.SkillsUpdate)stat.SubData; styleIcons.Clear(); if (log.Version < 186) { styleIcons.Add((ushort)0x01F4, "Bow prepare"); styleIcons.Add((ushort)0x01F5, "Lefthand hit"); styleIcons.Add((ushort)0x01F6, "Bothhands hit"); styleIcons.Add((ushort)0x01F7, "Bow shoot"); // styleIcons.Add((ushort)0x01F9, "Volley aim ?"); // styleIcons.Add((ushort)0x01FA, "Volley ready ?"); // styleIcons.Add((ushort)0x01FB, "Volley shoot ?"); } else { styleIcons.Add((ushort)0x3E80, "Bow prepare"); styleIcons.Add((ushort)0x3E81, "Lefthand hit"); styleIcons.Add((ushort)0x3E82, "Bothhands hit"); styleIcons.Add((ushort)0x3E83, "Bow shoot"); // styleIcons.Add((ushort)0x3E85, "Volley aim ?"); // styleIcons.Add((ushort)0x3E86, "Volley ready ?"); // styleIcons.Add((ushort)0x3E87, "Volley shoot ?"); } foreach (StoC_0x16_VariousUpdate.Skill skill in subData.data) { if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.Styles) { styleIcons[skill.icon] = skill.name; // s.WriteLine("{0, -16} 0x16:1 icon:0x{1:X4} name:{2}", pak.Time.ToString(), skill.icon, styleIcons[skill.icon]); } } /* foreach (DictionaryEntry entry in styleIcons) * { * ushort icon = (ushort)entry.Key; * s.WriteLine("{0, -16} 0x16:1 icon:0x{1:X4} name:{2}", pak.Time.ToString(), icon, entry.Value); * }*/ } } // Combat animation else if (pak is StoC_0xBC_CombatAnimation && (playerInfo != null)) { StoC_0xBC_CombatAnimation combat = (StoC_0xBC_CombatAnimation)pak; CombatWaitMessage.Clear(); ObjectInfo targetObj = oidInfo[combat.DefenderOid] as ObjectInfo; string styleName = (combat.StyleId == 0 /* || (combat.Result & 0x7F) != 0x0B)*/) ? "" : (styleIcons[combat.StyleId] == null ? "not found " + combat.StyleId.ToString() : (styleIcons[combat.StyleId]).ToString()); string targetName = targetObj == null ? "" : " target:" + targetObj.name + " (" + targetObj.type + ")"; if (combat.Stance == 0 && combat.AttackerOid == playerOid /* && combat.DefenderOid != 0*/) { switch (combat.Result & 0x7F) { case 0: CombatWaitMessage.Add(new WaitMessage(0x11, "You miss!")); CombatWaitMessage.Add(new WaitMessage(0x11, "You were strafing in combat and miss!")); break; case 1: if (targetObj != null) { CombatWaitMessage.Add(new WaitMessage(0x11, targetObj.GetFirstFullName + " parries your attack!")); } break; case 2: // if (targetObj != null)//TODO // CombatWaitMessage.Add(new WaitMessage(0x11, targetObj.GetFirstFullName + " The Midgardian Assassin attacks you and you block the blow!")); break; case 3: if (targetObj != null) { CombatWaitMessage.Add(new WaitMessage(0x11, targetObj.GetFirstFullName + " evades your attack!")); } break; case 4: CombatWaitMessage.Add(new WaitMessage(0x11, "You fumble the attack and take time to recover!")); break; case 0xA: if (targetObj != null) { CombatWaitMessage.Add( new WaitMessage(0x11, "You attack " + targetObj.GetFullName + " with your % and hit for % damage!")); } break; case 0xB: CombatWaitMessage.Add(new WaitMessage(0x11, "You perform your " + styleName + " perfectly. %")); if (targetObj != null) { CombatWaitMessage.Add( new WaitMessage(0x11, "You attack " + targetObj.GetFullName + " with your % and hit for % damage!")); } break; case 0x14: if (targetObj != null) { CombatWaitMessage.Add(new WaitMessage(0x11, "You hit " + targetObj.GetFullName + " for % damage!")); } break; default: break; } } if (combat.AttackerOid == playerOid) { s.WriteLine("{0, -16} 0xBC attackerOid:0x{1:X4}(You) defenderOid:0x{2:X4} style:0x{4:X4} result:0x{3:X2}{5}{6}", pak.Time.ToString(), combat.AttackerOid, combat.DefenderOid, combat.Result, combat.StyleId, styleName == "" ? "" : " styleName:" + styleName, targetName); foreach (WaitMessage msg in CombatWaitMessage) { s.WriteLine(" WAITING 0xAF 0x{0:X2} {1}", msg.msgType, msg.message); } countBC++; } } // Messages else if (pak is StoC_0xAF_Message) { StoC_0xAF_Message msg = (StoC_0xAF_Message)pak; switch (msg.Type) { // case 0x10: // Your cast combat case 0x11: // Your Melee combat // case 0x1B: // resist // case 0x1D: // X hits you // case 0x1E: // X miss you s.WriteLine("{0, -16} 0xAF 0x{1:X2} {2} ", pak.Time.ToString(), msg.Type, msg.Text); break; default: break; } } } } if (nameKey != "" && statKey != "") { plrInfo[nameKey + statKey] = playerInfo; } } }
/// <summary> /// Activates a log action. /// </summary> /// <param name="context">The context.</param> /// <param name="selectedPacket">The selected packet.</param> /// <returns><c>true</c> if log data tab should be updated.</returns> public override bool Activate(IExecutionContext context, PacketLocation selectedPacket) { PacketLog log = context.LogManager.GetPacketLog(selectedPacket.LogIndex); int selectedIndex = selectedPacket.PacketIndex; int MaxHealth = -1; int MaxPower = -1; int level = -1; int champ_level = -1; string className = ""; int classId = 0; bool flagFound = false; bool flagScarsOfBattleFound = false; bool flagSkillsChecked = false; StringBuilder str = new StringBuilder(); StoC_0xFB_CharStatsUpdate_175 charStats = null; int RASkillHPBonus = 0; int RASkillMPBonus = 0; for (int i = selectedIndex; i >= 0; i--) { Packet pak = log[i]; if (pak is StoC_0xFB_CharStatsUpdate_175) { if (charStats == null && (pak as StoC_0xFB_CharStatsUpdate_175).Flag != 0xFF) { charStats = pak as StoC_0xFB_CharStatsUpdate_175; if (MaxHealth == -1) { MaxHealth = charStats.MaxHealth; } } } else if (pak is CtoS_0x9D_RegionListRequest_174) { if (classId == 0 && (pak as CtoS_0x9D_RegionListRequest_174).Flag > 0) { classId = (pak as CtoS_0x9D_RegionListRequest_174).ClassId; } } else if (pak is StoC_0xAD_StatusUpdate_190) { if (MaxHealth == -1) { MaxHealth = (pak as StoC_0xAD_StatusUpdate_190).MaxHealth; } if (MaxPower == -1) { MaxPower = (pak as StoC_0xAD_StatusUpdate_190).MaxPower; } } else if (pak is StoC_0x16_VariousUpdate) { StoC_0x16_VariousUpdate stat = (StoC_0x16_VariousUpdate)pak; if (stat.SubCode == 3) { if (level == -1) { StoC_0x16_VariousUpdate.PlayerUpdate subData = (StoC_0x16_VariousUpdate.PlayerUpdate)stat.SubData; level = subData.playerLevel; if (className != subData.className) { for (int j = 0; j < ClassInfo.Length; j++) { // TODO check for realm, while it not too nessery, becose same class name on different realms have same same HPBase if ((string)ClassInfo[j][1] == subData.className) { classId = j; break; } } } className = subData.className; if (MaxHealth == -1) { MaxHealth = (((subData.maxHealthHigh & 0xFF) << 8) | (subData.maxHealthLow & 0xFF)); } // charName = subData.playerName; if (subData is StoC_0x16_VariousUpdate_179.PlayerUpdate_179) { champ_level = (subData as StoC_0x16_VariousUpdate_179.PlayerUpdate_179).championLevel; } } } else if (stat.SubCode == 1) { if (!flagSkillsChecked) { StoC_0x16_VariousUpdate.SkillsUpdate subData = (StoC_0x16_VariousUpdate.SkillsUpdate)stat.SubData; for (int j = (pak as StoC_0x16_VariousUpdate).SubCount - 1; j >= 0; j--) { bool flagPrintSkill = false; StoC_0x16_VariousUpdate.Skill skill = subData.data[j]; if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities && skill.name.StartsWith("Toughness ")) { switch (skill.name.Substring(10)) { case "I": RASkillHPBonus = 25; break; case "II": RASkillHPBonus = 75; break; case "III": RASkillHPBonus = 150; break; case "IV": RASkillHPBonus = 250; break; case "V": RASkillHPBonus = 400; break; default: RASkillHPBonus = 0; // something wrong... break; } flagPrintSkill = true; } else if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities && skill.name.StartsWith("Ethereal Bond ")) { switch (skill.name.Substring(14)) { case "I": RASkillMPBonus = 20; // +20 for scout (20) break; case "II": RASkillMPBonus = 50; // +30 for scout (50) break; case "III": RASkillMPBonus = 80; // +30 for scout (80) break; case "IV": RASkillMPBonus = 130; // +50 for scout (130) break; case "V": RASkillMPBonus = 200; // +70 for scout (200) break; default: RASkillMPBonus = 0; // something wrong... break; } flagPrintSkill = true; } else if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities && skill.name.StartsWith("Augmented Constitution ")) { flagPrintSkill = true; } else if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities && skill.name.StartsWith("Augmented Acuity ")) { flagPrintSkill = true; } else if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities && skill.name.Equals("Scars of Battle")) { flagPrintSkill = true; flagScarsOfBattleFound = true; } if (flagPrintSkill) { str.AppendFormat("level:{0,-2} type:{1}({2,-14}) stlOpen:0x{3:X4} bonus:{4,-2} icon:0x{5:X4} name:\"{6}\"\n", skill.level, (int)skill.page, skill.page.ToString().ToLower(), skill.stlOpen, skill.bonus, skill.icon, skill.name); } } if ((pak as StoC_0x16_VariousUpdate).StartIndex == 0) // not found any RA { flagSkillsChecked = true; } } } } if (charStats != null && level != -1 && classId != 0 && flagSkillsChecked) { flagFound = true; break; } } if (flagFound) { bool flagPureCaster = (bool)ClassInfo[classId][4]; str.Append(charStats.GetPacketDataString(true)); str.Append('\n'); str.Append('\n'); str.AppendFormat("class:{0}({1}) level:{2} PureCaster:{3}", classId, className, level, flagPureCaster); if (champ_level > -1) { str.AppendFormat(" champLevel:{0}", champ_level); } str.Append('\n'); str.AppendFormat("ManaStat:{0}", (eManaStat)ClassInfo[classId][3]); int ManaStat = 0; int ManaStatBuffBonus = 0; int ManaStatItemBonus = 0; int ManaStatRealmAbilitiesBonus = 0; switch ((eManaStat)ClassInfo[classId][3]) { case eManaStat.Intelligence: ManaStat = charStats.@int; ManaStatBuffBonus = charStats.B_int; ManaStatItemBonus = Math.Min(charStats.I_int, charStats.C_int); ManaStatRealmAbilitiesBonus = charStats.R_int; break; case eManaStat.Piety: ManaStat = charStats.pie; ManaStatBuffBonus = charStats.B_pie; ManaStatItemBonus = Math.Min(charStats.I_pie, charStats.C_pie); ManaStatRealmAbilitiesBonus = charStats.R_pie; break; case eManaStat.Empathy: ManaStat = charStats.emp; ManaStatBuffBonus = charStats.B_emp; ManaStatItemBonus = Math.Min(charStats.I_emp, charStats.C_emp); ManaStatRealmAbilitiesBonus = charStats.R_emp; break; case eManaStat.Charisma: ManaStat = charStats.chr; ManaStatBuffBonus = charStats.B_chr; ManaStatItemBonus = Math.Min(charStats.I_chr, charStats.C_chr); ManaStatRealmAbilitiesBonus = charStats.R_chr; break; default: break; } if (ManaStat != 0) { str.AppendFormat(":{0}", ManaStat); } // ManaStat += (int)(ManaStatRealmAbilitiesBonus * 1.2); if (ManaStatRealmAbilitiesBonus != 0) { str.AppendFormat(" RA_ManaStat:{0}", ManaStatRealmAbilitiesBonus); } // ManaStat += ManaStatBuffBonus; if (ManaStatBuffBonus != 0) { str.AppendFormat(" BuffBonus:{0}", ManaStatBuffBonus); } ManaStat += (int)(ManaStatItemBonus * 1.2); if (ManaStatItemBonus != 0) { str.AppendFormat(" ItemBonus:{0}", ManaStatItemBonus); } if (RASkillMPBonus != 0) { str.AppendFormat(" RealmAbilitiesMana:{0}", RASkillMPBonus); } str.Append('\n'); int Constitution = charStats.con; str.AppendFormat("classBaseHP:{0} CON:{1}", (int)ClassInfo[classId][2], charStats.con); if (classId == 58) // Vampiir { str.AppendFormat(" VampBonus CON:{0}(calced:{1})", charStats.Flag * 3, (level - 5) * 3); Constitution += charStats.Flag * 3; } int RealmAbilitiesBonusConstitution = charStats.R_con; Constitution += RealmAbilitiesBonusConstitution; if (RealmAbilitiesBonusConstitution != 0) { str.AppendFormat(" RA_CON:{0}", RealmAbilitiesBonusConstitution); } int BuffBonusConstitution = charStats.B_con; Constitution += BuffBonusConstitution; if (BuffBonusConstitution != 0) { str.AppendFormat(" BuffBonus:{0}", BuffBonusConstitution); } int ItemBonusConstitution = Math.Min(charStats.I_con, charStats.C_con); Constitution += ItemBonusConstitution; if (ItemBonusConstitution != 0) { str.AppendFormat(" ItemBonus:{0}", ItemBonusConstitution); } if (RASkillHPBonus != 0) { str.AppendFormat(" RealmAbilitiesHP:{0}", RASkillHPBonus); } int ItemBonusHits = 0; int MaxHealthCalculated = CalculateMaxHealth(level, Constitution, (int)ClassInfo[classId][2], champ_level); if (flagScarsOfBattleFound) { int HeavyTankBonusHP = (int)(MaxHealthCalculated * (1.0 + (level - 40) * 0.01)); str.AppendFormat(" HeavyTankBonusHP:{0}", HeavyTankBonusHP - MaxHealthCalculated); MaxHealthCalculated = HeavyTankBonusHP; } str.Append('\n'); MaxHealthCalculated += ItemBonusHits + RASkillHPBonus; int MaxManaCalculated = CalculateMaxMana(level, ManaStat, champ_level, flagPureCaster, str); str.AppendFormat("HP:{0} CalcedHP:{1}(calcedCON:{2})\n", MaxHealth, MaxHealthCalculated, Constitution); str.AppendFormat("MaxMana:{0} CalcedMaxMana:{1}(ManaStat:{2})\n", MaxPower, MaxManaCalculated, ManaStat); int insertPos = str.Length; int ItemHitsBonus = 0; int ItemHitsBonusCap = 0; int ItemPowerBonus = 0; int ItemPowerPoolBonus = 0; int ItemPowerPoolCapBonus = 0; CheckItemsHitsBonus(log, selectedIndex, str, ref ItemHitsBonus, ref ItemHitsBonusCap, ref ItemPowerBonus, ref ItemPowerPoolBonus, ref ItemPowerPoolCapBonus); str.Insert(insertPos, string.Format("\nCalcedMP:{0} ItemBonusPower:{1} ItemBonusPowerPool:{2} (+cap:{3})\n", (int)((MaxManaCalculated + ItemPowerBonus) * (1 + 0.01 * ItemPowerPoolBonus)) + RASkillMPBonus + ManaStatRealmAbilitiesBonus * 1.2, ItemPowerBonus, ItemPowerPoolBonus, ItemPowerPoolCapBonus)); if (MaxHealthCalculated != MaxHealth) { int CapItemBonusHits = ItemHitsBonusCap + level * 4; if (MaxHealth - MaxHealthCalculated - Math.Min(ItemHitsBonus, CapItemBonusHits) == 0) { str.Insert(insertPos, string.Format("\nCalcedHP:{2} ItemBonusHits:{0} (+cap:{1})", Math.Min(ItemHitsBonus, CapItemBonusHits), ItemHitsBonusCap, MaxHealthCalculated + Math.Min(ItemHitsBonus, CapItemBonusHits))); } else { str.Insert(insertPos, string.Format("\nCalcedHP:{3} unknown Hits:{0}, ItemBonusHits:{1} (+cap:{2})", MaxHealth - MaxHealthCalculated - Math.Min(ItemHitsBonus, CapItemBonusHits), Math.Min(ItemHitsBonus, CapItemBonusHits), ItemHitsBonusCap, MaxHealthCalculated + Math.Min(ItemHitsBonus, CapItemBonusHits))); } } } InfoWindowForm infoWindow = new InfoWindowForm(); infoWindow.Text = "Player calc info (right click to close)"; infoWindow.Width = 820; infoWindow.Height = 320; infoWindow.InfoRichTextBox.Text = str.ToString(); infoWindow.StartWindowThread(); return(false); }
/// <summary> /// Activates a log action. /// </summary> /// <param name="context">The context.</param> /// <param name="selectedPacket">The selected packet.</param> /// <returns><c>true</c> if log data tab should be updated.</returns> public bool Activate(IExecutionContext context, PacketLocation selectedPacket) { PacketLog log = context.LogManager.GetPacketLog(selectedPacket.LogIndex); int selectedIndex = selectedPacket.PacketIndex; Packet originalPak = log[selectedIndex]; if (!(originalPak is CtoS_0xBB_UseSkill || originalPak is CtoS_0x7D_UseSpellList || originalPak is CtoS_0xD8_DetailDisplayRequest)) // activate condition { return(false); } int spellIndex = -1; int spellLineIndex = -1; if (originalPak is CtoS_0xBB_UseSkill) { spellIndex = (originalPak as CtoS_0xBB_UseSkill).Index; } else if (originalPak is CtoS_0x7D_UseSpellList) { spellLineIndex = (originalPak as CtoS_0x7D_UseSpellList).SpellLineIndex; spellIndex = (originalPak as CtoS_0x7D_UseSpellList).SpellLevel; } else if (originalPak is CtoS_0xD8_DetailDisplayRequest) { switch ((originalPak as CtoS_0xD8_DetailDisplayRequest).ObjectType) { case 2: spellLineIndex = (originalPak as CtoS_0xD8_DetailDisplayRequest).ObjectId / 100; spellIndex = (originalPak as CtoS_0xD8_DetailDisplayRequest).ObjectId % 100; break; default: return(false); } } else { return(false); } StringBuilder str = new StringBuilder(); IList skillList = new ArrayList(); int additionStringCount = 0; ushort spellIcon = 0xFFFF; string spellName = "UNKNOWN"; bool searchInSpellEffects = false; str.Append(originalPak.ToHumanReadableString(TimeSpan.Zero, true)); str.Append('\n'); for (int i = selectedIndex; i >= 0; i--) { Packet pak = log[i]; if (pak is StoC_0x16_VariousUpdate) { StoC_0x16_VariousUpdate variousPak = (pak as StoC_0x16_VariousUpdate); if (originalPak is CtoS_0xBB_UseSkill) { if (variousPak.SubCode == 1) { StoC_0x16_VariousUpdate.SkillsUpdate data = (variousPak.SubData as StoC_0x16_VariousUpdate.SkillsUpdate); for (int j = variousPak.SubCount - 1; j >= 0; j--) { StoC_0x16_VariousUpdate.Skill skill = data.data[j]; if ((originalPak as CtoS_0xBB_UseSkill).Type == 0 && (int)skill.page == 0) { skillList.Add(skill); } else if ((originalPak as CtoS_0xBB_UseSkill).Type == 1 && (int)skill.page > 0) { skillList.Add(skill); } } if (variousPak.StartIndex == 0) { int index = skillList.Count; int lineIndex = -1; string skillInfo = ""; foreach (StoC_0x16_VariousUpdate.Skill skill in skillList) { index--; if (index == spellIndex) { if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.Spells && skill.stlOpen != 0xFE) { lineIndex = skill.stlOpen; } if (log.Version >= 180) { if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.Styles) { str.AppendFormat("\nSpec:\"{0}\"", GetSpecNameFromInternalIndex(skill.bonus)); } } skillInfo = string.Format("\nlevel:{0,-2} type:{1}({2,-14}) stlOpen:0x{3:X4} bonus:{4,-2} icon:0x{5:X4} name:\"{6}\"\n", skill.level, (int)skill.page, skill.page.ToString().ToLower(), skill.stlOpen, skill.bonus, skill.icon, skill.name); spellIcon = skill.icon; spellName = skill.name; additionStringCount += 2; searchInSpellEffects = skill.page == StoC_0x16_VariousUpdate.eSkillPage.RealmAbilities || skill.page == StoC_0x16_VariousUpdate.eSkillPage.Spells || skill.page == StoC_0x16_VariousUpdate.eSkillPage.Songs; break; } } if (lineIndex >= 0) { index = 0; foreach (StoC_0x16_VariousUpdate.Skill skill in data.data) { if (skill.page == StoC_0x16_VariousUpdate.eSkillPage.Specialization) { if (index++ == lineIndex) { str.AppendFormat("\nSpec:\"{0}\"", skill.name); // str.AppendFormat("\nlevel:{0,-2} type:{1}({2,-14}) stlOpen:0x{3:X4} bonus:{4,-2} icon:0x{5:X4} name:\"{6}\"\n", // skill.level, (int)skill.page, skill.page.ToString().ToLower(), skill.stlOpen, skill.bonus, skill.icon, skill.name); break; } } else { break; } } } str.Append(skillInfo); break; } } } else if (spellLineIndex >= 0) { if (variousPak.SubCode == 2) { StoC_0x16_VariousUpdate.SpellsListUpdate data = (variousPak.SubData as StoC_0x16_VariousUpdate.SpellsListUpdate); if (variousPak.StartIndex == spellLineIndex) { string spellLineName = ""; for (int j = 0; j < variousPak.SubCount; j++) { StoC_0x16_VariousUpdate.Spell spell = data.list[j]; if (spell.level == spellIndex) { str.AppendFormat("\nspellLineIndex:{0}(\"{4}\") spellLevel:{1,-2} icon:0x{2:X4} name:\"{3}\"\n", spellLineIndex, spell.level, spell.icon, spell.name, spellLineName); spellIcon = spell.icon; spellName = spell.name; searchInSpellEffects = true; additionStringCount += 2; break; } else if (spell.level == 0) { spellLineName = spell.name; } } } if (variousPak.SubType == 2 && variousPak.StartIndex == 0) // not this spell found in spellList { break; } } } } } if (searchInSpellEffects) { bool spellEffectFound = false; bool concEffectFound = false; for (int i = selectedIndex; i < log.Count; i++) { Packet pak = log[i]; if (pak is StoC_0x7F_UpdateIcons) { if (spellEffectFound) { continue; } StoC_0x7F_UpdateIcons effectsPak = (pak as StoC_0x7F_UpdateIcons); if (effectsPak != null) { for (int j = 0; j < effectsPak.EffectsCount; j++) { if (effectsPak.Effects[j].name == spellName) { StoC_0x7F_UpdateIcons.Effect effect = effectsPak.Effects[j]; str.Append('\n'); str.Append(pak.ToHumanReadableString(TimeSpan.Zero, true)); str.Append('\n'); spellIcon = effect.icon; additionStringCount += (2 + effectsPak.EffectsCount); spellEffectFound = true; break; } } if (spellEffectFound && concEffectFound) { break; } } } else if (pak is StoC_0x75_SetConcentrationList) { if (concEffectFound) { continue; } if (spellIcon != 0xFFFF) { StoC_0x75_SetConcentrationList concPak = (pak as StoC_0x75_SetConcentrationList); if (concPak != null) { for (int j = 0; j < concPak.EffectsCount; j++) { if (concPak.Effects[j].icon == spellIcon) { // if (concPak.Effects[j].effectName.Substring(10) != spellName.Substring(10)) continue; StoC_0x75_SetConcentrationList.ConcentrationEffect effect = concPak.Effects[j]; str.AppendFormat("\nCONC index:{0,-2} conc:{1,-2} icon:0x{2:X4} ownerName:\"{3}\" effectName:\"{4}\"", effect.index, effect.concentration, effect.icon, effect.ownerName, effect.effectName); str.Append('\n'); additionStringCount += (2 + concPak.EffectsCount); concEffectFound = true; break; } } if (/*spellEffectFound && */ concEffectFound) // conc packet always after effect packet, so we can break on conc packet { break; } } } } } } if (spellName != "UNKNOWN") { additionStringCount += FormInfoString(log, selectedIndex, str, spellIcon, spellName); } InfoWindowForm infoWindow = new InfoWindowForm(); infoWindow.Text = "Use skill/Cast spell info (right click to close)"; infoWindow.Width = 800; infoWindow.Height = 100; infoWindow.Height += 14 * additionStringCount; infoWindow.InfoRichTextBox.Text = str.ToString(); infoWindow.StartWindowThread(); return(false); }