Skip to content

Commit e573741

Browse files
committed
util: add basic support for CEs to encounter_tools
This is a basic initial attempt at supporting critical encounters and critical engagements from the encounter tools. It relies on the CE information we recently started generating from the xivapi, as well as the DirectorUpdate IDs pulled by hand. It does appear to work properly at least as far as finding encounters go. It does at least log the encounter name based off its English translation. There is likely more work required to verify that no other encounter logic breaks. Additionally, we might want to improve the make_timeline support to use the 0x21 log line as an entry check, since this is what we do in the timeline files that support critical encounters. This code was originally based on work from Valarnin, but its been heavily modified to now pull the CE data from the xivapi. This version only accepts CEs that match the zone we're in so it should have minimal chance of breaking other flows. I did end up hard coding the association of zone to encounter list, which could possibly be improved somehow. Signed-off-by: Jacob Keller <[email protected]>
1 parent cd7d847 commit e573741

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

util/logtools/encounter_tools.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
import BozjaDirectorIds from '../../resources/bozja_ce_map';
2+
import BozjaCEs from '../../resources/bozja_encounters';
13
import ContentType from '../../resources/content_type';
24
import DTFuncs from '../../resources/datetime';
35
import NetRegexes, { commonNetRegex } from '../../resources/netregexes';
46
import { UnreachableCode } from '../../resources/not_reached';
57
import PetData from '../../resources/pet_names';
8+
import SouthHornDirectorIds from '../../resources/south_horn_ce_map';
9+
import SouthHornCEs from '../../resources/south_horn_encounters';
610
import StringFuncs from '../../resources/stringhandlers';
11+
import ZadnorDirectorIds from '../../resources/zadnor_ce_map';
12+
import ZadnorCEs from '../../resources/zadnor_encounters';
13+
import ZoneId from '../../resources/zone_id';
714
import ZoneInfo from '../../resources/zone_info';
815
import { NetAnyMatches, NetMatches } from '../../types/net_matches';
916
import { CactbotBaseRegExp } from '../../types/net_trigger';
@@ -90,6 +97,7 @@ export class EncounterFinder {
9097
currentZone: ZoneEncInfo = {};
9198
currentFight: FightEncInfo = {};
9299
currentSeal?: string;
100+
currentCE?: string;
93101
zoneInfo?: typeof ZoneInfo[number];
94102

95103
haveWon = false;
@@ -112,6 +120,7 @@ export class EncounterFinder {
112120

113121
sealRegexes: Array<CactbotBaseRegExp<'GameLog'>> = [];
114122
unsealRegexes: Array<CactbotBaseRegExp<'GameLog'>> = [];
123+
ceRegex: CactbotBaseRegExp<'ActorControl'>;
115124

116125
initializeZone(): void {
117126
this.currentZone = {};
@@ -152,6 +161,8 @@ export class EncounterFinder {
152161
const line = `.*?${lang}.*?`;
153162
this.unsealRegexes.push(NetRegexes.message({ line: line }));
154163
}
164+
165+
this.ceRegex = NetRegexes.network6d({ command: '80000014' });
155166
}
156167

157168
skipZone(): boolean {
@@ -324,6 +335,12 @@ export class EncounterFinder {
324335
return;
325336
}
326337
}
338+
339+
const ce = this.ceRegex.exec(line)?.groups;
340+
341+
if (ce) {
342+
this.onCE(line, ce);
343+
}
327344
}
328345

329346
// start/endZone always bracket all fights and seals.
@@ -340,7 +357,7 @@ export class EncounterFinder {
340357
}
341358
onStartFight(
342359
line: string,
343-
matches: NetMatches['Ability' | 'GameLog' | 'SystemLogMessage' | 'InCombat'],
360+
matches: NetMatches['Ability' | 'ActorControl' | 'GameLog' | 'SystemLogMessage' | 'InCombat'],
344361
fightName?: string,
345362
sealId?: string,
346363
): void {
@@ -380,6 +397,44 @@ export class EncounterFinder {
380397
this.onEndFight(line, matches, 'Unseal');
381398
this.currentSeal = undefined;
382399
}
400+
401+
onCE(line: string, matches: NetMatches['ActorControl']): void {
402+
let validDirectorIds = undefined;
403+
let validCEs = undefined;
404+
if (this.currentZone.zoneId === ZoneId.TheBozjanSouthernFront) {
405+
validDirectorIds = BozjaDirectorIds;
406+
validCEs = BozjaCEs;
407+
} else if (this.currentZone.zoneId === ZoneId.Zadnor) {
408+
validDirectorIds = ZadnorDirectorIds;
409+
validCEs = ZadnorCEs;
410+
} else if (this.currentZone.zoneId === ZoneId.TheOccultCrescentSouthHorn) {
411+
validDirectorIds = SouthHornDirectorIds;
412+
validCEs = SouthHornCEs;
413+
} else {
414+
return;
415+
}
416+
417+
if (matches.data0 === '00') {
418+
this.onEndFight(line, matches, 'CE End');
419+
this.currentCE = undefined;
420+
} else {
421+
const id = matches.data0;
422+
const ceKey = validDirectorIds[id];
423+
if (ceKey === undefined) {
424+
// Unrecognized Director ID value
425+
return;
426+
}
427+
const ceInfo = validCEs[ceKey];
428+
if (ceInfo === undefined) {
429+
// Unexpected missing key
430+
return;
431+
}
432+
const ceName = ceInfo.name.en;
433+
434+
this.currentCE = id;
435+
this.onStartFight(line, matches, ceName);
436+
}
437+
}
383438
}
384439

385440
class EncounterCollector extends EncounterFinder {

0 commit comments

Comments
 (0)