From 91306d8c22fb458df195a3fac81433eb3339789a Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 3 Aug 2024 07:11:49 +0100 Subject: [PATCH] Migrate misdat.cpp data to TSV --- CMake/Assets.cmake | 1 + Source/effects.h | 2 +- Source/misdat.cpp | 434 ++++++++++++++++++++--------- Source/misdat.h | 16 +- Source/spelldat.h | 2 + assets/txtdata/missiles/misdat.tsv | 109 ++++++++ 6 files changed, 428 insertions(+), 136 deletions(-) create mode 100644 assets/txtdata/missiles/misdat.tsv diff --git a/CMake/Assets.cmake b/CMake/Assets.cmake index 263a1993c..c9e52fbcf 100644 --- a/CMake/Assets.cmake +++ b/CMake/Assets.cmake @@ -163,6 +163,7 @@ set(devilutionx_assets txtdata/items/item_suffixes.tsv txtdata/items/itemdat.tsv txtdata/items/unique_itemdat.tsv + txtdata/missiles/misdat.tsv txtdata/missiles/missile_sprites.tsv txtdata/monsters/monstdat.tsv txtdata/monsters/unique_monstdat.tsv diff --git a/Source/effects.h b/Source/effects.h index 3ff45e876..a81420855 100644 --- a/Source/effects.h +++ b/Source/effects.h @@ -1030,7 +1030,7 @@ enum class SfxID : int16_t { CryptDoorOpen, CryptDoorClose, - LAST = SfxID::CryptDoorClose, + LAST = CryptDoorClose, None = -1, }; diff --git a/Source/misdat.cpp b/Source/misdat.cpp index 8fa823a9f..e291afe1e 100644 --- a/Source/misdat.cpp +++ b/Source/misdat.cpp @@ -27,131 +27,6 @@ namespace devilution { -namespace { -constexpr auto Physical = MissileDataFlags::Physical; -constexpr auto Fire = MissileDataFlags::Fire; -constexpr auto Lightning = MissileDataFlags::Lightning; -constexpr auto Magic = MissileDataFlags::Magic; -constexpr auto Acid = MissileDataFlags::Acid; -constexpr auto Arrow = MissileDataFlags::Arrow; -constexpr auto Invisible = MissileDataFlags::Invisible; -} // namespace - -/** Data related to each missile ID. */ -const MissileData MissilesData[] = { - // clang-format off -// id mAddProc, mProc, mlSFX, miSFX, mFileNum, flags, MovementDistribution; -/*Arrow*/ { &AddArrow, &ProcessArrow, SfxID::None, SfxID::None, MissileGraphicID::Arrow, Physical | Arrow, MissileMovementDistribution::Blockable }, -/*Firebolt*/ { &AddFirebolt, &ProcessGenericProjectile, SfxID::SpellFirebolt, SfxID::SpellFireHit, MissileGraphicID::Fireball, Fire, MissileMovementDistribution::Blockable }, -/*Guardian*/ { &AddGuardian, &ProcessGuardian, SfxID::SpellGuardian, SfxID::None, MissileGraphicID::Guardian, Physical, MissileMovementDistribution::Disabled }, -/*Phasing*/ { &AddPhasing, &ProcessTeleport, SfxID::SpellTeleport, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*NovaBall*/ { &AddNovaBall, &ProcessNovaBall, SfxID::None, SfxID::None, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Unblockable }, -/*FireWall*/ { &AddFireWall, &ProcessFireWall, SfxID::SpellFireWall, SfxID::SpellFireHit, MissileGraphicID::FireWall, Fire, MissileMovementDistribution::Disabled }, -/*Fireball*/ { &AddFireball, &ProcessFireball, SfxID::SpellFirebolt, SfxID::SpellFireHit, MissileGraphicID::Fireball, Fire, MissileMovementDistribution::Blockable }, -/*LightningControl*/ { &AddLightningControl, &ProcessLightningControl, SfxID::None, SfxID::None, MissileGraphicID::Lightning, Lightning | Invisible, MissileMovementDistribution::Disabled }, -/*Lightning*/ { &AddLightning, &ProcessLightning, SfxID::SpellLightning, SfxID::SpellLightningHit, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Disabled }, -/*MagmaBallExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::None, SfxID::None, MissileGraphicID::MagmaBallExplosion, Physical, MissileMovementDistribution::Disabled }, -/*TownPortal*/ { &AddTownPortal, &ProcessTownPortal, SfxID::SpellPortal, SfxID::None, MissileGraphicID::TownPortal, Magic, MissileMovementDistribution::Disabled }, -/*FlashBottom*/ { &AddFlashBottom, &ProcessFlashBottom, SfxID::SpellNova, SfxID::SpellLightningHit, MissileGraphicID::FlashBottom, Magic, MissileMovementDistribution::Disabled }, -/*FlashTop*/ { &AddFlashTop, &ProcessFlashTop, SfxID::None, SfxID::None, MissileGraphicID::FlashTop, Magic, MissileMovementDistribution::Disabled }, -/*ManaShield*/ { &AddManaShield, nullptr, SfxID::SpellManaShield, SfxID::None, MissileGraphicID::ManaShield, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*FlameWave*/ { &AddFlameWave, &ProcessFlameWave, SfxID::None, SfxID::None, MissileGraphicID::FireWall, Fire, MissileMovementDistribution::Unblockable }, -/*ChainLightning*/ { &AddChainLightning, &ProcessChainLightning, SfxID::SpellLightning, SfxID::SpellLightningHit, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Disabled }, -/*ChainBall*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Disabled }, -/*BloodHit*/ { nullptr, nullptr, SfxID::SpellBloodStar, SfxID::SpellBloodStarHit, MissileGraphicID::BloodHit, Physical, MissileMovementDistribution::Disabled }, -/*BoneHit*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::BoneHit, Physical, MissileMovementDistribution::Disabled }, -/*MetalHit*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::MetalHit, Physical, MissileMovementDistribution::Disabled }, -/*Rhino*/ { &AddRhino, &ProcessRhino, SfxID::None, SfxID::None, MissileGraphicID::None, Physical, MissileMovementDistribution::Blockable }, -/*MagmaBall*/ { &AddMagmaBall, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::MagmaBall, Fire, MissileMovementDistribution::Blockable }, -/*ThinLightningControl*/ { &AddLightningControl, &ProcessLightningControl, SfxID::None, SfxID::None, MissileGraphicID::ThinLightning, Lightning | Invisible, MissileMovementDistribution::Disabled }, -/*ThinLightning*/ { &AddLightning, &ProcessLightning, SfxID::None, SfxID::None, MissileGraphicID::ThinLightning, Lightning, MissileMovementDistribution::Disabled }, -/*BloodStar*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::BloodStar, Magic, MissileMovementDistribution::Blockable }, -/*BloodStarExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::None, SfxID::None, MissileGraphicID::BloodStarExplosion, Magic, MissileMovementDistribution::Disabled }, -/*Teleport*/ { &AddTeleport, &ProcessTeleport, SfxID::SpellElemental, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*FireArrow*/ { &AddElementalArrow, &ProcessElementalArrow, SfxID::None, SfxID::None, MissileGraphicID::FireArrow, Fire | Arrow, MissileMovementDistribution::Blockable }, -/*DoomSerpents*/ { nullptr, nullptr, SfxID::SpellDoomSerpents, SfxID::None, MissileGraphicID::DoomSerpents, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*FireOnly*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::FireWall, Fire, MissileMovementDistribution::Disabled }, -/*StoneCurse*/ { &AddStoneCurse, &ProcessStoneCurse, SfxID::SpellStoneCurse, SfxID::None, MissileGraphicID::None, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*BloodRitual*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical, MissileMovementDistribution::Disabled }, -/*Invisibility*/ { nullptr, nullptr, SfxID::SpellInvisibility, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Golem*/ { &AddGolem, nullptr, SfxID::SpellGolem, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Etherealize*/ { nullptr, nullptr, SfxID::SpellEtherealize, SfxID::None, MissileGraphicID::Etherealize, Physical, MissileMovementDistribution::Disabled }, -/*Spurt*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::Spurt, Physical, MissileMovementDistribution::Disabled }, -/*ApocalypseBoom*/ { &AddApocalypseBoom, &ProcessApocalypseBoom, SfxID::None, SfxID::None, MissileGraphicID::ApocalypseBoom, Physical, MissileMovementDistribution::Disabled }, -/*Healing*/ { &AddHealing, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*FireWallControl*/ { &AddFireWallControl, &ProcessFireWallControl, SfxID::None, SfxID::None, MissileGraphicID::FireWall, Fire | Invisible, MissileMovementDistribution::Disabled }, -/*Infravision*/ { &AddInfravision, &ProcessInfravision, SfxID::SpellInfravision, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Identify*/ { &AddIdentify, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*FlameWaveControl*/ { &AddFlameWaveControl, &ProcessFlameWaveControl, SfxID::SpellFlameWave, SfxID::None, MissileGraphicID::FireWall, Fire, MissileMovementDistribution::Disabled }, -/*Nova*/ { &AddNova, &ProcessNova, SfxID::SpellNova, SfxID::None, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Disabled }, -/*Rage*/ { &AddRage, &ProcessRage, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Apocalypse*/ { &AddApocalypse, &ProcessApocalypse, SfxID::SpellApocalypse, SfxID::None, MissileGraphicID::ApocalypseBoom, Magic, MissileMovementDistribution::Disabled }, -/*ItemRepair*/ { &AddItemRepair, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*StaffRecharge*/ { &AddStaffRecharge, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*TrapDisarm*/ { &AddTrapDisarm, nullptr, SfxID::SpellTrapDisarm, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Inferno*/ { &AddInferno, &ProcessInferno, SfxID::SpellInferno, SfxID::None, MissileGraphicID::Inferno, Fire, MissileMovementDistribution::Disabled }, -/*InfernoControl*/ { &AddInfernoControl, &ProcessInfernoControl, SfxID::None, SfxID::None, MissileGraphicID::None, Fire | Invisible, MissileMovementDistribution::Disabled }, -/*FireMan*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical, MissileMovementDistribution::Blockable }, -/*Krull*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::Krull, Fire | Arrow, MissileMovementDistribution::Blockable }, -/*ChargedBolt*/ { &AddChargedBolt, &ProcessChargedBolt, SfxID::SpellChargedBolt, SfxID::None, MissileGraphicID::ChargedBolt, Lightning, MissileMovementDistribution::Blockable }, -/*HolyBolt*/ { &AddHolyBolt, &ProcessHolyBolt, SfxID::SpellHolyBolt, SfxID::SpellLightningHit, MissileGraphicID::HolyBolt, Physical, MissileMovementDistribution::Blockable }, -/*Resurrect*/ { &AddResurrect, nullptr, SfxID::None, SfxID::SpellResurrect, MissileGraphicID::None, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*Telekinesis*/ { &AddTelekinesis, nullptr, SfxID::SpellEtherealize, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*LightningArrow*/ { &AddElementalArrow, &ProcessElementalArrow, SfxID::None, SfxID::None, MissileGraphicID::LightningArrow, Lightning | Arrow, MissileMovementDistribution::Blockable }, -/*Acid*/ { &AddAcid, &ProcessGenericProjectile, SfxID::SpellAcid, SfxID::None, MissileGraphicID::Acid, Acid, MissileMovementDistribution::Blockable }, -/*AcidSplat*/ { &AddMissileExplosion, &ProcessAcidSplate, SfxID::None, SfxID::None, MissileGraphicID::AcidSplat, Acid, MissileMovementDistribution::Disabled }, -/*AcidPuddle*/ { &AddAcidPuddle, &ProcessAcidPuddle, SfxID::SpellPuddle, SfxID::None, MissileGraphicID::AcidPuddle, Acid, MissileMovementDistribution::Disabled }, -/*HealOther*/ { &AddHealOther, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Elemental*/ { &AddElemental, &ProcessElemental, SfxID::SpellElemental, SfxID::None, MissileGraphicID::Elemental, Fire, MissileMovementDistribution::Unblockable }, -/*ResurrectBeam*/ { &AddResurrectBeam, &ProcessResurrectBeam, SfxID::None, SfxID::None, MissileGraphicID::Resurrect, Physical, MissileMovementDistribution::Disabled }, -/*BoneSpirit*/ { &AddBoneSpirit, &ProcessBoneSpirit, SfxID::SpellBoneSpirit, SfxID::SpellBoneSpiritHit, MissileGraphicID::BoneSpirit, Magic, MissileMovementDistribution::Blockable }, -/*WeaponExplosion*/ { &AddWeaponExplosion, &ProcessWeaponExplosion, SfxID::None, SfxID::None, MissileGraphicID::None, Physical, MissileMovementDistribution::Disabled }, -/*RedPortal*/ { &AddRedPortal, &ProcessRedPortal, SfxID::SpellPortal, SfxID::None, MissileGraphicID::RedPortal, Physical, MissileMovementDistribution::Disabled }, -/*DiabloApocalypseBoom*/ { &AddApocalypseBoom, &ProcessApocalypseBoom, SfxID::None, SfxID::None, MissileGraphicID::DiabloApocalypseBoom, Physical, MissileMovementDistribution::Disabled }, -/*DiabloApocalypse*/ { &AddDiabloApocalypse, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Mana*/ { &AddMana, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Magi*/ { &AddMagi, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*LightningWall*/ { &AddLightningWall, &ProcessLightningWall, SfxID::SpellLightningWall, SfxID::SpellLightningHit, MissileGraphicID::Lightning, Lightning, MissileMovementDistribution::Disabled }, -/*LightningWallControl*/ { &AddFireWallControl, &ProcessLightningWallControl, SfxID::None, SfxID::None, MissileGraphicID::Lightning, Lightning | Invisible, MissileMovementDistribution::Disabled }, -/*Immolation*/ { &AddNova, &ProcessImmolation, SfxID::SpellFirebolt, SfxID::SpellFireHit, MissileGraphicID::Fireball, Fire, MissileMovementDistribution::Disabled }, -/*SpectralArrow*/ { &AddSpectralArrow, &ProcessSpectralArrow, SfxID::None, SfxID::None, MissileGraphicID::Arrow, Physical | Arrow, MissileMovementDistribution::Disabled }, -/*FireballBow*/ { &AddImmolation, &ProcessFireball, SfxID::ShootFireballBow, SfxID::SpellFireHit, MissileGraphicID::Fireball, Fire, MissileMovementDistribution::Blockable }, -/*LightningBow*/ { &AddLightningBow, &ProcessLightningBow, SfxID::ShootFireballBow, SfxID::None, MissileGraphicID::Lightning, Lightning | Invisible, MissileMovementDistribution::Disabled }, -/*ChargedBoltBow*/ { &AddChargedBoltBow, &ProcessChargedBolt, SfxID::SpellChargedBolt, SfxID::None, MissileGraphicID::ChargedBolt, Lightning, MissileMovementDistribution::Blockable }, -/*HolyBoltBow*/ { &AddHolyBolt, &ProcessHolyBolt, SfxID::SpellHolyBolt, SfxID::SpellLightningHit, MissileGraphicID::HolyBolt, Physical, MissileMovementDistribution::Blockable }, -/*Warp*/ { &AddWarp, &ProcessTeleport, SfxID::SpellEtherealize, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Reflect*/ { &AddReflect, nullptr, SfxID::SpellManaShield, SfxID::None, MissileGraphicID::Reflect, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Berserk*/ { &AddBerserk, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*RingOfFire*/ { &AddRingOfFire, &ProcessRingOfFire, SfxID::None, SfxID::None, MissileGraphicID::FireWall, Fire | Invisible, MissileMovementDistribution::Disabled }, -/*StealPotions*/ { &AddStealPotions, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*StealMana*/ { &AddStealMana, nullptr, SfxID::SpellEnd, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*RingOfLightning*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::Lightning, Lightning | Invisible, MissileMovementDistribution::Disabled }, -/*Search*/ { &AddSearch, &ProcessSearch, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Aura*/ { nullptr, nullptr, SfxID::None, SfxID::SpellLightningHit, MissileGraphicID::FlashBottom, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*Aura2*/ { nullptr, nullptr, SfxID::None, SfxID::None, MissileGraphicID::FlashTop, Magic | Invisible, MissileMovementDistribution::Disabled }, -/*SpiralFireball*/ { nullptr, nullptr, SfxID::SpellFirebolt, SfxID::SpellFireHit, MissileGraphicID::Fireball, Fire, MissileMovementDistribution::Disabled }, -/*RuneOfFire*/ { &AddRuneOfFire, &ProcessRune, SfxID::None, SfxID::None, MissileGraphicID::Rune, Physical, MissileMovementDistribution::Disabled }, -/*RuneOfLight*/ { &AddRuneOfLight, &ProcessRune, SfxID::None, SfxID::None, MissileGraphicID::Rune, Physical, MissileMovementDistribution::Disabled }, -/*RuneOfNova*/ { &AddRuneOfNova, &ProcessRune, SfxID::None, SfxID::None, MissileGraphicID::Rune, Physical, MissileMovementDistribution::Disabled }, -/*RuneOfImmolation*/ { &AddRuneOfImmolation, &ProcessRune, SfxID::None, SfxID::None, MissileGraphicID::Rune, Physical, MissileMovementDistribution::Disabled }, -/*RuneOfStone*/ { &AddRuneOfStone, &ProcessRune, SfxID::None, SfxID::None, MissileGraphicID::Rune, Physical, MissileMovementDistribution::Disabled }, -/*BigExplosion*/ { &AddBigExplosion, &ProcessBigExplosion, SfxID::BigExplosion, SfxID::BigExplosion, MissileGraphicID::BigExplosion, Fire, MissileMovementDistribution::Disabled }, -/*HorkSpawn*/ { &AddHorkSpawn, &ProcessHorkSpawn, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*Jester*/ { &AddJester, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*OpenNest*/ { &AddOpenNest, nullptr, SfxID::None, SfxID::None, MissileGraphicID::None, Physical | Invisible, MissileMovementDistribution::Disabled }, -/*OrangeFlare*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::OrangeFlare, Magic, MissileMovementDistribution::Blockable }, -/*BlueFlare*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::BlueFlare2, Magic, MissileMovementDistribution::Blockable }, -/*RedFlare*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::RedFlare, Magic, MissileMovementDistribution::Blockable }, -/*YellowFlare*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::YellowFlare, Magic, MissileMovementDistribution::Blockable }, -/*BlueFlare2*/ { &AddGenericMagicMissile, &ProcessGenericProjectile, SfxID::None, SfxID::None, MissileGraphicID::BlueFlare2, Magic, MissileMovementDistribution::Blockable }, -/*YellowExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::SpellFireHit, SfxID::None, MissileGraphicID::YellowFlareExplosion, Physical, MissileMovementDistribution::Disabled }, -/*RedExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::SpellFireHit, SfxID::None, MissileGraphicID::RedFlareExplosion, Physical, MissileMovementDistribution::Disabled }, -/*BlueExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::SpellFireHit, SfxID::None, MissileGraphicID::BlueFlareExplosion, Physical, MissileMovementDistribution::Disabled }, -/*BlueExplosion2*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::SpellFireHit, SfxID::None, MissileGraphicID::BlueFlareExplosion2, Physical, MissileMovementDistribution::Disabled }, -/*OrangeExplosion*/ { &AddMissileExplosion, &ProcessMissileExplosion, SfxID::SpellFireHit, SfxID::None, MissileGraphicID::OrangeFlareExplosion, Physical, MissileMovementDistribution::Disabled }, - // clang-format on -}; - namespace { /** Data related to each missile graphic ID. */ @@ -159,6 +34,9 @@ std::vector MissileSpriteData; std::vector> MissileAnimDelays; std::vector> MissileAnimLengths; +/** Data related to each missile ID. */ +std::vector MissilesData; + size_t ToIndex(std::vector> &all, const std::array &value) { for (size_t i = 0; i < all.size(); ++i) { @@ -176,6 +54,71 @@ tl::expected ParseMissileGraphicsFlag(std::st return tl::make_unexpected("Unknown enum value"); } +tl::expected ParseMissileGraphicID(std::string_view value) +{ + if (value.empty()) return MissileGraphicID::None; + if (value == "Arrow") return MissileGraphicID::Arrow; + if (value == "Fireball") return MissileGraphicID::Fireball; + if (value == "Guardian") return MissileGraphicID::Guardian; + if (value == "Lightning") return MissileGraphicID::Lightning; + if (value == "FireWall") return MissileGraphicID::FireWall; + if (value == "MagmaBallExplosion") return MissileGraphicID::MagmaBallExplosion; + if (value == "TownPortal") return MissileGraphicID::TownPortal; + if (value == "FlashBottom") return MissileGraphicID::FlashBottom; + if (value == "FlashTop") return MissileGraphicID::FlashTop; + if (value == "ManaShield") return MissileGraphicID::ManaShield; + if (value == "BloodHit") return MissileGraphicID::BloodHit; + if (value == "BoneHit") return MissileGraphicID::BoneHit; + if (value == "MetalHit") return MissileGraphicID::MetalHit; + if (value == "FireArrow") return MissileGraphicID::FireArrow; + if (value == "DoomSerpents") return MissileGraphicID::DoomSerpents; + if (value == "Golem") return MissileGraphicID::Golem; + if (value == "Spurt") return MissileGraphicID::Spurt; + if (value == "ApocalypseBoom") return MissileGraphicID::ApocalypseBoom; + if (value == "StoneCurseShatter") return MissileGraphicID::StoneCurseShatter; + if (value == "BigExplosion") return MissileGraphicID::BigExplosion; + if (value == "Inferno") return MissileGraphicID::Inferno; + if (value == "ThinLightning") return MissileGraphicID::ThinLightning; + if (value == "BloodStar") return MissileGraphicID::BloodStar; + if (value == "BloodStarExplosion") return MissileGraphicID::BloodStarExplosion; + if (value == "MagmaBall") return MissileGraphicID::MagmaBall; + if (value == "Krull") return MissileGraphicID::Krull; + if (value == "ChargedBolt") return MissileGraphicID::ChargedBolt; + if (value == "HolyBolt") return MissileGraphicID::HolyBolt; + if (value == "HolyBoltExplosion") return MissileGraphicID::HolyBoltExplosion; + if (value == "LightningArrow") return MissileGraphicID::LightningArrow; + if (value == "FireArrowExplosion") return MissileGraphicID::FireArrowExplosion; + if (value == "Acid") return MissileGraphicID::Acid; + if (value == "AcidSplat") return MissileGraphicID::AcidSplat; + if (value == "AcidPuddle") return MissileGraphicID::AcidPuddle; + if (value == "Etherealize") return MissileGraphicID::Etherealize; + if (value == "Elemental") return MissileGraphicID::Elemental; + if (value == "Resurrect") return MissileGraphicID::Resurrect; + if (value == "BoneSpirit") return MissileGraphicID::BoneSpirit; + if (value == "RedPortal") return MissileGraphicID::RedPortal; + if (value == "DiabloApocalypseBoom") return MissileGraphicID::DiabloApocalypseBoom; + if (value == "BloodStarBlue") return MissileGraphicID::BloodStarBlue; + if (value == "BloodStarBlueExplosion") return MissileGraphicID::BloodStarBlueExplosion; + if (value == "BloodStarYellow") return MissileGraphicID::BloodStarYellow; + if (value == "BloodStarYellowExplosion") return MissileGraphicID::BloodStarYellowExplosion; + if (value == "BloodStarRed") return MissileGraphicID::BloodStarRed; + if (value == "BloodStarRedExplosion") return MissileGraphicID::BloodStarRedExplosion; + if (value == "HorkSpawn") return MissileGraphicID::HorkSpawn; + if (value == "Reflect") return MissileGraphicID::Reflect; + if (value == "OrangeFlare") return MissileGraphicID::OrangeFlare; + if (value == "BlueFlare") return MissileGraphicID::BlueFlare; + if (value == "RedFlare") return MissileGraphicID::RedFlare; + if (value == "YellowFlare") return MissileGraphicID::YellowFlare; + if (value == "Rune") return MissileGraphicID::Rune; + if (value == "YellowFlareExplosion") return MissileGraphicID::YellowFlareExplosion; + if (value == "BlueFlareExplosion") return MissileGraphicID::BlueFlareExplosion; + if (value == "RedFlareExplosion") return MissileGraphicID::RedFlareExplosion; + if (value == "BlueFlare2") return MissileGraphicID::BlueFlare2; + if (value == "OrangeFlareExplosion") return MissileGraphicID::OrangeFlareExplosion; + if (value == "BlueFlareExplosion2") return MissileGraphicID::BlueFlareExplosion2; + return tl::make_unexpected("Unknown enum value"); +} + void LoadMissileSpriteData() { const std::string_view filename = "txtdata\\missiles\\missile_sprites.tsv"; @@ -190,7 +133,9 @@ void LoadMissileSpriteData() for (DataFileRecord record : dataFile) { RecordReader reader { record, filename }; MissileFileData &item = MissileSpriteData.emplace_back(); - reader.advance(); // skip id + MissileGraphicID id; + reader.read("id", id, ParseMissileGraphicID); + assert(static_cast(id) + 1 == MissileSpriteData.size()); reader.readInt("width", item.animWidth); reader.readInt("width2", item.animWidth2); reader.readString("name", item.name); @@ -210,6 +155,237 @@ void LoadMissileSpriteData() MissileAnimLengths.shrink_to_fit(); } +tl::expected ParseMissileDataFlag(std::string_view value) +{ + if (value == "Physical") return MissileDataFlags::Physical; + if (value == "Fire") return MissileDataFlags::Fire; + if (value == "Lightning") return MissileDataFlags::Lightning; + if (value == "Magic") return MissileDataFlags::Magic; + if (value == "Acid") return MissileDataFlags::Acid; + if (value == "Arrow") return MissileDataFlags::Arrow; + if (value == "Invisible") return MissileDataFlags::Invisible; + return tl::make_unexpected("Unknown enum value"); +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +tl::expected ParseMissileAddFn(std::string_view value) +{ + if (value.empty()) return nullptr; + if (value == "AddOpenNest") return AddOpenNest; + if (value == "AddRuneOfFire") return AddRuneOfFire; + if (value == "AddRuneOfLight") return AddRuneOfLight; + if (value == "AddRuneOfNova") return AddRuneOfNova; + if (value == "AddRuneOfImmolation") return AddRuneOfImmolation; + if (value == "AddRuneOfStone") return AddRuneOfStone; + if (value == "AddReflect") return AddReflect; + if (value == "AddBerserk") return AddBerserk; + if (value == "AddHorkSpawn") return AddHorkSpawn; + if (value == "AddJester") return AddJester; + if (value == "AddStealPotions") return AddStealPotions; + if (value == "AddStealMana") return AddStealMana; + if (value == "AddSpectralArrow") return AddSpectralArrow; + if (value == "AddWarp") return AddWarp; + if (value == "AddLightningWall") return AddLightningWall; + if (value == "AddBigExplosion") return AddBigExplosion; + if (value == "AddImmolation") return AddImmolation; + if (value == "AddLightningBow") return AddLightningBow; + if (value == "AddMana") return AddMana; + if (value == "AddMagi") return AddMagi; + if (value == "AddRingOfFire") return AddRingOfFire; + if (value == "AddSearch") return AddSearch; + if (value == "AddChargedBoltBow") return AddChargedBoltBow; + if (value == "AddElementalArrow") return AddElementalArrow; + if (value == "AddArrow") return AddArrow; + if (value == "AddPhasing") return AddPhasing; + if (value == "AddFirebolt") return AddFirebolt; + if (value == "AddMagmaBall") return AddMagmaBall; + if (value == "AddTeleport") return AddTeleport; + if (value == "AddNovaBall") return AddNovaBall; + if (value == "AddFireWall") return AddFireWall; + if (value == "AddFireball") return AddFireball; + if (value == "AddLightningControl") return AddLightningControl; + if (value == "AddLightning") return AddLightning; + if (value == "AddMissileExplosion") return AddMissileExplosion; + if (value == "AddWeaponExplosion") return AddWeaponExplosion; + if (value == "AddTownPortal") return AddTownPortal; + if (value == "AddFlashBottom") return AddFlashBottom; + if (value == "AddFlashTop") return AddFlashTop; + if (value == "AddManaShield") return AddManaShield; + if (value == "AddFlameWave") return AddFlameWave; + if (value == "AddGuardian") return AddGuardian; + if (value == "AddChainLightning") return AddChainLightning; + if (value == "AddRhino") return AddRhino; + if (value == "AddGenericMagicMissile") return AddGenericMagicMissile; + if (value == "AddAcid") return AddAcid; + if (value == "AddAcidPuddle") return AddAcidPuddle; + if (value == "AddStoneCurse") return AddStoneCurse; + if (value == "AddGolem") return AddGolem; + if (value == "AddApocalypseBoom") return AddApocalypseBoom; + if (value == "AddHealing") return AddHealing; + if (value == "AddHealOther") return AddHealOther; + if (value == "AddElemental") return AddElemental; + if (value == "AddIdentify") return AddIdentify; + if (value == "AddFireWallControl") return AddFireWallControl; + if (value == "AddInfravision") return AddInfravision; + if (value == "AddFlameWaveControl") return AddFlameWaveControl; + if (value == "AddNova") return AddNova; + if (value == "AddRage") return AddRage; + if (value == "AddItemRepair") return AddItemRepair; + if (value == "AddStaffRecharge") return AddStaffRecharge; + if (value == "AddTrapDisarm") return AddTrapDisarm; + if (value == "AddApocalypse") return AddApocalypse; + if (value == "AddInferno") return AddInferno; + if (value == "AddInfernoControl") return AddInfernoControl; + if (value == "AddChargedBolt") return AddChargedBolt; + if (value == "AddHolyBolt") return AddHolyBolt; + if (value == "AddResurrect") return AddResurrect; + if (value == "AddResurrectBeam") return AddResurrectBeam; + if (value == "AddTelekinesis") return AddTelekinesis; + if (value == "AddBoneSpirit") return AddBoneSpirit; + if (value == "AddRedPortal") return AddRedPortal; + if (value == "AddDiabloApocalypse") return AddDiabloApocalypse; + return tl::make_unexpected("Unknown MissileData::AddFn name"); +} + +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +tl::expected ParseMissileProcessFn(std::string_view value) +{ + if (value.empty()) return nullptr; + if (value == "ProcessElementalArrow") return ProcessElementalArrow; + if (value == "ProcessArrow") return ProcessArrow; + if (value == "ProcessGenericProjectile") return ProcessGenericProjectile; + if (value == "ProcessNovaBall") return ProcessNovaBall; + if (value == "ProcessAcidPuddle") return ProcessAcidPuddle; + if (value == "ProcessFireWall") return ProcessFireWall; + if (value == "ProcessFireball") return ProcessFireball; + if (value == "ProcessHorkSpawn") return ProcessHorkSpawn; + if (value == "ProcessRune") return ProcessRune; + if (value == "ProcessLightningWall") return ProcessLightningWall; + if (value == "ProcessBigExplosion") return ProcessBigExplosion; + if (value == "ProcessLightningBow") return ProcessLightningBow; + if (value == "ProcessRingOfFire") return ProcessRingOfFire; + if (value == "ProcessSearch") return ProcessSearch; + if (value == "ProcessLightningWallControl") return ProcessLightningWallControl; + if (value == "ProcessImmolation") return ProcessImmolation; + if (value == "ProcessSpectralArrow") return ProcessSpectralArrow; + if (value == "ProcessLightningControl") return ProcessLightningControl; + if (value == "ProcessLightning") return ProcessLightning; + if (value == "ProcessTownPortal") return ProcessTownPortal; + if (value == "ProcessFlashBottom") return ProcessFlashBottom; + if (value == "ProcessFlashTop") return ProcessFlashTop; + if (value == "ProcessFlameWave") return ProcessFlameWave; + if (value == "ProcessGuardian") return ProcessGuardian; + if (value == "ProcessChainLightning") return ProcessChainLightning; + if (value == "ProcessWeaponExplosion") return ProcessWeaponExplosion; + if (value == "ProcessMissileExplosion") return ProcessMissileExplosion; + if (value == "ProcessAcidSplate") return ProcessAcidSplate; + if (value == "ProcessTeleport") return ProcessTeleport; + if (value == "ProcessStoneCurse") return ProcessStoneCurse; + if (value == "ProcessApocalypseBoom") return ProcessApocalypseBoom; + if (value == "ProcessRhino") return ProcessRhino; + if (value == "ProcessFireWallControl") return ProcessFireWallControl; + if (value == "ProcessInfravision") return ProcessInfravision; + if (value == "ProcessApocalypse") return ProcessApocalypse; + if (value == "ProcessFlameWaveControl") return ProcessFlameWaveControl; + if (value == "ProcessNova") return ProcessNova; + if (value == "ProcessRage") return ProcessRage; + if (value == "ProcessInferno") return ProcessInferno; + if (value == "ProcessInfernoControl") return ProcessInfernoControl; + if (value == "ProcessChargedBolt") return ProcessChargedBolt; + if (value == "ProcessHolyBolt") return ProcessHolyBolt; + if (value == "ProcessElemental") return ProcessElemental; + if (value == "ProcessBoneSpirit") return ProcessBoneSpirit; + if (value == "ProcessResurrectBeam") return ProcessResurrectBeam; + if (value == "ProcessRedPortal") return ProcessRedPortal; + return tl::make_unexpected("Unknown MissileData::ProcessFn name"); +} + +// A temporary solution for parsing SfxID until we have a more general one. +// NOLINTNEXTLINE(readability-function-cognitive-complexity) +tl::expected ParseCastSound(std::string_view value) +{ + if (value.empty()) return SfxID::None; + if (value == "BigExplosion") return SfxID::BigExplosion; + if (value == "ShootFireballBow") return SfxID::ShootFireballBow; + if (value == "SpellAcid") return SfxID::SpellAcid; + if (value == "SpellApocalypse") return SfxID::SpellApocalypse; + if (value == "SpellBloodStar") return SfxID::SpellBloodStar; + if (value == "SpellBoneSpirit") return SfxID::SpellBoneSpirit; + if (value == "SpellChargedBolt") return SfxID::SpellChargedBolt; + if (value == "SpellDoomSerpents") return SfxID::SpellDoomSerpents; + if (value == "SpellElemental") return SfxID::SpellElemental; + if (value == "SpellEnd") return SfxID::SpellEnd; + if (value == "SpellEtherealize") return SfxID::SpellEtherealize; + if (value == "SpellFireHit") return SfxID::SpellFireHit; + if (value == "SpellFireWall") return SfxID::SpellFireWall; + if (value == "SpellFirebolt") return SfxID::SpellFirebolt; + if (value == "SpellFlameWave") return SfxID::SpellFlameWave; + if (value == "SpellGolem") return SfxID::SpellGolem; + if (value == "SpellGuardian") return SfxID::SpellGuardian; + if (value == "SpellHolyBolt") return SfxID::SpellHolyBolt; + if (value == "SpellInferno") return SfxID::SpellInferno; + if (value == "SpellInfravision") return SfxID::SpellInfravision; + if (value == "SpellInvisibility") return SfxID::SpellInvisibility; + if (value == "SpellLightning") return SfxID::SpellLightning; + if (value == "SpellLightningWall") return SfxID::SpellLightningWall; + if (value == "SpellManaShield") return SfxID::SpellManaShield; + if (value == "SpellNova") return SfxID::SpellNova; + if (value == "SpellPortal") return SfxID::SpellPortal; + if (value == "SpellPuddle") return SfxID::SpellPuddle; + if (value == "SpellStoneCurse") return SfxID::SpellStoneCurse; + if (value == "SpellTeleport") return SfxID::SpellTeleport; + if (value == "SpellTrapDisarm") return SfxID::SpellTrapDisarm; + return tl::make_unexpected("Unknown enum value (only a few are supported for now)"); +} + +// A temporary solution for parsing SfxID until we have a more general one. +tl::expected ParseHitSound(std::string_view value) +{ + if (value.empty()) return SfxID::None; + if (value == "BigExplosion") return SfxID::BigExplosion; + if (value == "SpellBloodStarHit") return SfxID::SpellBloodStarHit; + if (value == "SpellBoneSpiritHit") return SfxID::SpellBoneSpiritHit; + if (value == "SpellFireHit") return SfxID::SpellFireHit; + if (value == "SpellLightningHit") return SfxID::SpellLightningHit; + if (value == "SpellResurrect") return SfxID::SpellResurrect; + return tl::make_unexpected("Unknown enum value (only a few are supported for now)"); +} + +tl::expected ParseMissileMovementDistribution(std::string_view value) +{ + if (value.empty()) return MissileMovementDistribution::Disabled; + if (value == "Blockable") return MissileMovementDistribution::Blockable; + if (value == "Unblockable") return MissileMovementDistribution::Unblockable; + return tl::make_unexpected("Unknown enum value"); +} + +void LoadMisdat() +{ + const std::string_view filename = "txtdata\\missiles\\misdat.tsv"; + DataFile dataFile = DataFile::loadOrDie(filename); + dataFile.skipHeaderOrDie(filename); + + MissilesData.clear(); + MissilesData.reserve(dataFile.numRecords()); + for (DataFileRecord record : dataFile) { + RecordReader reader { record, filename }; + MissileData &item = MissilesData.emplace_back(); + reader.advance(); // skip id + reader.read("addFn", item.mAddProc, ParseMissileAddFn); + reader.read("processFn", item.mProc, ParseMissileProcessFn); + reader.read("castSound", item.mlSFX, ParseCastSound); + reader.read("hitSound", item.mlSFX, ParseHitSound); + reader.read("graphicId", item.mFileNum, ParseMissileGraphicID); + reader.readEnumList("flags", item.flags, ParseMissileDataFlag); + reader.read("movementDistribution", item.movementDistribution, ParseMissileMovementDistribution); + } + + // Sanity check because we do not actually parse the IDs yet. + assert(static_cast(MissileID::LAST) + 1 == MissilesData.size()); + + MissilesData.shrink_to_fit(); +} + } // namespace uint8_t MissileFileData::animDelay(uint8_t dir) const @@ -254,6 +430,12 @@ MissileFileData &GetMissileSpriteData(MissileGraphicID graphicId) void LoadMissileData() { LoadMissileSpriteData(); + LoadMisdat(); +} + +const MissileData &GetMissileData(MissileID missileId) +{ + return MissilesData[static_cast>(missileId)]; } void InitMissileGFX(bool loadHellfireGraphics) diff --git a/Source/misdat.h b/Source/misdat.h index e5c451b37..2913d14b2 100644 --- a/Source/misdat.h +++ b/Source/misdat.h @@ -128,8 +128,12 @@ enum class MissileDataFlags : uint8_t { use_enum_as_flags(MissileDataFlags); struct MissileData { - void (*mAddProc)(Missile &, AddMissileParameter &); - void (*mProc)(Missile &); + using AddFn = void (*)(Missile &, AddMissileParameter &); + using ProcessFn = void (*)(Missile &); + + AddFn mAddProc; + ProcessFn mProc; + /** * @brief Sound emitted when cast. */ @@ -200,13 +204,7 @@ struct MissileFileData { } }; -extern const MissileData MissilesData[]; - -inline const MissileData &GetMissileData(MissileID missileId) -{ - return MissilesData[static_cast>(missileId)]; -} - +const MissileData &GetMissileData(MissileID missileId); MissileFileData &GetMissileSpriteData(MissileGraphicID graphicId); void LoadMissileData(); diff --git a/Source/spelldat.h b/Source/spelldat.h index 3e9db7912..74458bc86 100644 --- a/Source/spelldat.h +++ b/Source/spelldat.h @@ -208,6 +208,8 @@ enum class MissileID : int8_t { BlueExplosion, BlueExplosion2, OrangeExplosion, + + LAST = OrangeExplosion, Null = -1, // clang-format on }; diff --git a/assets/txtdata/missiles/misdat.tsv b/assets/txtdata/missiles/misdat.tsv new file mode 100644 index 000000000..3f5646ccc --- /dev/null +++ b/assets/txtdata/missiles/misdat.tsv @@ -0,0 +1,109 @@ +id addFn processFn castSound hitSound graphicId flags movementDistribution +Arrow AddArrow ProcessArrow Arrow Physical,Arrow Blockable +Firebolt AddFirebolt ProcessGenericProjectile SpellFirebolt SpellFireHit Fireball Fire Blockable +Guardian AddGuardian ProcessGuardian SpellGuardian Guardian Physical +Phasing AddPhasing ProcessTeleport SpellTeleport Physical,Invisible +NovaBall AddNovaBall ProcessNovaBall Lightning Lightning Unblockable +FireWall AddFireWall ProcessFireWall SpellFireWall SpellFireHit FireWall Fire +Fireball AddFireball ProcessFireball SpellFirebolt SpellFireHit Fireball Fire Blockable +LightningControl AddLightningControl ProcessLightningControl Lightning Lightning,Invisible +Lightning AddLightning ProcessLightning SpellLightning SpellLightningHit Lightning Lightning +MagmaBallExplosion AddMissileExplosion ProcessMissileExplosion MagmaBallExplosion Physical +TownPortal AddTownPortal ProcessTownPortal SpellPortal TownPortal Magic +FlashBottom AddFlashBottom ProcessFlashBottom SpellNova SpellLightningHit FlashBottom Magic +FlashTop AddFlashTop ProcessFlashTop FlashTop Magic +ManaShield AddManaShield SpellManaShield ManaShield Magic,Invisible +FlameWave AddFlameWave ProcessFlameWave FireWall Fire Unblockable +ChainLightning AddChainLightning ProcessChainLightning SpellLightning SpellLightningHit Lightning Lightning +ChainBall Lightning Lightning +BloodHit SpellBloodStar SpellBloodStarHit BloodHit Physical +BoneHit BoneHit Physical +MetalHit MetalHit Physical +Rhino AddRhino ProcessRhino Physical Blockable +MagmaBall AddMagmaBall ProcessGenericProjectile MagmaBall Fire Blockable +ThinLightningControl AddLightningControl ProcessLightningControl ThinLightning Lightning,Invisible +ThinLightning AddLightning ProcessLightning ThinLightning Lightning +BloodStar AddGenericMagicMissile ProcessGenericProjectile BloodStar Magic Blockable +BloodStarExplosion AddMissileExplosion ProcessMissileExplosion BloodStarExplosion Magic +Teleport AddTeleport ProcessTeleport SpellElemental Physical,Invisible +FireArrow AddElementalArrow ProcessElementalArrow FireArrow Fire,Arrow Blockable +DoomSerpents SpellDoomSerpents DoomSerpents Magic,Invisible +FireOnly FireWall Fire +StoneCurse AddStoneCurse ProcessStoneCurse SpellStoneCurse Magic,Invisible +BloodRitual Physical +Invisibility SpellInvisibility Physical,Invisible +Golem AddGolem SpellGolem Physical,Invisible +Etherealize SpellEtherealize Etherealize Physical +Spurt Spurt Physical +ApocalypseBoom AddApocalypseBoom ProcessApocalypseBoom ApocalypseBoom Physical +Healing AddHealing Physical,Invisible +FireWallControl AddFireWallControl ProcessFireWallControl FireWall Fire,Invisible +Infravision AddInfravision ProcessInfravision SpellInfravision Physical,Invisible +Identify AddIdentify Physical,Invisible +FlameWaveControl AddFlameWaveControl ProcessFlameWaveControl SpellFlameWave FireWall Fire +Nova AddNova ProcessNova SpellNova Lightning Lightning +Rage AddRage ProcessRage Physical,Invisible +Apocalypse AddApocalypse ProcessApocalypse SpellApocalypse ApocalypseBoom Magic +ItemRepair AddItemRepair Physical,Invisible +StaffRecharge AddStaffRecharge Physical,Invisible +TrapDisarm AddTrapDisarm SpellTrapDisarm Physical,Invisible +Inferno AddInferno ProcessInferno SpellInferno Inferno Fire +InfernoControl AddInfernoControl ProcessInfernoControl Fire,Invisible +FireMan Physical Blockable +Krull Krull Fire,Arrow Blockable +ChargedBolt AddChargedBolt ProcessChargedBolt SpellChargedBolt ChargedBolt Lightning Blockable +HolyBolt AddHolyBolt ProcessHolyBolt SpellHolyBolt SpellLightningHit HolyBolt Physical Blockable +Resurrect AddResurrect SpellResurrect Magic,Invisible +Telekinesis AddTelekinesis SpellEtherealize Physical,Invisible +LightningArrow AddElementalArrow ProcessElementalArrow LightningArrow Lightning,Arrow Blockable +Acid AddAcid ProcessGenericProjectile SpellAcid Acid Acid Blockable +AcidSplat AddMissileExplosion ProcessAcidSplate AcidSplat Acid +AcidPuddle AddAcidPuddle ProcessAcidPuddle SpellPuddle AcidPuddle Acid +HealOther AddHealOther Physical,Invisible +Elemental AddElemental ProcessElemental SpellElemental Elemental Fire Unblockable +ResurrectBeam AddResurrectBeam ProcessResurrectBeam Resurrect Physical +BoneSpirit AddBoneSpirit ProcessBoneSpirit SpellBoneSpirit SpellBoneSpiritHit BoneSpirit Magic Blockable +WeaponExplosion AddWeaponExplosion ProcessWeaponExplosion Physical +RedPortal AddRedPortal ProcessRedPortal SpellPortal RedPortal Physical +DiabloApocalypseBoom AddApocalypseBoom ProcessApocalypseBoom DiabloApocalypseBoom Physical +DiabloApocalypse AddDiabloApocalypse Physical,Invisible +Mana AddMana Physical,Invisible +Magi AddMagi Physical,Invisible +LightningWall AddLightningWall ProcessLightningWall SpellLightningWall SpellLightningHit Lightning Lightning +LightningWallControl AddFireWallControl ProcessLightningWallControl Lightning Lightning,Invisible +Immolation AddNova ProcessImmolation SpellFirebolt SpellFireHit Fireball Fire +SpectralArrow AddSpectralArrow ProcessSpectralArrow Arrow Physical,Arrow +FireballBow AddImmolation ProcessFireball ShootFireballBow SpellFireHit Fireball Fire Blockable +LightningBow AddLightningBow ProcessLightningBow ShootFireballBow Lightning Lightning,Invisible +ChargedBoltBow AddChargedBoltBow ProcessChargedBolt SpellChargedBolt ChargedBolt Lightning Blockable +HolyBoltBow AddHolyBolt ProcessHolyBolt SpellHolyBolt SpellLightningHit HolyBolt Physical Blockable +Warp AddWarp ProcessTeleport SpellEtherealize Physical,Invisible +Reflect AddReflect SpellManaShield Reflect Physical,Invisible +Berserk AddBerserk Physical,Invisible +RingOfFire AddRingOfFire ProcessRingOfFire FireWall Fire,Invisible +StealPotions AddStealPotions Physical,Invisible +StealMana AddStealMana SpellEnd Physical,Invisible +RingOfLightning Lightning Lightning,Invisible +Search AddSearch ProcessSearch Physical,Invisible +Aura SpellLightningHit FlashBottom Magic,Invisible +Aura2 FlashTop Magic,Invisible +SpiralFireball SpellFirebolt SpellFireHit Fireball Fire +RuneOfFire AddRuneOfFire ProcessRune Rune Physical +RuneOfLight AddRuneOfLight ProcessRune Rune Physical +RuneOfNova AddRuneOfNova ProcessRune Rune Physical +RuneOfImmolation AddRuneOfImmolation ProcessRune Rune Physical +RuneOfStone AddRuneOfStone ProcessRune Rune Physical +BigExplosion AddBigExplosion ProcessBigExplosion BigExplosion BigExplosion BigExplosion Fire +HorkSpawn AddHorkSpawn ProcessHorkSpawn Physical,Invisible +Jester AddJester Physical,Invisible +OpenNest AddOpenNest Physical,Invisible +OrangeFlare AddGenericMagicMissile ProcessGenericProjectile OrangeFlare Magic Blockable +BlueFlare AddGenericMagicMissile ProcessGenericProjectile BlueFlare2 Magic Blockable +RedFlare AddGenericMagicMissile ProcessGenericProjectile RedFlare Magic Blockable +YellowFlare AddGenericMagicMissile ProcessGenericProjectile YellowFlare Magic Blockable +BlueFlare2 AddGenericMagicMissile ProcessGenericProjectile BlueFlare2 Magic Blockable +YellowExplosion AddMissileExplosion ProcessMissileExplosion SpellFireHit YellowFlareExplosion Physical +RedExplosion AddMissileExplosion ProcessMissileExplosion SpellFireHit RedFlareExplosion Physical +BlueExplosion AddMissileExplosion ProcessMissileExplosion SpellFireHit BlueFlareExplosion Physical +BlueExplosion2 AddMissileExplosion ProcessMissileExplosion SpellFireHit BlueFlareExplosion2 Physical +OrangeExplosion AddMissileExplosion ProcessMissileExplosion SpellFireHit OrangeFlareExplosion Physical