public void Register(ParsedLine line) { bool add = false; OwnerInfo OwnerInfo = null; // Record owner of all entities we see. if (line.srcEntityType == EntityType.Entity) { if (entityPlayerCache.TryGetValue(line.srcInt, out OwnerInfo)) { if (OwnerInfo.ownerInt != line.ownInt) { // Pet Owner changed... Not sure if possible... but just in case. entityPlayerCache.Remove(OwnerInfo.petInt); add = true; } } else { // Multiple entities may be owned by same owner. add = true; } if (add) { OwnerInfo = new OwnerInfo(); OwnerInfo.ownerDsp = line.ownDsp; OwnerInfo.ownerInt = line.ownInt; OwnerInfo.ownerEntityType = line.ownEntityType; OwnerInfo.petDsp = line.srcDsp; OwnerInfo.petInt = line.srcInt; entityPlayerCache.Add(line.srcInt, OwnerInfo); } } }
private void ProcessSourceNames(ParsedLine line) { switch (line.srcEntityType) { case EntityType.Player: { line.encAttackerName = line.srcDsp; line.unitAttackerName = line.srcDsp; break; } case EntityType.Pet: { OwnerInfo owner = petOwnerRegistery.Resolve(line.srcInt); if (owner != null) { // Use the pet owner name for encounter name and filtering. line.encAttackerName = owner.ownerDsp; // Pet name: line.unitAttackerName = line.srcDsp + " [" + owner.ownerDsp + "'s Pet]"; if (this.checkBox_mergePets.Checked) { line.unitAttackerName = owner.ownerDsp; } } else { // Pet with unknown owner. // Register it under UNKNOWN until it resolves. line.encAttackerName = unk; line.unitAttackerName = unk; } break; } case EntityType.Entity: { OwnerInfo owner = entityOwnerRegistery.Resolve(line.srcInt); if (owner != null) { if (owner.ownerEntityType == EntityType.Creature) { line.encAttackerName = owner.ownerDsp; if (checkBox_mergeNPC.Checked) { // Merge all NPCs to a single name. line.unitAttackerName = owner.ownerDsp; } else { // Separate each NPC with its unique creature ID added. String creatureId = owner.ownerInt.Split()[0].Substring(2); line.unitAttackerName = owner.ownerDsp + " [" + creatureId + "]"; } } else { line.encAttackerName = owner.ownerDsp; line.unitAttackerName = owner.ownerDsp; } } else { line.encAttackerName = line.srcDsp; line.unitAttackerName = line.srcDsp; } break; } case EntityType.Creature: { line.encAttackerName = line.srcDsp; if (checkBox_mergeNPC.Checked) { // Merge all NPCs to a single name. line.unitAttackerName = line.srcDsp; } else { // Separate each NPC with its unique creature ID added. String creatureId = line.srcInt.Split()[0].Substring(2); line.unitAttackerName = line.srcDsp + " [" + creatureId + "]"; } break; } // case ParsedLine.EntityType.Unknown: default: { // Use the defaults. line.encAttackerName = line.srcDsp; line.unitAttackerName = line.srcDsp; break; } } }
private void ProcessTargetNames(ParsedLine line) { switch (line.tgtEntityType) { case EntityType.Player: { line.encTargetName = line.tgtDsp; line.unitTargetName = line.tgtDsp; break; } case EntityType.Pet: { line.tgtOwnerInfo = petOwnerRegistery.Resolve(line.tgtInt); if (line.tgtOwnerInfo != null) { // Use the pet owner name for encounter name and filtering. line.encTargetName = line.tgtOwnerInfo.ownerDsp; // Pet name: line.unitTargetName = line.tgtDsp + " [" + line.tgtOwnerInfo.ownerDsp + "'s Pet]"; if (this.checkBox_mergePets.Checked) { line.unitTargetName = line.tgtOwnerInfo.ownerDsp; } } else { // Pet with unknown owner. // Register it under UNKNOWN until it resolves. line.encTargetName = unk; line.unitTargetName = unk; } break; } case EntityType.Entity: { line.tgtOwnerInfo = entityOwnerRegistery.Resolve(line.tgtInt); if (line.tgtOwnerInfo != null) { // What does this mean??? } break; } case EntityType.Creature: { if (line.tgtInt.Contains(" Trickster_Baitandswitch")) { // Bait and Switch // 13:07:09:21:57:26.9::Dracnia,P[200787912@7184553 Dracnia@tminhtran],,*,Lodur,C[215 Trickster_Baitandswitch],Lashing Blade,Pn.Gji3ar1,Physical,Critical|Flank|Kill,14778.6,15481.4 // Not a pet... line.encTargetName = line.tgtDsp; line.unitTargetName = "Trickster [" + line.tgtDsp + "]"; } else { line.encTargetName = line.tgtDsp; String creatureId = line.tgtInt.Split()[0].Substring(2); if (checkBox_mergeNPC.Checked) { // Merge all NPCs to a single name. line.unitTargetName = line.tgtDsp; } else { // Separate each NPC with its unique creature ID added. line.unitTargetName = line.tgtDsp + " [" + creatureId + "]"; } } break; } // case ParsedLine.EntityType.Unknown: default: { // Use the defaults. break; } } }
private void ProcessNamesTargetOnly(ParsedLine line) { // Target only ProcessTargetNames(line); }
private void ProcessOwnerSourceNames(ParsedLine line) { // Owner default: line.encAttackerName = line.ownDsp; line.unitAttackerName = line.ownDsp; // We assume the owner is the owner of the source for this processing. if (line.srcEntityType == EntityType.Pet) { // Use the pet owner name for encounter name and filtering. line.encAttackerName = line.ownDsp; // Pet name: line.unitAttackerName = line.srcDsp + " [" + line.ownDsp + "'s Pet]"; if (this.checkBox_mergePets.Checked) { line.unitAttackerName = line.ownDsp; } } else if (line.ownEntityType == EntityType.Creature) { line.encAttackerName = line.ownDsp; String creatureId = line.ownInt.Split()[0].Substring(2); if (checkBox_mergeNPC.Checked) { // Merge all NPCs to a single name. line.unitAttackerName = line.ownDsp; } else { // Separate each NPC with its unique creature ID added. line.unitAttackerName = line.ownDsp + " [" + creatureId + "]"; } } }
public void AddShield(MasterSwing ms, ParsedLine line) { ShieldLine sl = new ShieldLine(); sl.ms = ms; sl.line = line; active.AddLast(sl); }
private void ProcessAction(ParsedLine l) { l.logInfo.detectedType = Color.Gray.ToArgb(); if (l.type == "HitPoints") { ProcessActionHeals(l); } else if (l.type == "Shield") { ProcessActionShields(l); } else if (l.type == "AttribModExpire") // Cleanse { ProcessActionCleanse(l); } else if (l.type == "Power") { ProcessActionPower(l); } else if (l.showPowerDisplayName) { // Non-damaging effects. ProcessActionSPDN(l); } else { // What is left should all be damage. ProcessActionDamage(l); } // add action Killing if (l.kill) { l.logInfo.detectedType = Color.Fuchsia.ToArgb(); // Clean from last MM hit. // The Kill can come right before a proc. Ordering isssue. // magicMissileLastHit.Remove(l.tgtInt); // TODO: use tgtDsp or unitTargetName? ActGlobals.oFormSpellTimers.RemoveTimerMods(l.tgtDsp); ActGlobals.oFormSpellTimers.DispellTimerMods(l.tgtDsp); // No "Killing : Flank" ever. Doesn't make sense since there is no damage in the kill tracking. // And it messes up the kill counts. // AddCombatActionHostile(l, l.swingType, l.critical, l.special, "Killing", Dnum.Death, l.type); // Use encounter names attacker and target here. This allows filtering if (ActGlobals.oFormActMain.SetEncounter(l.logInfo.detectedTime, l.encAttackerName, l.encTargetName)) { MasterSwing ms = new MasterSwing(l.swingType, l.critical, l.special, Dnum.Death, l.logInfo.detectedTime, l.ts, "Killing", l.unitAttackerName, "Death", l.unitTargetName); ms.Tags.Add("Flank", l.flank); ActGlobals.oFormActMain.AddCombatAction(ms); } } }
private void ProcessActionSPDN(ParsedLine l) { // Handle all the buff and proc buffs/debuffs // type: PowerRecharge, Null, Alacrity, CombatAdvantage, Lightning(Storm Spell), CritSeverity, ... l.logInfo.detectedType = Color.DarkTurquoise.ToArgb(); if (l.evtInt == "Pn.Fwolu") // Chaotic Growth { // Chaotic Growth (Fixed in latest NW patch) // 13:07:18:10:51:58.2::Tifa,P[200500793@6707245 Tifa@liliiith],,*,Guard,C[2205 Mindflayer_Duergarguardthrall],Chaotic Growth,Pn.Fwolu,Null,ShowPowerDisplayName,0,0 l.logInfo.detectedType = Color.DarkOliveGreen.ToArgb(); ProcessNamesOST(l); ChaoticGrowthInfo cgi = null; if (magicMissileLastHit.TryGetValue(l.tgtInt, out cgi)) { cgi.triggered = true; cgi.ts = l.logInfo.detectedTime; cgi.encName = l.encAttackerName; cgi.unitName = l.unitAttackerName; } if (ActGlobals.oFormActMain.InCombat) { AddCombatActionHostile(l, (int)SwingTypeEnum.NonMelee, l.critical, l.special, l.attackType, Dnum.NoDamage, 0, l.type); } } else if (l.evtInt == "Pn.Zh5vu") { // Storm Spell // 13:07:18:10:49:10.1::Tifa,P[200500793@6707245 Tifa@liliiith],,*,Scourge,C[2143 Mindflayer_Scourge],Storm Spell,Pn.Zh5vu,Lightning,ShowPowerDisplayName,583.917,0 // Ignore this as there is a damage log line to go with it. } else if (injuryTypes.ContainsKey(l.evtInt)) { // Injure... // Ignore this as it is not reall part of combat. } else { // Default if (ActGlobals.oFormActMain.InCombat) { ProcessNamesOST(l); AddCombatActionHostile(l, (int)SwingTypeEnum.NonMelee, l.critical, l.special, l.attackType, Dnum.NoDamage, 0, l.type); } } }
private void ProcessBasic(ParsedLine line) { // // Fix up the ParsedLine. // Add calculated data fields to the ParsedLine. // if (line.ownDsp == "" && line.ownInt == "") { // Ugly fix for lines without an owner line.ownDsp = NW_Parser.unk; line.ownInt = NW_Parser.unkInt; } else if (line.ownInt[0] == 'P') { line.ownEntityType = EntityType.Player; } else if (line.ownInt[0] == 'C') { // There should never be a Pet or Entity in this possition?? line.ownEntityType = EntityType.Creature; } if (line.srcInt == "*") { line.srcDsp = line.ownDsp; line.srcInt = line.ownInt; line.srcEntityType = line.ownEntityType; } else if ((line.srcInt == "") && (line.srcDsp == "")) { // // // Ugly fix for lines without a source // // srcDsp = NW_Parser.unk; // // srcInt = NW_Parser.unkInt; // // Ugly fix does not work. See this valid example from a log: // "13:07:02:13:48:18.1::Kallista Hellbourne,P[200674407@288107 Kallista Hellbourne@tonyleon],,,Sentry,C[1150404 Frost_Goblin_Sentry],Storm Spell,Pn.Zh5vu,Lightning,ShowPowerDisplayName,580.333,0" // The Control Wizard effect Storm Spell seems to not have a source. Should just use the owner in this case. // If the owner is unknown this will work as before. line.srcDsp = line.ownDsp; line.srcInt = line.ownInt; line.srcEntityType = line.ownEntityType; } else if (line.srcInt[0] == 'P') { line.srcEntityType = EntityType.Player; } else if (line.srcInt[0] == 'C') { // Basic Pet and Entity detection.. if (line.srcInt.Contains(" Pet_")) { line.srcEntityType = EntityType.Pet; } else if (line.srcInt.Contains(" Entity_")) { line.srcEntityType = EntityType.Entity; } else { line.srcEntityType = EntityType.Creature; } } if (line.tgtInt == "*") { line.tgtDsp = line.srcDsp; line.tgtInt = line.srcInt; line.tgtEntityType = line.srcEntityType; // If it is a Pet then the pet owner info needs to get set. // But first we can not do it here in case this is the first time we saw the owner. // Need to register owner of pet first... } else if ((line.tgtInt == "") && (line.tgtDsp == "")) { // Ugly fix for lines without a target line.tgtDsp = NW_Parser.unk; line.tgtInt = NW_Parser.unkInt; } else if (line.tgtInt[0] == 'P') { line.tgtEntityType = EntityType.Player; } else if (line.tgtInt[0] == 'C') { // Basic Pet and Entity detection.. if (line.tgtInt.Contains(" Pet_")) { line.tgtEntityType = EntityType.Pet; } else if (line.tgtInt.Contains(" Entity_")) { line.tgtEntityType = EntityType.Entity; } else { line.tgtEntityType = EntityType.Creature; } } // Defaults for the clean names. line.encAttackerName = line.ownDsp; line.encTargetName = line.tgtDsp; line.unitAttackerName = line.ownDsp; line.unitTargetName = line.tgtDsp; }
private void ProcessActionPower(ParsedLine l) { int magAdj = (int)Math.Round(l.mag); //int magBaseAdj = (int)Math.Round(l.magBase * 10); l.logInfo.detectedType = Color.Black.ToArgb(); // NOTE: Do NOT use SetEncounter() on power (i.e Non-Hostile Actions) if (ActGlobals.oFormActMain.InCombat) { if (l.evtInt == "Pn.Ygyxld") // Critical Power { // Critical Power // 13:07:18:10:40:48.3::Tifa,P[200500793@6707245 Tifa@liliiith],Shard,C[2006 Entity_Shardoftheendlessavalanche],,*,Critical Power,Pn.Ygyxld,Power,,-0,0 // This power can trigger on CW's entities... These triggers should be ignored as they are zero effect. if (l.ownInt != l.srcInt) { l.logInfo.detectedType = Color.Gray.ToArgb(); return; } } if (l.evtInt == "Pn.He9xu") // Bait and Switch { // TR - Bait and Switch Trigger // special case: Bait and Switch // 13:07:09:20:53:00.9::Lodur,C[835 Trickster_Baitandswitch],,*,Lodur,P[201093074@7545190 Lodur@lodur42],Trigger,Pn.He9xu,Power,,-0.521139,0 // 13:07:09:21:43:30.3::Lodur,C[152 Trickster_Baitandswitch],,*,Lodur,P[201093074@7545190 Lodur@lodur42],Trigger,Pn.He9xu,Power,Immune,0,0 // 13:07:10:09:11:08.8::Lodur,C[178 Trickster_Baitandswitch],,*,Lodur,P[201093074@7545190 Lodur@lodur42],Trigger,Pn.He9xu,Power,Immune,0,0 ProcessNamesTargetOnly(l); // Target is the source as well. AddCombatActionNW( (int)SwingTypeEnum.PowerHealing, l.critical, false, "", "Trickster [" + l.tgtDsp + "]", "Bait and Switch", new Dnum(-magAdj), -l.mag, 0, l.logInfo.detectedTime, l.ts, l.tgtDsp, l.type); } else if (l.evtInt == "Pn.Jy04um1") // Guard Break { // Guard Break // 13:07:18:10:50:08.7::Largoevo,P[201228983@6531604 Largoevo@largoevo],Bodyguard,C[2175 Mindflayer_Thoonhulk_Eventbodyguard],Largoevo,P[201228983@6531604 Largoevo@largoevo],Guard Break,Pn.Jy04um1,Power,,-28.8571,0 // Owner = Guardian Fighter [Attacker] // source = Target enemy [Special] // target = Guardian Fighter [Victim] // // NOTE: Do not assume source is a pet of owner. Source could be a pet or fake pet. Resolve fake pet to owner. ProcessNamesST(l); AddCombatActionNW( (int)SwingTypeEnum.PowerHealing, l.critical, false, l.unitAttackerName, l.unitTargetName, l.evtDsp, new Dnum(-magAdj), -l.mag, 0, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } else if (l.evtInt == "Pn.Wxao05") // Maelstrom of Chaos { // Maelstrom of Chaos // 13:07:18:10:37:50.5::Tifa,P[200500793@6707245 Tifa@liliiith],,*,,*,Maelstrom of Chaos,Pn.Wxao05,Power,,500,0 // Canceling this power early will cost half of your Action Points. // Ignore this for now. } else { // Normal Power case... ProcessNamesOST(l); AddCombatActionNW( (int)SwingTypeEnum.PowerHealing, l.critical, l.flank, l.special, l.unitAttackerName, l.attackType, new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } } }
private void ProcessActionShields(ParsedLine l) { int magAdj = (int)Math.Round(l.mag); int magBaseAdj = (int)Math.Round(l.magBase); // Shielding goes first and acts like a heal to cancel coming damage. Attacker has his own damage line. example: // 13:07:02:10:48:49.1::Neston,P[200243656@6371989 Neston@adamtech],,*,Flemming Fedtgebis,P[201082649@7532407 Flemming Fedtgebis@feehavregroed],Forgemaster's Flame,Pn.Lbf9ic,Shield,,-349.348,-154.608 // 13:07:02:10:48:49.1::SorXian,P[201063397@7511146 SorXian@sorxian],,*,Flemming Fedtgebis,P[201082649@7532407 Flemming Fedtgebis@feehavregroed],Entangling Force,Pn.Oonws91,Shield,,-559.613,-247.663 // 13:07:02:10:48:49.1::Neston,P[200243656@6371989 Neston@adamtech],,*,Flemming Fedtgebis,P[201082649@7532407 Flemming Fedtgebis@feehavregroed],Forgemaster's Flame,Pn.Lbf9ic,Radiant,,154.608,349.348 // 13:07:02:10:48:49.1::SorXian,P[201063397@7511146 SorXian@sorxian],,*,Flemming Fedtgebis,P[201082649@7532407 Flemming Fedtgebis@feehavregroed],Entangling Force,Pn.Oonws91,Arcane,,247.663,559.613 // NOTE: // Notice that the mag and magBase numbers are swap in the shield line verse the damage line. // Therefore the amount shield == magBase ??? // The mag is meaningless ??? // If mag > magBase on the attack is all damage not shielded ??? (ie high armor pen) // NOTE: // NW Patch on 7/17/2013 changed shield to report blocked damage in the mag field. // 13:07:18:10:25:54.2::Miner,C[1445 Mindflayer_Duergarminerthrall],,*,Largoevo,P[201228983@6531604 Largoevo@largoevo],Melee Attack,Pn.M7kie6,Shield,,-242.837,0 // Actuall not sure on this.... // // Target prevented damage. // l.logInfo.detectedType = l.critical ? Color.Green.ToArgb() : Color.DarkGreen.ToArgb(); ProcessNamesOST(l); // Use encounter names attacker and target here. This allows filtering // Hostile action triggered. Use SetEncounter(). if (ActGlobals.oFormActMain.SetEncounter(l.logInfo.detectedTime, l.encAttackerName, l.encTargetName)) { // Put the attacker and the attack type in the special field. string special = l.unitAttackerName + " : " + l.attackType; Dnum shielded = null; float mag = 0; float magBase = 0; // This is just weird... if (l.magBase == 0) // Don't use magBaseAdj here. Rounded to zero is not zero. { shielded = new Dnum( -magAdj ); mag = -l.mag; magBase = -l.magBase; } else { shielded = new Dnum(-magBaseAdj); mag = -l.magBase; magBase = -l.mag; } // SwingType = Heal // special = attacker // attacker & victim = target MasterSwing ms = new MasterSwing( (int)SwingTypeEnum.Healing, l.critical, special, shielded, l.logInfo.detectedTime, l.ts, l.type, l.unitTargetName, l.type, l.unitTargetName); ms.Tags.Add("DamageF", mag); ms.Tags.Add("Flank", l.flank); ActGlobals.oFormActMain.AddCombatAction(ms); unmatchedShieldLines.AddShield(ms, l); } }
private void ProcessActionHeals(ParsedLine l) { int magAdj = (int)Math.Round(l.mag); int magBaseAdj = (int)Math.Round(l.magBase); l.logInfo.detectedType = l.critical ? Color.Green.ToArgb() : Color.DarkGreen.ToArgb(); // NOTE: Do NOT use SetEncounter() on heals (i.e Non-Hostile Actions) // Heals can not start an encounter. if (ActGlobals.oFormActMain.InCombat) { ProcessNamesOST(l); // PVP Rune Heal - Needs some cleanup. Use the player as the source since they grabbed it. // Does 'Pn.R0jdk' == PVP RUNE HEAL??? // 13:07:09:14:00:23.2::Rune,C[317 Pvp_Rune_Heal],,*,Mus'Mugen Uhlaalaa,P[201045055@5998737 Mus'Mugen Uhlaalaa@bupfen],Heal,Pn.R0jdk,HitPoints,,-1136.92,0 if (l.evtInt == "Pn.R0jdk") // Assume this is PVP Rune Heal for now... { AddCombatActionNW( (int)SwingTypeEnum.Healing, l.critical, false, l.special, l.unitTargetName, "PVP Heal Rune", new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } else if (l.evtInt == "Pn.Hemuxg") // PvP Kill downed player { // PVP finish off // 13:07:10:09:13:09.2::CamierDerWeisse,P[200083978@5783571 CamierDerWeisse@faru2],,*,FIVEFINGERZ,P[200862049@7260841 FIVEFINGERZ@fivefingerz],Kill,Pn.Hemuxg,HitPoints,,0,0 // TODO: Should this be recorded or ignored... } else if (l.evtInt == "Pn.Qiwkdx1") // Pretty sure this is end of pvp auto heal. { // TODO: Make sure this is really only an end of pvp match auto heal. // 13:07:10:11:03:42.1::Nephylia Necromon,P[201238857@7793332 Nephylia Necromon@nephodin],,*,,*,,Pn.Qiwkdx1,HitPoints,,-7240.66,0 // Ignore it. } else if (l.evtInt == "Pn.Dbm4um1") // Campfire { // Camp fire. // Give credit to the player for standing in it. // Note: Trying to eliminate the [unknown] source. // 13:07:10:11:02:20.6::,,,,Brandeor,P[201267923@5148411 Brandeor@brandeor],Campfire,Pn.Dbm4um1,HitPoints,,-525.321,0 AddCombatActionNW( (int)SwingTypeEnum.Healing, l.critical, false, l.special, l.unitTargetName, l.evtDsp, new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } else if (l.evtInt == "Pn.Zrqjy1") // Chaotic Growth { // Chaotic Growth - Proc debuff from CW Magic Missile. Debuffed target AOE heals casters allies. // But the log shows the debuffed target as the healer... // Credit should go to the CW that casted the MM, but that is not clear in the logs. // 13:07:09:20:52:51.5::Rassler,P[200973822@6215544 Rassler@lendal4],,*,Rhiyan Torr,P[200010914@5686857 Rhiyan Torr@wyvernonenine],Chaotic Growth,Pn.Zrqjy1,HitPoints,,-215,0 // NOTE: Track the last person to hit each target with magic missile. Give healing credit to that person. // IF that fails then it is a self heal... Keeps it on the same team in pvp at least. bool handled = false; ChaoticGrowthInfo cgi = null; if (magicMissileLastHit.TryGetValue(l.srcInt, out cgi)) { if (!cgi.triggered) { cgi.triggered = true; cgi.ts = l.logInfo.detectedTime; } // Use encounter names attacker and target here. This allows filtering // NOTE: Use SetEncounter() as this heal is part of a hostile action. if (ActGlobals.oFormActMain.SetEncounter(l.logInfo.detectedTime, cgi.encName, l.encTargetName)) { AddCombatActionNW( (int)SwingTypeEnum.Healing, l.critical, l.flank, l.unitAttackerName, cgi.unitName, l.evtDsp, new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } handled = true; } if (!handled) { // Use encounter names attacker and target here. This allows filtering // NOTE: Use SetEncounter() as this heal is part of a hostile action. if (ActGlobals.oFormActMain.SetEncounter(l.logInfo.detectedTime, l.encTargetName, l.encTargetName)) { AddCombatActionNW( (int)SwingTypeEnum.Healing, l.critical, l.flank, l.unitAttackerName, unk, l.evtDsp, new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } } } else if (l.evtInt == "Pn.R1tsg4") { // Shocking execution // There is a HitPoints of value zero that is assioatied with shocking execution. // Note that the <EvtInt> is different from the actual damaging log entry. // Just ignore it... // 13:07:17:10:33:02.1::Lodur,P[201093074@7545190 Lodur@lodur42],,*,KingOfSwordsx2,P[201247997@5290133 KingOfSwordsx2@sepherosrox],Shocking Execution,Pn.R1tsg4,HitPoints,,0,0 } else { // Default heal. AddCombatActionNW( (int)SwingTypeEnum.Healing, l.critical, l.flank, l.special, l.unitAttackerName, l.attackType, new Dnum(-magAdj), -l.mag, -l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type); } } }
private void ProcessActionDamage(ParsedLine l) { int magAdj = (int)Math.Round(l.mag); int magBaseAdj = (int)Math.Round(l.magBase); l.logInfo.detectedType = l.critical ? Color.Red.ToArgb() : Color.DarkRed.ToArgb(); string special = l.special; MasterSwing msShielded = unmatchedShieldLines.MatchDamage(l); if (msShielded != null) { // Fix up the shield line. // Tags are about the only thing that can be altered on MS that is already added via AddCombatAction. // So do most of it with adding Tags. // Shield line: add column for attack damage and % blocked // Attack line: add amount shielded to the 'special' column. object val; if (msShielded.Tags.TryGetValue("DamageF", out val)) { float df = (float) val; string shieldSpecialText = "Shield(" + df.ToString("F1") + ")"; if (special == "None") { special = shieldSpecialText; } else { special = l.special + " | " + shieldSpecialText; } float shielded = df / l.mag; msShielded.Tags.Add("ShieldDmgF", l.mag); msShielded.Tags.Add("ShieldP", shielded); } } if (l.evtInt == "Autodesc.Combatevent.Falling") { // Falling damage does not start combat... if (ActGlobals.oFormActMain.InCombat) { ProcessNamesOST(l); AddCombatActionHostile(l, l.swingType, l.critical, special, l.attackType, magAdj, l.mag, l.type, l.magBase); } } else if (l.evtInt == "Pn.Wypyjw1") // Knight's Valor, { // "13:07:18:10:30:48.3::Largoevo,P[201228983@6531604 Largoevo@largoevo],Ugan the Abominable,C[1469 Mindflayer_Miniboss_Ugan],Largoevo,P[201228983@6531604 Largoevo@largoevo],Knight's Valor,Pn.Wypyjw1,Physical,,449.42,1195.48 // Attack goes SRC -> TRG and ignore the owner. The SRC is not the owner's pet. ProcessNamesST(l); AddCombatActionHostile(l, l.swingType, l.critical, special, l.attackType, magAdj, l.mag, l.type, l.magBase); } else { ProcessNamesOST(l); if ((l.evtInt == "Pn.3t6cw8") && (magAdj > 0)) // Magic Missile { ChaoticGrowthInfo cgi = null; if (magicMissileLastHit.TryGetValue(l.tgtInt, out cgi)) { if (cgi.triggered) { TimeSpan t = l.logInfo.detectedTime - cgi.ts; if (t.TotalSeconds > 10.0) { cgi.triggered = false; } } if (!cgi.triggered) { cgi.encName = l.encAttackerName; cgi.unitName = l.unitAttackerName; cgi.ts = l.logInfo.detectedTime; } } else { cgi = new ChaoticGrowthInfo(); cgi.encName = l.encAttackerName; cgi.unitName = l.unitAttackerName; cgi.triggered = false; cgi.ts = l.logInfo.detectedTime; magicMissileLastHit.Add(l.tgtInt, cgi); } } // // Note: There seems to be many cases where dmgBase == 0 while damage is applied. // /* if (l.flags.Contains("Miss")) { // TODO: Not sure I have ever seen a "miss" in a log. This actually valid? AddCombatActionHostile(l, l.swingType, l.critical, l.special, l.attackType, Dnum.Miss, l.type, magBaseAdj); } else */ if (l.immune) { if ((magAdj == 0) && (magBaseAdj == 0)) { // 13:07:18:10:49:21.6::Tristan,C[2120 Pet_Dog],,*,Oll'noth the Dominator,C[1997 Mindflayer_Eventboss],Takedown,Pn.Ebxsjf,KnockBack,Immune,0,0 // Ignore these for now... l.logInfo.detectedType = Color.Gray.ToArgb(); } else { // Generally damaging attacks have mag=0 and magBase > 0 when Immune. l.logInfo.detectedType = Color.Maroon.ToArgb(); AddCombatActionHostile(l, l.swingType, l.critical, special, l.attackType, Dnum.NoDamage, l.mag, l.type, l.magBase); } } else if (l.dodge) { // It really looks like Dodge does not stop all damage - just reduces it by about 80%... // I have seen damaging attacks that are both Dodge and Kill in the flags. // So the target dodged but still died. l.logInfo.detectedType = Color.Maroon.ToArgb(); AddCombatActionHostile(l, l.swingType, l.critical, special, l.attackType, magAdj, l.mag, l.type, l.magBase); } else { if ((magAdj == 0) && (magBaseAdj == 0)) { // Ignore it... This is generally a Non-Target entity getting AOE'd... l.logInfo.detectedType = Color.Gray.ToArgb(); } else { // NOT All attacks have a magBase (anymore). AddCombatActionHostile(l, l.swingType, l.critical, special, l.attackType, magAdj, l.mag, l.type, l.magBase); } } } }
private void ProcessActionCleanse(ParsedLine l) { l.logInfo.detectedType = Color.Blue.ToArgb(); // Cleanse // 13:07:17:10:37:53.5::righteous,P[201081445@5908801 righteous@r1ghteousg],,*,KingOfSwordsx2,P[201247997@5290133 KingOfSwordsx2@sepherosrox],Cleanse,Pn.H8hm3x1,AttribModExpire,ShowPowerDisplayName,0,0 if (ActGlobals.oFormActMain.InCombat) { ProcessNamesOST(l); AddCombatActionNW( (int)SwingTypeEnum.CureDispel, l.critical, l.flank, l.special, l.unitAttackerName, l.attackType, Dnum.NoDamage, l.mag, l.magBase, l.logInfo.detectedTime, l.ts, l.unitTargetName, l.type ); } }
// For hostile actions only. Handles the SetEncounter(). private void AddCombatActionHostile( ParsedLine line, int swingType, bool critical, string special, string theAttackType, Dnum Damage, float realDamage, string theDamageType, float baseDamage=0) { // Use encounter names attacker and target here. This allows filtering if (ActGlobals.oFormActMain.SetEncounter(line.logInfo.detectedTime, line.encAttackerName, line.encTargetName)) { // add Flank to AttackType if setting is set string tempAttack = theAttackType; if (line.flank && this.checkBox_flankSkill.Checked) tempAttack = theAttackType + ": Flank"; AddCombatActionNW( swingType, line.critical, line.flank, special, line.unitAttackerName, tempAttack, Damage, realDamage, baseDamage, line.logInfo.detectedTime, line.ts, line.unitTargetName, theDamageType); } }
private void ProcessNamesOST(ParsedLine line) { // Owner, Source (belongs to owner), Target petOwnerRegistery.Register(line); entityOwnerRegistery.Register(line); ProcessOwnerSourceNames(line); ProcessTargetNames(line); }
public void Register(ParsedLine line) { // Problem lines: // "13:07:02:13:48:18.1::Kallista Hellbourne,P[200674407@288107 Kallista Hellbourne@tonyleon],,,Sentry,C[1150404 Frost_Goblin_Sentry],Storm Spell,Pn.Zh5vu,Lightning,ShowPowerDisplayName,580.333,0" // "13:07:03:11:47:12.6::Grizzard,P[200743305@6022049 Grizzard@shamedy],Cutter,C[9395 Winterforge_Frost_Goblin_Cutter],Grizzard,P[200743305@6022049 Grizzard@shamedy],Guard Break,Pn.Jy04um1,Power,,-23.1135,0" // "13:07:09:11:01:08.4::Correk,P[201028460@1546238 Correk@Gleyvien],Target Dummy,C[265291 Entity_Targetdummy],,*,Doom!,Pn.F1j0yx1,Radiant,Critical,10557.2,8445.78" // "13:07:09:11:01:59.5::Nasus king,P[201132249@7587600 Nasus king@portazorras],SerGay,C[265715 Pet_Clericdisciple],Target Dummy,C[265291 Entity_Targetdummy],Sacred Flame,Pn.Tegils,Physical,Flank,59.7605,0" bool add = false; OwnerInfo OwnerInfo = null; // Record owner of all pets we see. if (line.srcEntityType == EntityType.Pet) { if (petPlayerCache.TryGetValue(line.srcInt, out OwnerInfo)) { if (OwnerInfo.ownerInt != line.ownInt) { // Pet Owner changed... Not sure if possible... but just in case. petPlayerCache.Remove(OwnerInfo.petInt); playerPetCache.Remove(OwnerInfo.ownerInt); add = true; } } else { // Check if this player had another pet registered and clean up. // Only one pet is allowed. if (playerPetCache.TryGetValue(line.ownInt, out OwnerInfo)) { playerPetCache.Remove(line.ownInt); petPlayerCache.Remove(OwnerInfo.petInt); } add = true; } if (add) { OwnerInfo = new OwnerInfo(); OwnerInfo.ownerDsp = line.ownDsp; OwnerInfo.ownerInt = line.ownInt; OwnerInfo.ownerEntityType = line.ownEntityType; OwnerInfo.petDsp = line.srcDsp; OwnerInfo.petInt = line.srcInt; petPlayerCache.Add(line.srcInt, OwnerInfo); playerPetCache.Add(line.ownInt, OwnerInfo); } } }
private void ProcessNamesST(ParsedLine line) { // Source, Target: All independant ProcessSourceNames(line); ProcessTargetNames(line); }
public MasterSwing MatchDamage(ParsedLine line) { LinkedListNode<ShieldLine> slnNext = active.First; while (slnNext != null) { LinkedListNode<ShieldLine> cur = slnNext; ShieldLine sl = cur.Value; slnNext = slnNext.Next; // Examaple: // 13:09:26:09:31:31.2::Lorne Fellbane,P[201332730@6101294 Lorne Fellbane@todesfaelle],,*,HeLLCaT,P[201327748@7398668 HeLLCaT@phantom3535],Bilethorn Weapon,Pn.Nhw1351,Shield,,-1.3,0 // 13:09:26:09:31:31.2::Lorne Fellbane,P[201332730@6101294 Lorne Fellbane@todesfaelle],,*,HeLLCaT,P[201327748@7398668 HeLLCaT@phantom3535],Bilethorn Weapon,Pn.Nhw1351,Shield,,-10.9585,0 // 13:09:26:09:31:31.2::Lorne Fellbane,P[201332730@6101294 Lorne Fellbane@todesfaelle],HeLLCaT,P[201327748@7398668 HeLLCaT@phantom3535],,*,Bilethorn Weapon,Pn.Nhw1351,Poison,,1.3,6.5 // 13:09:26:09:31:31.2::Lorne Fellbane,P[201332730@6101294 Lorne Fellbane@todesfaelle],HeLLCaT,P[201327748@7398668 HeLLCaT@phantom3535],,*,Bilethorn Weapon,Pn.Nhw1351,Poison,,10.9585,54.7925 // Notice that the Source field doesn't always match... /* Odd case of zero damage: 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Shield,,-2,-0.484209 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Shield,,-2,-0.242104 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Fire,Dodge,0,0 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Fire,,0,0 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Fire,,0.484209,2 13:09:26:09:36:11.8::briserus,P[201401849@8271148 briserus@briserus],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Flaming Weapon,Pn.Mzftfj,Fire,Dodge,0.242104,2 */ /* Two Shield lines for one damage line: TODO: Handle this... 13:09:26:09:36:20.8::DRUGnROLL,P[200404637@6548010 DRUGnROLL@drugnroll],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Entangling Force,Pn.Oonws91,Shield,,-17.2139,-3.44278 13:09:26:09:36:20.8::DRUGnROLL,P[200404637@6548010 DRUGnROLL@drugnroll],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Entangling Force,Pn.Oonws91,Shield,,-340.835,0 13:09:26:09:36:20.8::Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],,*,,*,Health Steal,Pn.S6b30w1,HitPoints,,-0.0190611,0 13:09:26:09:36:20.8::Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],,*,,*,Health Steal,Pn.S6b30w1,HitPoints,,-0.117442,0 13:09:26:09:36:20.8::DRUGnROLL,P[200404637@6548010 DRUGnROLL@drugnroll],,*,Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],Entangling Force,Pn.Oonws91,Arcane,Critical,344.278,1721.39 13:09:26:09:36:20.9::Lord DopeVIII,P[200441364@6420568 Lord DopeVIII@lorddopeviii],,*,,*,Shielded Resurgence,Pn.Mrczs41,Null,ShowPowerDisplayName,0,0 */ // Compare if ((sl.line.evtInt == line.evtInt) && (sl.line.ownInt == line.ownInt) && // (sl.line.srcInt == line.srcInt) && (sl.line.tgtInt == line.tgtInt) && (line.type != "Shield") && (line.mag > 0.0) // <- Skip zero damage lines. ) { // Matched active.Remove(cur); return sl.ms; } else { // Check expired. TimeSpan diff = line.logInfo.detectedTime - sl.ms.Time; if (diff.TotalMilliseconds > 500) { // Drop old and unmatch shield lines. // Generally shield line should match in <= 100ms. active.Remove(cur); } } } return null; }
// Must match LogLineEventDelegate signature void oFormActMain_BeforeLogLineRead(bool isImport, LogLineEventArgs logInfo) { parsedLineCount++; if (logInfo.logLine.Length < 30 || logInfo.logLine[19] != ':' || logInfo.logLine[20] != ':') { logInfo.detectedType = Color.DarkGray.ToArgb(); errorLineCount++; return; } if (logInfo.detectedTime != curActionTime) { // Different times mean new action block, any pending actions won't be related to those of the new block curActionTime = logInfo.detectedTime; } ParsedLine pl = new ParsedLine(logInfo); if (pl.error) { logInfo.detectedType = Color.DarkGray.ToArgb(); errorLineCount++; return; } // Fix up the ParsedLine to be easy to process. ProcessBasic(pl); // Detect Player names.. if ( ! (playersCharacterFound || isImport ) ) { if (pl.ownEntityType == EntityType.Player) { if (playerCharacterNames.ContainsKey(pl.ownDsp)) { ActGlobals.charName = pl.ownDsp; playersCharacterFound = true; } } } // Do the real stuff.. ProcessAction(pl); }