1#![allow(non_snake_case)]
3use wowlab_engine_combat::CombatSystemBuilder;
4use wowlab_engine_gamedata::ResolvedGameData;
5use wowlab_engine_ports::ResolveDependencies;
6pub(crate) mod aberrant_spellforge;
7pub(crate) mod algethar_puzzle_box;
8pub(crate) mod all_devouring_nucleus;
9pub(crate) mod araz_ritual_forge;
10pub(crate) mod arcanoweave_cord;
11pub(crate) mod brand_ceaseless_ire;
12pub(crate) mod bursting_lightshard;
13pub(crate) mod candle_confidant;
14pub(crate) mod chromebustible_bomb_suit;
15pub(crate) mod darkfuse_medichopper;
16pub(crate) mod diamantine_voidcore;
17pub(crate) mod emberwing_feather;
18pub(crate) mod flarendo_pilot_light;
19pub(crate) mod foul_behemoth_chelicera;
20pub(crate) mod gallagio_bottle_service;
21pub(crate) mod gaze_of_the_alnseer;
22pub(crate) mod geargrinder_spare_keys;
23pub(crate) mod heart_of_ancient_hunger;
24pub(crate) mod high_speakers_accretion;
25pub(crate) mod house_of_cards;
26pub(crate) mod junkmaestro_mega_magnet;
27pub(crate) mod kuj0_flame_vents;
28pub(crate) mod light_company_guidon;
29pub(crate) mod locuswalkers_ribbon;
30pub(crate) mod loomithar_living_silk;
31pub(crate) mod mad_queens_mandate;
32pub(crate) mod mereldar_toll;
33pub(crate) mod mister_lock_n_stalk;
34pub(crate) mod overclocked_gear_a_rang;
35pub(crate) mod ovinax_mercurial_egg;
36pub(crate) mod perfidious_projector;
37pub(crate) mod radiant_plume;
38pub(crate) mod ringing_ritual_mud;
39pub(crate) mod signet_of_the_priory;
40pub(crate) mod sikrans_endless_arsenal;
41pub(crate) mod skarmorak_shard;
42pub(crate) mod skyterror_corrosive_organ;
43pub(crate) mod soulbinder_embrace;
44pub(crate) mod sporecallers_blooming_loop;
45pub(crate) mod spymasters_web;
46pub(crate) mod torq_big_red_button;
47pub(crate) mod treacherous_transmitter;
48pub(crate) mod umbral_plume;
49pub(crate) mod unyielding_netherprism;
50pub(crate) mod vaelgors_final_stare;
51pub(crate) mod vexie_pit_whistle;
52const SIMPLE_EQUIP_AURA_ITEMS: &[(u32, &str, &[u32])] = &[
53 (212_456, "Void Reapers Contract", &[444_067]),
54 (219_311, "Void Pactstone", &[443_537]),
55 (219_312, "Empowering Crystal Anubikkaj", &[443_538]),
56 (219_314, "Ara Kara Sacbrood", &[443_541]),
57 (219_305, "Carved Blazikon Wax", &[443_527]),
58 (219_307, "Remnant Of Darkness", &[443_530]),
59 (219_302, "Scrapsinger Symphony", &[443_414]),
60 (219_304, "Conductors Wax Whistle", &[443_525]),
61 (219_317, "Harvester Edict", &[451_055]),
62 (219_316, "Ceaseless Swarmgland", &[443_545]),
63 (219_315, "Refracting Aggression Module", &[443_544]),
64 (219_296, "Entropic Skardyn Core", &[443_380]),
65 (225_577, "Sureki Zealots Insignia", &[457_683]),
66 (225_578, "Seal Of The Poisoned Pact", &[457_815, 457_918]),
67 (228_411, "Cyrces Circlet", &[462_342]),
68 (219_297, "Cinderbrew Stein", &[446_648]),
69 (242_394, "Eradicating Arcanocore", &[1_233_384]),
70 (242_400, "Nexus Kings Command", &[1_232_776]),
71 (242_397, "Sigil Cosmic Hunt", &[1_235_360]),
72 (242_398, "Naazindhris Mystic Lash", &[1_235_387]),
73 (242_399, "Screams Forgotten Sky", &[1_235_272]),
74 (242_395, "Astral Antenna", &[1_234_714]),
75 (230_026, "Scrapfield 9001", &[466_671]),
76 (230_198, "Eye Of Kezan", &[469_888]),
77 (230_194, "Reverb Radio", &[471_567]),
78 (230_192, "Mugs Moxie Jug", &[471_548]),
79 (232_541, "Improvised Seaforium Pacemaker", &[1_218_714, 1_218_712]),
80 (232_545, "Gigazap Zap Cap", &[1_219_103]),
81 (230_199, "Zee Thug Hotline", &[1_217_356, 1_217_829]),
82 (219_321, "Cirral Concoctory", &[443_559]),
83 (219_295, "Sigil Algari Concordance", &[443_378]),
84];
85type ItemRegisterFn = fn(
86 CombatSystemBuilder,
87 &ResolvedGameData,
88 wowlab_engine_gamedata::ItemBudget,
89) -> CombatSystemBuilder;
90const ITEMS: &[(u32, ItemRegisterFn)] = &[
91 (220_202, spymasters_web::register),
92 (221_023, treacherous_transmitter::register),
93 (220_305, ovinax_mercurial_egg::register),
94 (212_454, mad_queens_mandate::register),
95 (212_451, aberrant_spellforge::register),
96 (219_300, skarmorak_shard::register),
97 (219_308, signet_of_the_priory::register),
98 (212_453, skyterror_corrosive_organ::register),
99 (219_915, foul_behemoth_chelicera::register),
100 (219_313, mereldar_toll::register),
101 (219_303, high_speakers_accretion::register),
102 (219_301, overclocked_gear_a_rang::register),
103 (219_310, bursting_lightshard::register),
104 (242_401, brand_ceaseless_ire::register),
105 (242_402, araz_ritual_forge::register),
106 (242_404, all_devouring_nucleus::register),
107 (242_392, diamantine_voidcore::register),
108 (242_396, unyielding_netherprism::register),
109 (242_403, perfidious_projector::register),
110 (242_393, loomithar_living_silk::register),
111 (242_391, soulbinder_embrace::register),
112 (230_027, house_of_cards::register),
113 (230_019, vexie_pit_whistle::register),
114 (230_190, torq_big_red_button::register),
115 (230_191, flarendo_pilot_light::register),
116 (230_188, gallagio_bottle_service::register),
117 (230_197, geargrinder_spare_keys::register),
118 (230_029, chromebustible_bomb_suit::register),
119 (230_193, mister_lock_n_stalk::register),
120 (230_189, junkmaestro_mega_magnet::register),
121 (232_542, darkfuse_medichopper::register),
122 (232_543, ringing_ritual_mud::register),
123 (232_546, kuj0_flame_vents::register),
124 (225_649, candle_confidant::register),
125 (212_449, sikrans_endless_arsenal::register),
126 (249_343, gaze_of_the_alnseer::register),
127 (260_235, umbral_plume::register),
128 (249_806, radiant_plume::register),
129 (239_664, arcanoweave_cord::register),
130 (249_346, vaelgors_final_stare::register),
131 (249_344, light_company_guidon::register),
132 (250_144, emberwing_feather::register),
133 (249_342, heart_of_ancient_hunger::register),
134 (249_809, locuswalkers_ribbon::register),
135 (268_290, sporecallers_blooming_loop::register),
136 (193_701, algethar_puzzle_box::register),
137];
138pub const REGISTERED_ITEMS: &[(u32, &str)] = &[
140 (220_202, "SPYMASTERS_WEB"),
141 (221_023, "TREACHEROUS_TRANSMITTER"),
142 (220_305, "OVINAX_MERCURIAL_EGG"),
143 (212_454, "MAD_QUEENS_MANDATE"),
144 (212_451, "ABERRANT_SPELLFORGE"),
145 (219_300, "SKARMORAK_SHARD"),
146 (219_308, "SIGNET_OF_THE_PRIORY"),
147 (212_453, "SKYTERROR_CORROSIVE_ORGAN"),
148 (212_456, "VOID_REAPERS_CONTRACT"),
149 (219_915, "FOUL_BEHEMOTH_CHELICERA"),
150 (219_313, "MERELDAR_TOLL"),
151 (219_303, "HIGH_SPEAKERS_ACCRETION"),
152 (219_311, "VOID_PACTSTONE"),
153 (219_312, "EMPOWERING_CRYSTAL_ANUBIKKAJ"),
154 (219_314, "ARA_KARA_SACBROOD"),
155 (219_305, "CARVED_BLAZIKON_WAX"),
156 (219_307, "REMNANT_OF_DARKNESS"),
157 (219_301, "OVERCLOCKED_GEAR_A_RANG"),
158 (219_302, "SCRAPSINGER_SYMPHONY"),
159 (219_304, "CONDUCTORS_WAX_WHISTLE"),
160 (219_317, "HARVESTER_EDICT"),
161 (219_316, "CEASELESS_SWARMGLAND"),
162 (219_310, "BURSTING_LIGHTSHARD"),
163 (219_315, "REFRACTING_AGGRESSION_MODULE"),
164 (219_296, "ENTROPIC_SKARDYN_CORE"),
165 (225_577, "SUREKI_ZEALOTS_INSIGNIA"),
166 (225_578, "SEAL_OF_THE_POISONED_PACT"),
167 (228_411, "CYRCES_CIRCLET"),
168 (219_297, "CINDERBREW_STEIN"),
169 (242_401, "BRAND_CEASELESS_IRE"),
170 (242_402, "ARAZ_RITUAL_FORGE"),
171 (242_404, "ALL_DEVOURING_NUCLEUS"),
172 (242_392, "DIAMANTINE_VOIDCORE"),
173 (242_394, "ERADICATING_ARCANOCORE"),
174 (242_400, "NEXUS_KINGS_COMMAND"),
175 (242_397, "SIGIL_COSMIC_HUNT"),
176 (242_398, "NAAZINDHRIS_MYSTIC_LASH"),
177 (242_399, "SCREAMS_FORGOTTEN_SKY"),
178 (242_395, "ASTRAL_ANTENNA"),
179 (242_396, "UNYIELDING_NETHERPRISM"),
180 (242_403, "PERFIDIOUS_PROJECTOR"),
181 (242_393, "LOOMITHAR_LIVING_SILK"),
182 (242_391, "SOULBINDER_EMBRACE"),
183 (230_027, "HOUSE_OF_CARDS"),
184 (230_019, "VEXIE_PIT_WHISTLE"),
185 (230_026, "SCRAPFIELD_9001"),
186 (230_190, "TORQ_BIG_RED_BUTTON"),
187 (230_191, "FLARENDO_PILOT_LIGHT"),
188 (230_198, "EYE_OF_KEZAN"),
189 (230_194, "REVERB_RADIO"),
190 (230_192, "MUGS_MOXIE_JUG"),
191 (230_188, "GALLAGIO_BOTTLE_SERVICE"),
192 (230_197, "GEARGRINDER_SPARE_KEYS"),
193 (230_029, "CHROMEBUSTIBLE_BOMB_SUIT"),
194 (230_193, "MISTER_LOCK_N_STALK"),
195 (230_189, "JUNKMAESTRO_MEGA_MAGNET"),
196 (232_541, "IMPROVISED_SEAFORIUM_PACEMAKER"),
197 (232_542, "DARKFUSE_MEDICHOPPER"),
198 (232_543, "RINGING_RITUAL_MUD"),
199 (232_545, "GIGAZAP_ZAP_CAP"),
200 (232_546, "KUJ0_FLAME_VENTS"),
201 (230_199, "ZEE_THUG_HOTLINE"),
202 (219_321, "CIRRAL_CONCOCTORY"),
203 (225_649, "CANDLE_CONFIDANT"),
204 (219_295, "SIGIL_ALGARI_CONCORDANCE"),
205 (212_449, "SIKRANS_ENDLESS_ARSENAL"),
206 (249_343, "GAZE_OF_THE_ALNSEER"),
207 (260_235, "UMBRAL_PLUME"),
208 (249_806, "RADIANT_PLUME"),
209 (239_664, "ARCANOWEAVE_CORD"),
210 (249_346, "VAELGORS_FINAL_STARE"),
211 (249_344, "LIGHT_COMPANY_GUIDON"),
212 (250_144, "EMBERWING_FEATHER"),
213 (249_342, "HEART_OF_ANCIENT_HUNGER"),
214 (249_809, "LOCUSWALKERS_RIBBON"),
215 (268_290, "SPORECALLERS_BLOOMING_LOOP"),
216 (193_701, "ALGETHAR_PUZZLE_BOX"),
217];
218pub(crate) const ITEM_RESOLVE_IDS: &[ResolveDependencies] = &[
219 ResolveDependencies::new(220_202, &[444_958, 444_959]),
220 ResolveDependencies::new(221_023, &[446_209, 449_946]),
221 ResolveDependencies::new(220_305, &[445_066, 445_560]),
222 ResolveDependencies::new(212_454, &[443_124, 443_128]),
223 ResolveDependencies::new(212_451, &[443_415, 445_619]),
224 ResolveDependencies::new(219_300, &[443_407, 443_409]),
225 ResolveDependencies::new(219_308, &[443_531, 450_877]),
226 ResolveDependencies::new(212_453, &[444_488, 444_489]),
227 ResolveDependencies::new(212_456, &[444_067]),
228 ResolveDependencies::new(219_915, &[444_258, 444_264]),
229 ResolveDependencies::new(219_313, &[450_561, 450_641]),
230 ResolveDependencies::new(219_303, &[443_415, 462_035]),
231 ResolveDependencies::new(219_311, &[443_537]),
232 ResolveDependencies::new(219_312, &[443_538]),
233 ResolveDependencies::new(219_314, &[443_541]),
234 ResolveDependencies::new(219_305, &[443_527]),
235 ResolveDependencies::new(219_307, &[443_530]),
236 ResolveDependencies::new(219_301, &[443_411, 446_764]),
237 ResolveDependencies::new(219_302, &[443_414]),
238 ResolveDependencies::new(219_304, &[443_525]),
239 ResolveDependencies::new(219_317, &[451_055]),
240 ResolveDependencies::new(219_316, &[443_545]),
241 ResolveDependencies::new(219_310, &[443_536, 450_916]),
242 ResolveDependencies::new(219_315, &[443_544]),
243 ResolveDependencies::new(219_296, &[443_380]),
244 ResolveDependencies::new(225_577, &[457_683]),
245 ResolveDependencies::new(225_578, &[457_815, 457_918]),
246 ResolveDependencies::new(228_411, &[462_342]),
247 ResolveDependencies::new(219_297, &[446_648]),
248 ResolveDependencies::new(242_401, &[1_235_225]),
249 ResolveDependencies::new(242_402, &[1_232_797, 1_232_802]),
250 ResolveDependencies::new(242_404, &[1_235_500]),
251 ResolveDependencies::new(242_392, &[1_234_996]),
252 ResolveDependencies::new(242_394, &[1_233_384]),
253 ResolveDependencies::new(242_400, &[1_232_776]),
254 ResolveDependencies::new(242_397, &[1_235_360]),
255 ResolveDependencies::new(242_398, &[1_235_387]),
256 ResolveDependencies::new(242_399, &[1_235_272]),
257 ResolveDependencies::new(242_395, &[1_234_714]),
258 ResolveDependencies::new(242_396, &[1_233_553, 1_233_556]),
259 ResolveDependencies::new(242_403, &[1_235_557, 1_244_636]),
260 ResolveDependencies::new(242_393, &[1_232_719, 1_232_721]),
261 ResolveDependencies::new(242_391, &[1_235_218, 1_235_425]),
262 ResolveDependencies::new(230_027, &[466_680, 466_681]),
263 ResolveDependencies::new(230_019, &[466_646, 466_652]),
264 ResolveDependencies::new(230_026, &[466_671]),
265 ResolveDependencies::new(230_190, &[470_042, 470_286]),
266 ResolveDependencies::new(230_191, &[471_057, 471_142]),
267 ResolveDependencies::new(230_198, &[469_888]),
268 ResolveDependencies::new(230_194, &[471_567]),
269 ResolveDependencies::new(230_192, &[471_548]),
270 ResolveDependencies::new(230_188, &[471_213, 471_214]),
271 ResolveDependencies::new(230_197, &[471_058, 471_059]),
272 ResolveDependencies::new(230_029, &[466_693, 466_810]),
273 ResolveDependencies::new(230_193, &[467_469, 467_485]),
274 ResolveDependencies::new(230_189, &[471_211, 471_212]),
275 ResolveDependencies::new(232_541, &[1_218_712, 1_218_714]),
276 ResolveDependencies::new(232_542, &[1_220_488, 1_220_605]),
277 ResolveDependencies::new(232_543, &[1_219_102, 1_221_145]),
278 ResolveDependencies::new(232_545, &[1_219_103]),
279 ResolveDependencies::new(232_546, &[1_218_716, 1_219_410]),
280 ResolveDependencies::new(230_199, &[1_217_356, 1_217_829]),
281 ResolveDependencies::new(219_321, &[443_559]),
282 ResolveDependencies::new(225_649, &[455_451]),
283 ResolveDependencies::new(219_295, &[443_378]),
284 ResolveDependencies::new(212_449, &[447_970]),
285 ResolveDependencies::new(249_343, &[1_256_896, 1_266_686, 1_266_687]),
286 ResolveDependencies::new(260_235, &[1_265_808, 1_265_809]),
287 ResolveDependencies::new(249_806, &[1_260_592, 1_260_615]),
288 ResolveDependencies::new(239_664, &[1_241_529, 1_241_530]),
289 ResolveDependencies::new(249_346, &[1_259_293, 1_260_459]),
290 ResolveDependencies::new(249_344, &[1_251_817, 1_259_633]),
291 ResolveDependencies::new(250_144, &[1_250_508]),
292 ResolveDependencies::new(249_342, &[1_251_822, 1_262_753]),
293 ResolveDependencies::new(249_809, &[1_259_314, 1_259_317, 1_268_058]),
294 ResolveDependencies::new(268_290, &[1_285_138, 1_286_135, 1_286_316]),
295 ResolveDependencies::new(193_701, &[383_781]),
296];
297pub(crate) const ITEM_USE_SPELLS: &[(u32, u32)] = &[
298 (220_202, 444_959),
299 (221_023, 449_946),
300 (220_305, 445_560),
301 (212_454, 443_124),
302 (212_451, 445_619),
303 (219_300, 443_407),
304 (219_308, 443_531),
305 (212_453, 444_489),
306 (219_915, 444_264),
307 (219_313, 450_561),
308 (219_303, 443_415),
309 (219_301, 443_411),
310 (219_310, 443_536),
311 (242_402, 1_232_802),
312 (242_396, 1_233_556),
313 (242_403, 1_244_636),
314 (242_393, 1_232_721),
315 (242_391, 1_235_425),
316 (230_027, 466_681),
317 (230_019, 466_652),
318 (230_190, 470_286),
319 (230_191, 471_142),
320 (230_188, 471_214),
321 (230_197, 471_059),
322 (230_029, 466_810),
323 (230_193, 467_485),
324 (230_189, 471_212),
325 (232_542, 1_220_488),
326 (232_543, 1_219_102),
327 (232_546, 1_218_716),
328 (225_649, 455_451),
329 (212_449, 447_970),
330 (249_346, 1_260_459),
331 (249_344, 1_259_633),
332 (250_144, 1_250_508),
333 (193_701, 383_781),
334];
335pub(crate) fn register_equipped(
336 mut builder: CombatSystemBuilder,
337 data: &ResolvedGameData,
338 equipped: &[wowlab_engine_ports::EquippedItem],
339) -> Result<CombatSystemBuilder, wowlab_engine_ports::EngineError> {
340 for item in equipped {
341 if let Some(&(_, register)) = ITEMS
342 .iter()
343 .find(|(registered_id, _)| *registered_id == item.item_id)
344 {
345 builder = register(builder, data, crate::items::item_budget(data, item)?);
346 }
347
348 if let Some(&(_, display, aura_ids)) = SIMPLE_EQUIP_AURA_ITEMS
349 .iter()
350 .find(|(registered_id, _, _)| *registered_id == item.item_id)
351 {
352 builder = crate::items::register_simple_equip_auras(
353 data,
354 display,
355 aura_ids,
356 || builder,
357 );
358 }
359
360 if let Some(&(_, use_spell)) = ITEM_USE_SPELLS
361 .iter()
362 .find(|(registered_id, _)| *registered_id == item.item_id)
363 {
364 builder = builder.item_use_spell(item.slot, use_spell);
365 }
366 }
367
368 builder = register_player_cast_hooks(builder, equipped);
369 builder = register_player_impact_hooks(builder, data, equipped);
370
371 Ok(builder)
372}
373const PLAYER_CAST_HOOKS: &[(u32, wowlab_engine_combat::CastHookFn)] = &[
374 (219_915, crate::hooks::items::foul_behemoth_chelicera::on_player_cast),
375 (242_404, crate::hooks::items::all_devouring_nucleus::on_player_cast),
376 (242_392, crate::hooks::items::diamantine_voidcore::on_player_cast),
377 (249_342, crate::hooks::items::heart_of_ancient_hunger::on_player_cast),
378 (249_809, crate::hooks::items::locuswalkers_ribbon::on_player_cast),
379];
380fn register_player_cast_hooks(
381 mut builder: CombatSystemBuilder,
382 equipped: &[wowlab_engine_ports::EquippedItem],
383) -> CombatSystemBuilder {
384 for item in equipped {
385 if let Some(&(_, hook)) = PLAYER_CAST_HOOKS
386 .iter()
387 .find(|(registered_id, _)| *registered_id == item.item_id)
388 {
389 builder = builder.on_player_cast(hook);
390 }
391 }
392
393 builder
394}
395type PlayerImpactHookEntry = (
396 u32,
397 Option<u32>,
398 wowlab_engine_combat::ImpactProcFn,
399 bool,
400 bool,
401 bool,
402);
403const PLAYER_IMPACT_HOOKS: &[PlayerImpactHookEntry] = &[
404 (
405 249_343,
406 Some(1_256_896),
407 crate::hooks::items::gaze_of_the_alnseer::on_player_impact,
408 false,
409 true,
410 false,
411 ),
412 (
413 239_664,
414 Some(1_241_529),
415 crate::hooks::items::arcanoweave_cord::on_player_impact,
416 false,
417 false,
418 false,
419 ),
420 (
421 268_290,
422 Some(1_285_138),
423 crate::hooks::items::sporecallers_blooming_loop::on_player_impact,
424 false,
425 false,
426 false,
427 ),
428];
429fn register_player_impact_hooks(
430 mut builder: CombatSystemBuilder,
431 data: &ResolvedGameData,
432 equipped: &[wowlab_engine_ports::EquippedItem],
433) -> CombatSystemBuilder {
434 for item in equipped {
435 if let Some(
436 &(_, driver_spell_id, hook, periodic_only, skip_periodic, crit_only),
437 ) = PLAYER_IMPACT_HOOKS
438 .iter()
439 .find(|(registered_id, ..)| *registered_id == item.item_id)
440 {
441 builder = builder
442 .register_impact_proc(wowlab_engine_combat::ImpactProc {
443 driver: driver_spell_id
444 .map_or_else(
445 wowlab_engine_combat::ProcDriver::default,
446 |driver| {
447 wowlab_engine_combat::ProcDriver::from_spell(
448 data,
449 driver,
450 wowlab_engine_combat::ProcTriggerSide::Caster,
451 )
452 },
453 ),
454 actor_filter: wowlab_engine_combat::ImpactActorFilter::Player,
455 chance: 1.0,
456 fire: hook,
457 spell_filter: None,
458 periodic_only,
459 skip_periodic,
460 crit_only,
461 });
462 }
463 }
464
465 builder
466}