content: -- | Blast definitions.
  module Content.ItemKindBlast
    ( -- * Group name patterns
      pattern S_FIRECRACKER, pattern S_VIOLENT_FRAGMENTATION, pattern S_FRAGMENTATION, pattern S_FOCUSED_FRAGMENTATION, pattern S_VIOLENT_CONCUSSION, pattern S_CONCUSSION, pattern S_FOCUSED_CONCUSSION, pattern S_VIOLENT_FLASH, pattern S_FOCUSED_FLASH, pattern S_GLASS_HAIL, pattern S_FOCUSED_GLASS_HAIL, pattern S_PHEROMONE, pattern S_CALMING_MIST, pattern S_DISTRESSING_ODOR, pattern S_HEALING_MIST, pattern S_HEALING_MIST_2, pattern S_WOUNDING_MIST, pattern S_DISTORTION, pattern S_SMOKE, pattern S_BOILING_WATER, pattern S_GLUE, pattern S_WASTE, pattern S_ANTI_SLOW_MIST, pattern S_ANTIDOTE_MIST, pattern S_SLEEP_MIST, pattern S_DENSE_SHOWER, pattern S_SPARSE_SHOWER, pattern S_MELEE_PROTECTIVE_BALM, pattern S_RANGE_PROTECTIVE_BALM, pattern S_DEFENSELESSNESS_RUNOUT, pattern S_RESOLUTION_DUST, pattern S_HASTE_SPRAY, pattern S_VIOLENT_SLOWNESS_MIST, pattern S_SLOWNESS_MIST, pattern S_FOCUSED_SLOWNESS_MIST, pattern S_EYE_DROP, pattern S_IRON_FILING, pattern S_SMELLY_DROPLET, pattern S_EYE_SHINE, pattern S_WHISKEY_SPRAY, pattern S_YOUTH_SPRINKLE, pattern S_POISON_CLOUD, pattern S_PING_PLASH, pattern S_VIOLENT_BURNING_OIL_2, pattern S_VIOLENT_BURNING_OIL_3, pattern S_VIOLENT_BURNING_OIL_4, pattern S_BURNING_OIL_2, pattern S_BURNING_OIL_3, pattern S_BURNING_OIL_4, pattern S_FOCUSED_BURNING_OIL_2, pattern S_FOCUSED_BURNING_OIL_3, pattern S_FOCUSED_BURNING_OIL_4
    , blastNoStatOf, blastBonusStatOf
    , pattern ARMOR_MISC
    , blastsGNSingleton, blastsGN
    , -- * Content
      blasts
    ) where
  
  import Prelude ()
  
  import Game.LambdaHack.Core.Prelude
  
  import Game.LambdaHack.Content.ItemKind
  import Game.LambdaHack.Core.Dice
  import Game.LambdaHack.Definition.Ability
  import Game.LambdaHack.Definition.Color
  import Game.LambdaHack.Definition.Defs
  import Game.LambdaHack.Definition.DefsInternal
  import Game.LambdaHack.Definition.Flavour
  
  import Content.ItemKindTemporary
  
  -- * Group name patterns
  
  blastsGNSingleton :: [GroupName ItemKind]
  blastsGNSingleton =
         [S_FIRECRACKER, S_VIOLENT_FRAGMENTATION, S_FRAGMENTATION, S_FOCUSED_FRAGMENTATION, S_VIOLENT_CONCUSSION, S_CONCUSSION, S_FOCUSED_CONCUSSION, S_VIOLENT_FLASH, S_FOCUSED_FLASH, S_GLASS_HAIL, S_FOCUSED_GLASS_HAIL, S_PHEROMONE, S_CALMING_MIST, S_DISTRESSING_ODOR, S_HEALING_MIST, S_HEALING_MIST_2, S_WOUNDING_MIST, S_DISTORTION, S_SMOKE, S_BOILING_WATER, S_GLUE, S_WASTE, S_ANTI_SLOW_MIST, S_ANTIDOTE_MIST, S_SLEEP_MIST, S_DENSE_SHOWER, S_SPARSE_SHOWER, S_MELEE_PROTECTIVE_BALM, S_RANGE_PROTECTIVE_BALM, S_DEFENSELESSNESS_RUNOUT, S_RESOLUTION_DUST, S_HASTE_SPRAY, S_VIOLENT_SLOWNESS_MIST, S_SLOWNESS_MIST, S_FOCUSED_SLOWNESS_MIST, S_EYE_DROP, S_IRON_FILING, S_SMELLY_DROPLET, S_EYE_SHINE, S_WHISKEY_SPRAY, S_YOUTH_SPRINKLE, S_POISON_CLOUD, S_PING_PLASH, S_VIOLENT_BURNING_OIL_2, S_VIOLENT_BURNING_OIL_3, S_VIOLENT_BURNING_OIL_4, S_BURNING_OIL_2, S_BURNING_OIL_3, S_BURNING_OIL_4, S_FOCUSED_BURNING_OIL_2, S_FOCUSED_BURNING_OIL_3, S_FOCUSED_BURNING_OIL_4]
    ++ map firecrackerAt [1..4]
    ++ map blastNoStatOf noStatGN
    ++ map blastBonusStatOf bonusStatGN
  
  pattern S_FIRECRACKER, S_VIOLENT_FRAGMENTATION, S_FRAGMENTATION, S_FOCUSED_FRAGMENTATION, S_VIOLENT_CONCUSSION, S_CONCUSSION, S_FOCUSED_CONCUSSION, S_VIOLENT_FLASH, S_FOCUSED_FLASH, S_GLASS_HAIL, S_FOCUSED_GLASS_HAIL, S_PHEROMONE, S_CALMING_MIST, S_DISTRESSING_ODOR, S_HEALING_MIST, S_HEALING_MIST_2, S_WOUNDING_MIST, S_DISTORTION, S_SMOKE, S_BOILING_WATER, S_GLUE, S_WASTE, S_ANTI_SLOW_MIST, S_ANTIDOTE_MIST, S_SLEEP_MIST, S_DENSE_SHOWER, S_SPARSE_SHOWER, S_MELEE_PROTECTIVE_BALM, S_RANGE_PROTECTIVE_BALM, S_DEFENSELESSNESS_RUNOUT, S_RESOLUTION_DUST, S_HASTE_SPRAY, S_VIOLENT_SLOWNESS_MIST, S_SLOWNESS_MIST, S_FOCUSED_SLOWNESS_MIST, S_EYE_DROP, S_IRON_FILING, S_SMELLY_DROPLET, S_EYE_SHINE, S_WHISKEY_SPRAY, S_YOUTH_SPRINKLE, S_POISON_CLOUD, S_PING_PLASH, S_VIOLENT_BURNING_OIL_2, S_VIOLENT_BURNING_OIL_3, S_VIOLENT_BURNING_OIL_4, S_BURNING_OIL_2, S_BURNING_OIL_3, S_BURNING_OIL_4, S_FOCUSED_BURNING_OIL_2, S_FOCUSED_BURNING_OIL_3, S_FOCUSED_BURNING_OIL_4 :: GroupName ItemKind
  
  blastsGN :: [GroupName ItemKind]
  blastsGN =
         [ARMOR_MISC]
  
  pattern ARMOR_MISC :: GroupName ItemKind
  
  pattern S_FIRECRACKER = GroupName "firecracker"
  pattern S_VIOLENT_FRAGMENTATION = GroupName "violent fragmentation"
  pattern S_FRAGMENTATION = GroupName "fragmentation"
  pattern S_FOCUSED_FRAGMENTATION = GroupName "focused fragmentation"
  pattern S_VIOLENT_CONCUSSION = GroupName "violent concussion"
  pattern S_CONCUSSION = GroupName "concussion"
  pattern S_FOCUSED_CONCUSSION = GroupName "focused concussion"
  pattern S_VIOLENT_FLASH = GroupName "violent flash"
  pattern S_FOCUSED_FLASH = GroupName "focused flash"
  pattern S_GLASS_HAIL = GroupName "glass hail"
  pattern S_FOCUSED_GLASS_HAIL = GroupName "focused glass hail"
  pattern S_PHEROMONE = GroupName "pheromone"
  pattern S_CALMING_MIST = GroupName "calming mist"
  pattern S_DISTRESSING_ODOR = GroupName "distressing odor"
  pattern S_HEALING_MIST = GroupName "healing mist"
  pattern S_HEALING_MIST_2 = GroupName "strong healing mist"
  pattern S_WOUNDING_MIST = GroupName "wounding mist"
  pattern S_DISTORTION = GroupName "distortion"
  pattern S_SMOKE = GroupName "smoke"
  pattern S_BOILING_WATER = GroupName "boiling water"
  pattern S_GLUE = GroupName "glue"
  pattern S_WASTE = GroupName "waste"
  pattern S_ANTI_SLOW_MIST = GroupName "anti-slow mist"
  pattern S_ANTIDOTE_MIST = GroupName "antidote mist"
  pattern S_SLEEP_MIST = GroupName "sleep mist"
  pattern S_DENSE_SHOWER = GroupName "dense shower"
  pattern S_SPARSE_SHOWER = GroupName "sparse shower"
  pattern S_MELEE_PROTECTIVE_BALM = GroupName "melee protective balm"
  pattern S_RANGE_PROTECTIVE_BALM = GroupName "ranged protective balm"
  pattern S_DEFENSELESSNESS_RUNOUT = GroupName "PhD defense question"
  pattern S_RESOLUTION_DUST = GroupName "resolution dust"
  pattern S_HASTE_SPRAY = GroupName "haste spray"
  pattern S_VIOLENT_SLOWNESS_MIST = GroupName "violent nitrogen mist"
  pattern S_SLOWNESS_MIST = GroupName "nitrogen mist"
  pattern S_FOCUSED_SLOWNESS_MIST = GroupName "focused nitrogen mist"
  pattern S_EYE_DROP = GroupName "eye drop"
  pattern S_IRON_FILING = GroupName "iron filing"
  pattern S_SMELLY_DROPLET = GroupName "smelly droplet"
  pattern S_EYE_SHINE = GroupName "eye shine"
  pattern S_WHISKEY_SPRAY = GroupName "whiskey spray"
  pattern S_YOUTH_SPRINKLE = GroupName "youth sprinkle"
  pattern S_POISON_CLOUD = GroupName "poison cloud"
  pattern S_PING_PLASH = GroupName "ping and flash"
  pattern S_VIOLENT_BURNING_OIL_2 = GroupName "violent burning oil 2"
  pattern S_VIOLENT_BURNING_OIL_3 = GroupName "violent burning oil 3"
  pattern S_VIOLENT_BURNING_OIL_4 = GroupName "violent burning oil 4"
  pattern S_BURNING_OIL_2 = GroupName "burning oil 2"
  pattern S_BURNING_OIL_3 = GroupName "burning oil 3"
  pattern S_BURNING_OIL_4 = GroupName "burning oil 4"
  pattern S_FOCUSED_BURNING_OIL_2 = GroupName "focused burning oil 2"
  pattern S_FOCUSED_BURNING_OIL_3 = GroupName "focused burning oil 3"
  pattern S_FOCUSED_BURNING_OIL_4 = GroupName "focused burning oil 4"
  
  firecrackerAt :: Int -> GroupName ItemKind
  firecrackerAt n = GroupName $ "firecracker" <+> tshow n
  
  blastNoStatOf :: GroupName ItemKind -> GroupName ItemKind
  blastNoStatOf grp = GroupName $ fromGroupName grp <+> "mist"
  
  blastBonusStatOf :: GroupName ItemKind -> GroupName ItemKind
  blastBonusStatOf grp = GroupName $ fromGroupName grp <+> "dew"
  
  pattern ARMOR_MISC = GroupName "miscellaneous armor"
  
  -- * Content
  
  blasts :: [ItemKind]
  blasts =
    [spreadBurningOil2, spreadBurningOil3, spreadBurningOil4, spreadBurningOil82, spreadBurningOil83, spreadBurningOil84, focusedBurningOil2, focusedBurningOil3, focusedBurningOil4, firecracker1, firecracker2, firecracker3, firecracker4, firecracker5, spreadFragmentation, spreadFragmentation8, focusedFragmentation, spreadConcussion, spreadConcussion8, focusedConcussion, spreadFlash, spreadFlash8, focusedFlash, singleSpark, glassPiece, focusedGlass, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, smoke, boilingWater, glue, waste, mistAntiSlow, mistAntidote, mistSleep, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, defenselessnessRunout, resolutionDust, hasteSpray, spreadNitrogen, spreadNitrogen8, focusedNitrogen, eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, youthSprinkle, poisonCloud, pingFlash, blastNoSkMove, blastNoSkMelee, blastNoSkDisplace, blastNoSkAlter, blastNoSkWait, blastNoSkMoveItem, blastNoSkProject, blastNoSkApply, blastBonusSkMove, blastBonusSkMelee, blastBonusSkDisplace, blastBonusSkAlter, blastBonusSkWait, blastBonusSkMoveItem, blastBonusSkProject, blastBonusSkApply]
  
  spreadBurningOil2,    spreadBurningOil3, spreadBurningOil4, spreadBurningOil82, spreadBurningOil83, spreadBurningOil84, focusedBurningOil2, focusedBurningOil3, focusedBurningOil4, firecracker1, firecracker2, firecracker3, firecracker4, firecracker5, spreadFragmentation, spreadFragmentation8, focusedFragmentation, spreadConcussion, spreadConcussion8, focusedConcussion, spreadFlash, spreadFlash8, focusedFlash, singleSpark, glassPiece, focusedGlass, fragrance, pheromone, mistCalming, odorDistressing, mistHealing, mistHealing2, mistWounding, distortion, smoke, boilingWater, glue, waste, mistAntiSlow, mistAntidote, mistSleep, denseShower, sparseShower, protectingBalmMelee, protectingBalmRanged, defenselessnessRunout, resolutionDust, hasteSpray, spreadNitrogen, spreadNitrogen8, focusedNitrogen,  eyeDrop, ironFiling, smellyDroplet, eyeShine, whiskeySpray, youthSprinkle, poisonCloud, pingFlash, blastNoSkMove, blastNoSkMelee, blastNoSkDisplace, blastNoSkAlter, blastNoSkWait, blastNoSkMoveItem, blastNoSkProject, blastNoSkApply, blastBonusSkMove, blastBonusSkMelee, blastBonusSkDisplace, blastBonusSkAlter, blastBonusSkWait, blastBonusSkMoveItem, blastBonusSkProject, blastBonusSkApply :: ItemKind
  
  -- We take care (e.g., in burningOil below) that blasts are not faster
  -- than 100% fastest natural speed, or some frames would be skipped,
  -- which is a waste of perfectly good frames.
  
  -- * Parameterized blasts
  
  spreadBurningOil :: Int -> GroupName ItemKind -> ItemKind
  spreadBurningOil n grp = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "burning oil"
    , ifreq    = [(grp, 1)]
    , iflavour = zipPlain [BrYellow]
    , icount   = intToDice (4 + n * 2)
    , irarity  = [(1, 1)]
    , iverbHit = "sear"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity (max 10 $ min 100 $ n `div` 2 * 10)
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 2 ]
    , ieffects = [ Burn 1
                 , toOrganBad S_PACIFIED (2 + 1 `d` 2) ]
                     -- slips and frantically puts out fire
    , idesc    = "Sticky oil, burning brightly."
    , ikit     = []
    }
  spreadBurningOil2 = spreadBurningOil 2 S_VIOLENT_BURNING_OIL_2
                        -- 2 steps, 2 turns
  spreadBurningOil3 = spreadBurningOil 3 S_VIOLENT_BURNING_OIL_3
                        -- 2 steps, 2 turns
  spreadBurningOil4 = spreadBurningOil 4 S_VIOLENT_BURNING_OIL_4
                        -- 4 steps, 2 turns
  spreadBurningOil8 :: Int -> GroupName ItemKind -> ItemKind
  spreadBurningOil8 n grp = (spreadBurningOil (n `div` 2) grp)
    { icount   = 7  -- 8 was too deadly
    }
  spreadBurningOil82 = spreadBurningOil8 2 S_BURNING_OIL_2
  spreadBurningOil83 = spreadBurningOil8 3 S_BURNING_OIL_3
  spreadBurningOil84 = spreadBurningOil8 4 S_BURNING_OIL_4
  focusedBurningOil :: Int -> GroupName ItemKind -> GroupName ItemKind -> ItemKind
  focusedBurningOil n grp grpExplode = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "igniting oil"
    , ifreq    = [(grp, 1)]
    , iflavour = zipPlain [BrYellow]  -- all ignitions yellow to avoid appearing
                                      -- as a small vial explosion
    , icount   = intToDice n
    , irarity  = [(1, 1)]
    , iverbHit = "ignite"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
        -- when the target position is occupied, the explosion starts one step
        -- away, hence we set range to 0 steps, to limit dispersal
    , ieffects = [OnSmash $ Explode grpExplode]
    , idesc    = idesc spreadBurningOil2
    , ikit     = []
    }
  focusedBurningOil2 = focusedBurningOil 2 S_FOCUSED_BURNING_OIL_2 S_BURNING_OIL_2
  focusedBurningOil3 = focusedBurningOil 3 S_FOCUSED_BURNING_OIL_3 S_BURNING_OIL_3
  focusedBurningOil4 = focusedBurningOil 4 S_FOCUSED_BURNING_OIL_4 S_BURNING_OIL_4
  firecracker :: Int -> ItemKind
  firecracker n = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "firecracker"
    , ifreq    = [(if n == 5
                   then S_FIRECRACKER
                   else firecrackerAt n, 1)]
    , iflavour = zipPlain [brightCol !! ((n + 2) `mod` length brightCol)]
    , icount   = if n <= 3 then 1 `d` min 2 n else 2 + 1 `d` 2
    , irarity  = [(1, 1)]
    , iverbHit = if n >= 4 then "singe" else "crack"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine $ intToDice $ 1 + n `div` 2 ]
    , ieffects = [if n >= 4 then Burn 1 else RefillCalm (-2)]
                 ++ [Discharge 1 30 | n >= 3]
                 ++ [OnSmash $ Explode $ firecrackerAt (n - 1) | n >= 2]
    , idesc    = "Scraps of burnt paper, covering little pockets of black powder, buffeted by colorful explosions."
    , ikit     = []
    }
  firecracker5 = firecracker 5
  firecracker4 = firecracker 4
  firecracker3 = firecracker 3
  firecracker2 = firecracker 2
  firecracker1 = firecracker 1
  
  -- * Focused blasts
  
  spreadFragmentation = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "fragmentation burst"
    , ifreq    = [(S_VIOLENT_FRAGMENTATION, 1)]
    , iflavour = zipPlain [Red]
    , icount   = 8  -- strong but few, so not always hits target
    , irarity  = [(1, 1)]
    , iverbHit = "tear apart"
    , iweight  = 1
    , idamage  = 3 `d` 1  -- deadly and adjacent actor hit by 2 on average;
                          -- however, moderate armour blocks completely
    , iaspects = [ ToThrow $ ThrowMod 100 20 4  -- 4 steps, 1 turn
                 , SetFlag Lobable, SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 3, AddSkill SkHurtMelee $ -12 * 5 ]
    , ieffects = [DropItem 1 1 COrgan CONDITION]
    , idesc    = "Flying shards, flame and smoke."
    , ikit     = []
    }
  spreadFragmentation8 = spreadFragmentation
    { ifreq    = [(S_FRAGMENTATION, 1)]
    , icount   = 5
    , iaspects = [ ToThrow $ ThrowMod 100 10 2  -- 2 steps, 1 turn
                 , SetFlag Lobable, SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 3, AddSkill SkHurtMelee $ -12 * 5 ]
        -- smaller radius, so worse for area effect, but twice the direct damage
    }
  focusedFragmentation = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "deflagration ignition"  -- black powder
    , ifreq    = [(S_FOCUSED_FRAGMENTATION, 1)]
    , iflavour = zipPlain [BrYellow]
    , icount   = 3  -- 15 in total vs 8, higher spread
    , irarity  = [(1, 1)]
    , iverbHit = "ignite"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
        -- when the target position is occupied, the explosion starts one step
        -- away, hence we set range to 0 steps, to limit dispersal
    , ieffects = [OnSmash $ Explode S_FRAGMENTATION]
    , idesc    = idesc spreadFragmentation
    , ikit     = []
    }
  spreadConcussion = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "concussion blast"
    , ifreq    = [(S_VIOLENT_CONCUSSION, 1)]
    , iflavour = zipPlain [Magenta]
    , icount   = 12  -- pushing sometimes gets the victim out of attacker range,
                     -- but also sometimes moves to a position hit again later
    , irarity  = [(1, 1)]
    , iverbHit = "shock"
    , iweight  = 1
    , idamage  = 1 `d` 1  -- only air pressure, so not as deadly as fragmentation,
                          -- but armour can't block completely that easily
    , iaspects = [ ToThrow $ ThrowMod 100 20 4  -- 4 steps, 1 turn
                 , SetFlag Lobable, SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 3, AddSkill SkHurtMelee $ -8 * 5 ]
        -- outdoors it has short range, but we only model indoors in the game;
        -- it's much faster than black powder shock wave, but we are beyond
        -- human-noticeable speed differences on short distances anyway
    , ieffects = [ DropItem maxBound 1 CEqp ARMOR_MISC
                 , PushActor (ThrowMod 400 25 1)  -- 1 step, fast; after DropItem
                     -- this produces spam for braced actors; too bad
                 , toOrganBad S_IMMOBILE 1  -- no balance
                 , toOrganBad S_DEAFENED 23 ]
    , idesc    = "Shock wave, hot gases, some fire and smoke."
    , ikit     = []
    }
  spreadConcussion8 = spreadConcussion
    { ifreq    = [(S_CONCUSSION, 1)]
    , icount   = 6
    , iaspects = [ ToThrow $ ThrowMod 100 10 2  -- 2 steps, 1 turn
                 , SetFlag Lobable, SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 3, AddSkill SkHurtMelee $ -8 * 5 ]
    }
  focusedConcussion = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "detonation ignition"  -- nitroglycerine
    , ifreq    = [(S_FOCUSED_CONCUSSION, 1)]
    , iflavour = zipPlain [BrYellow]
    , icount   = 4  -- 24 in total vs 12, higher spread, less harm from pushing
    , irarity  = [(1, 1)]
    , iverbHit = "ignite"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [OnSmash $ Explode S_CONCUSSION]
    , idesc    = idesc spreadConcussion
    , ikit     = []
    }
  spreadFlash = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "magnesium flash"
    , ifreq    = [(S_VIOLENT_FLASH, 1)]
    , iflavour = zipPlain [BrWhite]
    , icount   = 13
    , irarity  = [(1, 1)]
    , iverbHit = "dazzle"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ ToThrow $ ThrowMod 100 20 4  -- 4 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 5 ]
    , ieffects = [ toOrganBad S_BLIND 5
                 , toOrganBad S_WEAKENED 20 ]
                   -- Wikipedia says: blind for five seconds and afterimage
                   -- for much longer, harming aim
    , idesc    = "A very bright flash of fire, causing long-lasting afterimages."
    , ikit     = []
    }
  spreadFlash8 = spreadFlash
    { iname    = "spark"
    , ifreq    = [(S_SPARK, 1)]
    , icount   = 5
    , iverbHit = "singe"
    , iaspects = [ ToThrow $ ThrowMod 100 10 2  -- 2 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 5 ]
    }
  focusedFlash = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "magnesium ignition"
    , ifreq    = [(S_FOCUSED_FLASH, 1)]
    , iflavour = zipPlain [BrYellow]
    , icount   = 5  -- 25 in total vs 13, higher spread
    , irarity  = [(1, 1)]
    , iverbHit = "ignite"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [OnSmash $ Explode S_SPARK]
    , idesc    = idesc spreadFlash
    , ikit     = []
    }
  singleSpark = spreadFlash
    { iname    = "single spark"
    , ifreq    = [(S_SINGLE_SPARK, 1)]  -- too weak to start a fire
    , icount   = 1
    , iverbHit = "spark"
    , iaspects = [ toLinger 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 3 ]
    , ieffects = []
    , idesc    = "A glowing ember."
    , ikit     = []
    }
  glassPiece = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "glass piece"
    , ifreq    = [(S_GLASS_HAIL, 1)]
    , iflavour = zipPlain [Blue]
    , icount   = 6
    , irarity  = [(1, 1)]
    , iverbHit = "cut"
    , iweight  = 1
    , idamage  = 2 `d` 1
    , iaspects = [ ToThrow $ ThrowMod 100 10 4  -- 2 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkHurtMelee $ -15 * 5 ]
                   -- brittle, not too dense; armor blocks
    , ieffects = []
    , idesc    = "Swift, sharp edges."
    , ikit     = []
    }
  focusedGlass = glassPiece  -- when blowing up windows
    { ifreq    = [(S_FOCUSED_GLASS_HAIL, 1)]
    , icount   = 2
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkHurtMelee $ -15 * 5 ]
    , ieffects = [OnSmash $ Explode S_GLASS_HAIL]
    }
  
  -- * Assorted blasts that don't induce conditions or not used mainly for them
  
  fragrance = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "fragrance"  -- instant, fast fragrance
    , ifreq    = [(S_FRAGRANCE, 1)]
    , iflavour = zipPlain [Magenta]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "engulf"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ ToThrow $ ThrowMod 200 5 1  -- 2 steps, .5 turn (necklaces)
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [Impress, toOrganGood S_ROSE_SMELLING 45]
    -- Linger 10, because sometimes it takes 2 turns due to starting just
    -- before actor turn's end (e.g., via a necklace).
    , idesc    = "A pleasant scent."
    , ikit     = []
    }
  pheromone = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "musky whiff"  -- a kind of mist rather than fragrance
    , ifreq    = [(S_PHEROMONE, 1)]
    , iflavour = zipPlain [BrMagenta]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "tempt"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 10  -- 2 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [Dominate]
    , idesc    = "A sharp, strong scent."
    , ikit     = []
    }
  mistCalming = ItemKind  -- unused
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_CALMING_MIST, 1)]
    , iflavour = zipPlain [BrGreen]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "sooth"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [RefillCalm 2]
    , idesc    = "A soothing, gentle cloud."
    , ikit     = []
    }
  odorDistressing = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "distressing whiff"
    , ifreq    = [(S_DISTRESSING_ODOR, 1)]
    , iflavour = zipFancy [BrRed]  -- salmon
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "distress"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 10  -- 2 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [ RefillCalm (-10)
                 , toOrganBad S_FOUL_SMELLING (20 + 1 `d` 5)
                 , toOrganBad S_IMPATIENT (2 + 1 `d` 2) ]
    , idesc    = "It turns the stomach."  -- and so can't stand still
    , ikit     = []
    }
  mistHealing = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"  -- powerful, so slow and narrow
    , ifreq    = [(S_HEALING_MIST, 1)]
    , iflavour = zipFancy [BrGreen]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "revitalize"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 1 ]
    , ieffects = [RefillHP 2]
    , idesc    = "It fills the air with light and life."
    , ikit     = []
    }
  mistHealing2 = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_HEALING_MIST_2, 1)]
    , iflavour = zipPlain [Green]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "revitalize"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 2 ]
    , ieffects = [RefillHP 4]
    , idesc    = "At its touch, wounds close and bruises fade."
    , ikit     = []
    }
  mistWounding = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_WOUNDING_MIST, 1)]
    , iflavour = zipPlain [BrRed]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "devitalize"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [RefillHP (-2)]
    , idesc    = "The air itself stings and itches."
    , ikit     = []
    }
  distortion = ItemKind
    { isymbol  = toContentSymbol 'v'
    , iname    = "vortex"
    , ifreq    = [(S_DISTORTION, 1)]
    , iflavour = zipPlain [White]
    , icount   = 8  -- braced are immune to Teleport; avoid failure messages
    , irarity  = [(1, 1)]
    , iverbHit = "engulf"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 10  -- 2 steps, 1 turn
                 , SetFlag Lobable, SetFlag Fragile, SetFlag Blast ]
    , ieffects = [Teleport $ 15 + 1 `d` 10]
    , idesc    = "The air shifts oddly, as though light is being warped."
    , ikit     = []
    }
  smoke = ItemKind  -- when stuff burns out  -- unused
    { isymbol  = toContentSymbol '`'
    , iname    = "smoke fume"  -- pluralizes better than 'smokes'
    , ifreq    = [(S_SMOKE, 1)]
    , iflavour = zipPlain [BrBlack]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "choke"  -- or "obscure"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 20  -- 4 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganBad S_WITHHOLDING (5 + 1 `d` 3)]
                    -- choking and tears, can roughly see, but not aim
    , idesc    = "Twirling clouds of grey smoke."
    , ikit     = []
    }
  boilingWater = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "boiling water"
    , ifreq    = [(S_BOILING_WATER, 1)]
    , iflavour = zipPlain [White]
    , icount   = 17  -- 18 causes 3 particles to hit the same actor 3 tiles away
    , irarity  = [(1, 1)]
    , iverbHit = "boil"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 30  -- 6 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [Burn 1]
    , idesc    = "It bubbles and hisses."
    , ikit     = []
    }
  glue = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "hoof glue"
    , ifreq    = [(S_GLUE, 1)]
    , iflavour = zipPlain [Cyan]
    , icount   = 8  -- Paralyze doesn't stack; avoid failure messages
    , irarity  = [(1, 1)]
    , iverbHit = "glue"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 10  -- 2 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [Paralyze 10]
    , idesc    = "Thick and clinging."
    , ikit     = []
    }
  waste = ItemKind
    { isymbol  = toContentSymbol '*'
    , iname    = "waste piece"
    , ifreq    = [(S_WASTE, 1)]
    , iflavour = zipPlain [Brown]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "splosh"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [ toOrganBad S_FOUL_SMELLING (30 + 1 `d` 10)
                 , toOrganBad S_DISPOSSESSED (10 + 1 `d` 5) ]
    , idesc    = "Sodden and foul-smelling."
    , ikit     = []
    }
  mistAntiSlow = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_ANTI_SLOW_MIST, 1)]
    , iflavour = zipFancy [BrYellow]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "propel"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [DropItem 1 1 COrgan S_SLOWED]
    , idesc    = "A cleansing rain."
    , ikit     = []
    }
  mistAntidote = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_ANTIDOTE_MIST, 1)]
    , iflavour = zipFancy [BrBlue]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "cure"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [DropItem 1 maxBound COrgan S_POISONED]
    , idesc    = "Washes away death's dew."
    , ikit     = []
    }
  mistSleep = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(S_SLEEP_MIST, 1)]
    , iflavour = zipFancy [BrMagenta]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "put to sleep"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [PutToSleep]
    , idesc    = "Lulls weary warriors."
    , ikit     = []
    }
  
  -- * Condition-inducing blasts
  
  -- Almost all have @toLinger 10@, that travels 2 steps in 1 turn.
  -- These are very fast projectiles, not getting into the way of big
  -- actors and not burdening the engine for long.
  -- A few are slower 'mists'.
  
  denseShower = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "dense shower"
    , ifreq    = [(S_DENSE_SHOWER, 1)]
    , iflavour = zipFancy [Green]
    , icount   = 12
    , irarity  = [(1, 1)]
    , iverbHit = "strengthen"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_STRENGTHENED 5]
    , idesc    = "A thick rain of droplets."
    , ikit     = []
    }
  sparseShower = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "sparse shower"
    , ifreq    = [(S_SPARSE_SHOWER, 1)]
    , iflavour = zipFancy [Red]
    , icount   = 8
    , irarity  = [(1, 1)]
    , iverbHit = "weaken"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganBad S_WEAKENED 7]
    , idesc    = "Light droplets that cling to clothing."
    , ikit     = []
    }
  protectingBalmMelee = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "balm droplet"
    , ifreq    = [(S_MELEE_PROTECTIVE_BALM, 1)]
    , iflavour = zipFancy [Brown]
    , icount   = 6
    , irarity  = [(1, 1)]
    , iverbHit = "balm"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganGood S_PROTECTED_FROM_MELEE (3 + 1 `d` 3)]
    , idesc    = "A thick ointment that hardens the skin."
    , ikit     = []
    }
  protectingBalmRanged = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "balm droplet"
    , ifreq    = [(S_RANGE_PROTECTIVE_BALM, 1)]
    , iflavour = zipPlain [BrYellow]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "balm"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_PROTECTED_FROM_RANGED (3 + 1 `d` 3)]
    , idesc    = "Grease that protects from flying death."
    , ikit     = []
    }
  defenselessnessRunout = ItemKind
    { isymbol  = toContentSymbol '?'
    , iname    = "PhD defense question"
    , ifreq    = [(S_DEFENSELESSNESS_RUNOUT, 1)]
    , iflavour = zipFancy [BrRed]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "nag"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganBad S_DEFENSELESS (3 + 1 `d` 3)]
    , idesc    = "Only the most learned make use of this."
    , ikit     = []
    }
  resolutionDust = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "resolution dust"
    , ifreq    = [(S_RESOLUTION_DUST, 1)]
    , iflavour = zipPlain [Brown]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "calm"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_RESOLUTE (3 + 1 `d` 3)]
                   -- short enough duration that @calmEnough@ not a big problem
    , idesc    = "A handful of honest earth, to strengthen the soul."
    , ikit     = []
    }
  hasteSpray = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "haste spray"
    , ifreq    = [(S_HASTE_SPRAY, 1)]
    , iflavour = zipFancy [BrYellow]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "haste"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_HASTED (3 + 1 `d` 3)]
    , idesc    = "A quick spurt."
    , ikit     = []
    }
  spreadNitrogen = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "slowness mist"
    , ifreq    = [(S_VIOLENT_SLOWNESS_MIST, 1)]
    , iflavour = zipPlain [BrBlack]
    , icount   = 15
    , irarity  = [(1, 1)]
    , iverbHit = "freeze"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 10  -- 2 steps, 2 turns, mist, slow
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganBad S_SLOWED (2 + 1 `d` 3)]
    , idesc    = "Colourless cold clammy fog, making each movement an effort."
    , ikit     = []
    }
  spreadNitrogen8 = spreadNitrogen
    { ifreq    = [(S_SLOWNESS_MIST, 1)]
    , icount   = 7
    , iaspects = [ toVelocity 5  -- 1 step, 1 turn, mist, slow
                 , SetFlag Fragile, SetFlag Blast ]
    }
  focusedNitrogen = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "slowness mist droplet"
    , ifreq    = [(S_FOCUSED_SLOWNESS_MIST, 1)]
    , iflavour = zipFancy [White]
    , icount   = 4 -- 28 in total vs 15, higher spread
    , irarity  = [(1, 1)]
    , iverbHit = "freeze"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toLinger 0  -- 0 steps, 1 turn
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [ OnSmash $ Explode S_SLOWNESS_MIST
                 , toOrganBad S_SLOWED (2 + 1 `d` 3) ]
    , idesc    = "Colourless and colder than ice."
    , ikit     = []
    }
  eyeDrop = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "eye drop"
    , ifreq    = [(S_EYE_DROP, 1)]
    , iflavour = zipFancy [BrCyan]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "cleanse"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_FAR_SIGHTED (3 + 1 `d` 3)]
    , idesc    = "Not to be taken orally."
    , ikit     = []
    }
  ironFiling = ItemKind  -- fast, short, strongly blinding blast
    { isymbol  = toContentSymbol '`'
    , iname    = "iron filing"
    , ifreq    = [(S_IRON_FILING, 1)]
    , iflavour = zipPlain [Red]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "blind"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganBad S_BLIND (10 + 1 `d` 10)]
    , idesc    = "A shaving of bright metal."
    , ikit     = []
    }
  smellyDroplet = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "smelly droplet"
    , ifreq    = [(S_SMELLY_DROPLET, 1)]
    , iflavour = zipFancy [Blue]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "sensitize"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_KEEN_SMELLING (5 + 1 `d` 3)]
    , idesc    = "A viscous lump that stains the skin."
    , ikit     = []
    }
  eyeShine = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "eye shine"
    , ifreq    = [(S_EYE_SHINE, 1)]
    , iflavour = zipFancy [Cyan]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "smear"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_SHINY_EYED (3 + 1 `d` 3)]
    , idesc    = "They almost glow in the dark."
    , ikit     = []
    }
  whiskeySpray = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "whiskey spray"
    , ifreq    = [(S_WHISKEY_SPRAY, 1)]
    , iflavour = zipFancy [Brown]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "inebriate"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [toOrganGood S_DRUNK (3 + 1 `d` 3)]
    , idesc    = "It burns in the best way."
    , ikit     = []
    }
  youthSprinkle = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "youth sprinkle"
    , ifreq    = [(S_YOUTH_SPRINKLE, 1)]
    , iflavour = zipFancy [BrGreen]
    , icount   = 16
    , irarity  = [(1, 1)]
    , iverbHit = "sprinkle"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [toLinger 10, SetFlag Fragile, SetFlag Blast]
    , ieffects = [ toOrganGood S_ROSE_SMELLING (40 + 1 `d` 20)
                 , toOrganNoTimer S_REGENERATING ]
    , idesc    = "Bright and smelling of the Spring."
    , ikit     = []
    }
  poisonCloud = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "poison cloud"
    , ifreq    = [(S_POISON_CLOUD, 1)]
    , iflavour = zipFancy [BrMagenta]
    , icount   = 11  -- low, to be less deadly in a tunnel, compared to single hit
    , irarity  = [(1, 1)]
    , iverbHit = "poison"
    , iweight  = 0  -- lingers, blocking path
    , idamage  = 0
    , iaspects = [ ToThrow $ ThrowMod 10 100 2  -- 2 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganNoTimer S_POISONED]
    , idesc    = "Choking gas that stings the eyes."
    , ikit     = []
    }
  pingFlash = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "flash"
    , ifreq    = [(S_PING_PLASH, 1)]
    , iflavour = zipFancy [Green]
    , icount   = 1
    , irarity  = [(1, 1)]
    , iverbHit = "ping"
    , iweight  = 1  -- to prevent blocking the way
    , idamage  = 0
    , iaspects = [ ToThrow $ ThrowMod 200 0 1  -- 1 step, .5 turn (necklaces)
                 , SetFlag Fragile, SetFlag Blast
                 , AddSkill SkShine 2 ]
    , ieffects = [OnSmash Yell]
    , idesc    = "A ping and a display flash from an echolocator out of sync momentarily."
    , ikit     = []
    }
  blastNoStat :: GroupName ItemKind -> ItemKind
  blastNoStat grp = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "mist"
    , ifreq    = [(blastNoStatOf grp, 1)]
    , iflavour = zipFancy [White]
    , icount   = 12
    , irarity  = [(1, 1)]
    , iverbHit = "drain"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 10  -- 2 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganBad grp (3 + 1 `d` 3)]
    , idesc    = "Completely disables one personal faculty."
    , ikit     = []
    }
  blastNoSkMove = blastNoStat S_IMMOBILE
  blastNoSkMelee = blastNoStat S_PACIFIED
  blastNoSkDisplace = blastNoStat S_IRREPLACEABLE
  blastNoSkAlter = blastNoStat S_RETAINING
  blastNoSkWait = blastNoStat S_IMPATIENT
  blastNoSkMoveItem = blastNoStat S_DISPOSSESSED
  blastNoSkProject = blastNoStat S_WITHHOLDING
  blastNoSkApply = blastNoStat S_PARSIMONIOUS
  blastBonusStat :: GroupName ItemKind -> ItemKind
  blastBonusStat grp = ItemKind
    { isymbol  = toContentSymbol '`'
    , iname    = "dew"
    , ifreq    = [(blastBonusStatOf grp, 1)]
    , iflavour = zipFancy [White]
    , icount   = 12
    , irarity  = [(1, 1)]
    , iverbHit = "elevate"
    , iweight  = 1
    , idamage  = 0
    , iaspects = [ toVelocity 10  -- 2 steps, 2 turns
                 , SetFlag Fragile, SetFlag Blast ]
    , ieffects = [toOrganGood grp (20 + 1 `d` 5)]
    , idesc    = "Temporarily enhances the given personal faculty."
    , ikit     = []
    }
  blastBonusSkMove = blastBonusStat S_MORE_MOBILE
  blastBonusSkMelee = blastBonusStat S_MORE_COMBATIVE
  blastBonusSkDisplace = blastBonusStat S_MORE_DISPLACING
  blastBonusSkAlter = blastBonusStat S_MORE_MODIFYING
  blastBonusSkWait = blastBonusStat S_MORE_PATIENT
  blastBonusSkMoveItem = blastBonusStat S_MORE_TIDY
  blastBonusSkProject = blastBonusStat S_MORE_PROJECTING
  blastBonusSkApply = blastBonusStat S_MORE_PRACTICAL
  