
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// Arcane-FX
// Copyright (C) Faust Logic, Inc.
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
// FLAME BROIL
//

$AdvancedLighting = ($pref::AFX::advancedFXLighting && !afxLegacyLighting());
$BrightLighting_mask = 0x800000; // BIT(23); 

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// CASTING ZODIAC

//
// The casting zodiac is created with three primary
// layers and two glows. Using additive blends helps
// to suggest that the patterns are projected light.
// The SHARED_freeze_XM transform modifier (defined in
// another file) is used to lock some of the zodiacs
// to their initial constraint positions.
// 

// A white glowing zodiac that fades in and
// out at start of casting-time
datablock afxZodiacData(FB_ZodeReveal_CE)
{  
  texture = $afxSpellDataPath @ "/FB/zodiacs/FB_caster_reveal";
  radius = 3.0;
  startAngle = 187.5; 
  rotationRate = -30.0;
  color = "1.0 1.0 1.0 1.0";
  blend = additive;
  interiorHorizontalOnly = true;
};
//
datablock afxEffectWrapperData(FB_ZodeReveal_EW)
{
  effect = FB_ZodeReveal_CE;
  posConstraint = caster;
  lifetime = 0.75;
  fadeInTime = 0.5;
  fadeOutTime = 0.25;
  xfmModifiers[0] = SHARED_freeze_XM;
};

if ($AdvancedLighting)
{
  %FB_MainZodeRevealLight_TLK_intensity = 5.0;

  datablock afxXM_LocalOffsetData(FB_MainZodeRevealLight_offset_XM)
  {
    localOffset = "0 2 -4";
  };
  datablock afxXM_SpinData(FB_MainZodeRevealLight_spin1_XM)
  {
    spinAxis = "0 0 1";
    spinAngle = 0;
    spinRate = -30;
  };
  datablock afxXM_SpinData(FB_MainZodeRevealLight_spin2_XM : FB_MainZodeRevealLight_spin1_XM)
  {
    spinAngle = 120;
  };
  datablock afxXM_SpinData(FB_MainZodeRevealLight_spin3_XM : FB_MainZodeRevealLight_spin1_XM)
  {
    spinAngle = 240;
  };

  datablock afxLightData(FB_MainZodeRevealLight_TLK_CE)
  {
    type = "Spot";
    radius = 5;
    direction = "0 -0.313 -0.95";
    sgCastsShadows = false;
    color = 1.0*%FB_MainZodeRevealLight_TLK_intensity SPC
            1.0*%FB_MainZodeRevealLight_TLK_intensity SPC
            1.0*%FB_MainZodeRevealLight_TLK_intensity;
  };

  datablock afxEffectWrapperData(FB_MainZodeRevealLight_1_TLK_EW : FB_ZodeReveal_EW)
  {
    effect = FB_MainZodeRevealLight_TLK_CE;
    xfmModifiers[1] = FB_MainZodeRevealLight_spin1_XM;
    xfmModifiers[2] = FB_MainZodeRevealLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_MainZodeRevealLight_2_TLK_EW : FB_ZodeReveal_EW)
  {
    effect = FB_MainZodeRevealLight_TLK_CE;
    xfmModifiers[1] = FB_MainZodeRevealLight_spin2_XM;
    xfmModifiers[2] = FB_MainZodeRevealLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_MainZodeRevealLight_3_TLK_EW : FB_ZodeReveal_EW)
  {
    effect = FB_MainZodeRevealLight_TLK_CE;
    xfmModifiers[1] = FB_MainZodeRevealLight_spin3_XM;
    xfmModifiers[2] = FB_MainZodeRevealLight_offset_XM;
  };

  $FB_MainZodeRevealLight_1_TLK = FB_MainZodeRevealLight_1_TLK_EW;
  $FB_MainZodeRevealLight_2_TLK = FB_MainZodeRevealLight_2_TLK_EW;
  $FB_MainZodeRevealLight_3_TLK = FB_MainZodeRevealLight_3_TLK_EW;
}
else
{
  $FB_MainZodeRevealLight_1_TLK = "";
  $FB_MainZodeRevealLight_2_TLK = "";
  $FB_MainZodeRevealLight_3_TLK = "";
}

// An orange/red zodiac.
datablock afxZodiacData(FB_Zode1_CE)
{  
  texture = $afxSpellDataPath @ "/FB/zodiacs/FB_caster";
  radius = 3.0;
  startAngle = 180.0;
  rotationRate = -30.0;
  color = "1.0 1.0 1.0 0.8";
  blend = additive;
  interiorHorizontalOnly = true;
};
//
datablock afxEffectWrapperData(FB_Zode1_EW)
{
  effect = FB_Zode1_CE;
  posConstraint = caster;
  delay = 0.25;
  fadeInTime = 0.75;
  fadeOutTime = 1.0;
  lifetime = 3.0;
  xfmModifiers[0] = SHARED_freeze_XM;
};

// Main Zode Underglow
//  Glowing zodiacs blended additively tend to be washed-out atop
//  light groundplanes, as is the case with TLK and the sand-colored
//  ground in the demo.  To make them visually "pop" the ground must
//  be darkened, and this is done here.  The "underglow" zodiac is
//  a copy of the glow zodiac that is blended normally.  Because the
//  glow zodiacs have halos extending beyond their opaque regions
//  that blend with black, the ground is subtly darkened.  As the
//  glow is layered atop it -- it pops!  Increasing the color value
//  increases the effect.
datablock afxZodiacData(FB_Zode1_TLKunderglow_CE : FB_Zode1_CE)
{
  texture = $afxSpellDataPath @ "/FB/zodiacs/FB_caster-underglow256";
  color = "0.5 0.5 0.5 0.5";
  blend = normal;
};
//
datablock afxEffectWrapperData(FB_Zode1_TLKunderglow_EW : FB_Zode1_EW)
{
  effect = FB_Zode1_TLKunderglow_CE;
  execConditions = $BrightLighting_mask;
};

// A sparse orange zodiac with inner rune ring
// and outer skulls.
datablock afxZodiacData(FB_Zode2_CE)
{  
  texture = $afxSpellDataPath @ "/shared/zodiacs/zode_text";
  radius = 3.0;
  startAngle = 180.0;
  rotationRate = 20.0;
  color = "1.0 0.0 0.0 1.0";
  blend = additive;
  interiorHorizontalOnly = true;
};
//
datablock afxEffectWrapperData(FB_Zode2_EW)
{
  effect = FB_Zode2_CE;
  posConstraint = caster;
  delay = 0.25;
  fadeInTime = 0.75;
  fadeOutTime = 1.0;
  lifetime = 3.0;
  xfmModifiers[0] = SHARED_freeze_XM;
};

// Runes & Skulls Zode Underglow
//  Here the zode is made black but only slightly opaque to subtly
//  darken the ground, making the additive glow zode appear more
//  saturated.
datablock afxZodiacData(FB_Zode2_TLKunderglow_CE : FB_Zode2_CE)
{
  color = "0 0 0 0.25";
  blend = normal;
};
//
datablock afxEffectWrapperData(FB_Zode2_TLKunderglow_EW : FB_Zode2_EW)
{
  effect = FB_Zode2_TLKunderglow_CE;
  execConditions = $BrightLighting_mask;
};

// A white zodiac with sketchy runes. 
datablock afxZodiacData(FB_Zode3_CE)
{  
  texture = $afxSpellDataPath @ "/FB/zodiacs/FB_caster-symbols";
  radius = 3.0;
  startAngle = 180.0;
  rotationRate = -30.0;
  color = "1.0 1.0 1.0 0.5";
  blend = additive;
  interiorHorizontalOnly = true;
};
//
datablock afxEffectWrapperData(FB_Zode3_EW)
{
  effect = FB_Zode3_CE;
  posConstraint = caster;
  delay = 0.25;
  fadeInTime = 0.75;
  fadeOutTime = 1.0;
  lifetime = 3.0;
  xfmModifiers[0] = SHARED_freeze_XM;
};

// A white glowing zodiac that fades in and out at middle
// of casting-time. It establishes the circle where the 
// ring-of-fire emerges.
datablock afxZodiacData(FB_ZodeGlowRing_CE)
{  
  texture = $afxSpellDataPath @ "/FB/zodiacs/FB_glowring";
  radius = 3.0;
  startAngle = 165.0;
  rotationRate = -30.0;
  color = "1.0 1.0 1.0 1.0";
  blend = additive;
  interiorHorizontalOnly = true;
};
//
datablock afxEffectWrapperData(FB_ZodeGlowRing_EW)
{
  effect = FB_ZodeGlowRing_CE;
  posConstraint = caster;
  delay = 0.6;
  lifetime = 1.25;
  fadeInTime = 0.6;
  fadeOutTime = 0.25;
  xfmModifiers[0] = SHARED_freeze_XM;
};

if ($AdvancedLighting)
{
  %FB_ZodeGlowRingLight_TLK_intensity = 1.0;

  datablock afxXM_LocalOffsetData(FB_ZodeGlowRingLight_offset_XM)
  {
    localOffset = "0 2 -4";
  };
  datablock afxXM_SpinData(FB_ZodeGlowRingLight_spin1_XM)
  {
    spinAxis = "0 0 1";
    spinAngle = 0-60;
    spinRate = -30;
  };
  datablock afxXM_SpinData(FB_ZodeGlowRingLight_spin2_XM : FB_ZodeGlowRingLight_spin1_XM)
  {
    spinAngle = 120-60;
  };
  datablock afxXM_SpinData(FB_ZodeGlowRingLight_spin3_XM : FB_ZodeGlowRingLight_spin1_XM)
  {
    spinAngle = 240-60;
  };

  // main zode reveal light
  datablock afxLightData(FB_ZodeGlowRingLight_TLK_CE)
  {
    type = "Spot";
    radius = 5;
    direction = "0 -0.313 -0.95";
    sgCastsShadows = false;
    color = 1.0*%FB_MainZodeRevealLight_TLK_intensity SPC
            1.0*%FB_MainZodeRevealLight_TLK_intensity SPC
            1.0*%FB_MainZodeRevealLight_TLK_intensity;
  };

  datablock afxEffectWrapperData(FB_ZodeGlowRingLight_1_TLK_EW : FB_ZodeGlowRing_EW)
  {
    effect = FB_ZodeGlowRingLight_TLK_CE;
    lifetime = 0.7; //1.25;

    xfmModifiers[1] = FB_ZodeGlowRingLight_spin1_XM;
    xfmModifiers[2] = FB_ZodeGlowRingLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_ZodeGlowRingLight_2_TLK_EW : FB_ZodeGlowRingLight_1_TLK_EW)
  {
    xfmModifiers[1] = FB_ZodeGlowRingLight_spin2_XM;
    xfmModifiers[2] = FB_ZodeGlowRingLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_ZodeGlowRingLight_3_TLK_EW : FB_ZodeGlowRingLight_1_TLK_EW)
  {
    xfmModifiers[1] = FB_ZodeGlowRingLight_spin3_XM;
    xfmModifiers[2] = FB_ZodeGlowRingLight_offset_XM;
  };

  $FB_ZodeGlowRingLight_1_TLK = FB_ZodeGlowRingLight_1_TLK_EW;
  $FB_ZodeGlowRingLight_2_TLK = FB_ZodeGlowRingLight_2_TLK_EW;
  $FB_ZodeGlowRingLight_3_TLK = FB_ZodeGlowRingLight_3_TLK_EW;
}
else
{
  $FB_ZodeGlowRingLight_1_TLK = "";
  $FB_ZodeGlowRingLight_2_TLK = "";
  $FB_ZodeGlowRingLight_3_TLK = "";
}


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// RING OF FIRE

//
// The ring-of-fire is created by layering ten emitters that 
// orbit the caster at ground level. To fill out the ring, 
// the emitters start out at different angles distributed 
// around the circle, and also move at varying rates in both
// clockwise and counter-clockwise directions.  
//

//
// This particle system is the main component used in the
// ring-of-fire and also by the fireball missile.
//
datablock ParticleData(FB_Flames_P)
{
   textureName          = $afxSpellDataPath @ "/FB/particles/FB_fireZodiac";
   dragCoeffiecient     = 0.5;
   inheritedVelFactor   = 0.00;
   lifetimeMS           = 900;
   lifetimeVarianceMS   = 200;
   useInvAlpha          = false;
   spinRandomMin        = -720.0;
   spinRandomMax        = 720.0;
   colors[0]            = "1.0 1.0 1.0 1.0";
   colors[1]            = "1.0 1.0 0.0 1.0";
   colors[2]            = "1.0 0.0 0.0 1.0";
   colors[3]            = "1.0 0.0 0.0 0.0";
   sizes[0]             = 0.6;
   sizes[1]             = 1.05;
   sizes[2]             = 0.5;
   sizes[3]             = 0.15;
   times[0]             = 0.0;
   times[1]             = 0.2;
   times[2]             = 0.55;
   times[3]             = 1.0;
};
//
datablock ParticleEmitterData(FB_Flames_E)
{
  ejectionOffset        = 0.02;
  ejectionPeriodMS      = 10;
  periodVarianceMS      = 0;
  ejectionVelocity      = 1.2;
  velocityVariance      = 0.9;
  thetaMin              = 0.0;
  thetaMax              = 0.0;
  particles             = FB_Flames_P;
};

// this offset defines the radius of ring-of-fire
datablock afxXM_LocalOffsetData(FB_FireRing_offset_XM)
{
  localOffset = "0 1.75 0";
};

datablock afxXM_GroundConformData(FB_FireRing_ground_XM)
{
  height = 0.01;
};

// this and the other spin modifiers set the starting
// angle and rotation rate of the ring-of-fire emitters.
datablock afxXM_SpinData(FB_FireRing_spin1_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 0;
  spinRate = 900;
};
//
datablock afxEffectWrapperData(FB_FireRing1_EW)
{
  effect = FB_Flames_E;
  posConstraint = caster;
  delay = 1.35; //1.5-.25
  lifetime = 1.6; //1.25
  xfmModifiers[0] = "FB_FireRing_spin1_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin2_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 60;
  spinRate = 500;
};
//
datablock afxEffectWrapperData(FB_FireRing2_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin2_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin3_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 120;
  spinRate = -850;
};
//
datablock afxEffectWrapperData(FB_FireRing3_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin3_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin4_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 180;
  spinRate = 600;
};
//
datablock afxEffectWrapperData(FB_FireRing4_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin4_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin5_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 240;
  spinRate = -560;
};
//
datablock afxEffectWrapperData(FB_FireRing5_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin5_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin6_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 300;
  spinRate = -360;
};
//
datablock afxEffectWrapperData(FB_FireRing6_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin6_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin7_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 30;
  spinRate = -780;
};
//
datablock afxEffectWrapperData(FB_FireRing7_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin7_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin8_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 90;
  spinRate = 450;
};
//
datablock afxEffectWrapperData(FB_FireRing8_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin8_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin9_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 150;
  spinRate = -700;
};
//
datablock afxEffectWrapperData(FB_FireRing9_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin9_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};

datablock afxXM_SpinData(FB_FireRing_spin10_XM)
{
  spinAxis = "0 0 1";
  spinAngle = 210;
  spinRate = -340;
};
//
datablock afxEffectWrapperData(FB_FireRing10_EW : FB_FireRing1_EW)
{
  xfmModifiers[0] = "FB_FireRing_spin10_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
  xfmModifiers[2] = "FB_FireRing_ground_XM";
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// RING-OF-FIRE LIGHTS

//
// If the $AdvancedLighting flag is set (see top of file), light from
// the ring of fire is simultated using two point lights positioned
// below the caster.  Paths are used to simulate a subtle flicker.
//

if ($AdvancedLighting)
{
  %FB_FireRingLight_TLK_intensity = 5.0;

  // this offset defines the lights distance beneath the terrain
  datablock afxXM_LocalOffsetData(FB_FireRingLight_offset_XM)
  {
    localOffset = "0 0 -4";
  };

  // flicker path 1
  datablock afxPathData(FB_FireRingLight_TLK_1_Path)
  {
    points = " 0    0    0"   SPC
             " 0.1 -0.3  0.8" SPC
             "-0.3  0.2 -0.6" SPC
             " 0.0 -0.6  0.4" SPC
             " -0.7 0.4 -0.8" SPC
             " 0    0    0";
    lifetime = 0.25;
    loop = cycle;
    mult = 0.06;
  };
  //
  datablock afxXM_PathConformData(FB_FireRingLight_TLK_1_path_XM)
  {
    paths = "FB_FireRingLight_TLK_1_Path";
  };

  // flicker path 2
  datablock afxPathData(FB_FireRingLight_TLK_2_Path)
  {
    points = " 0    0    0"   SPC
             " 0.4  0.7 -0.3" SPC
             "-0.3  0.0  0.4" SPC
             " 0.2  0.4 -0.8" SPC
             "-0.4 -0.8  0.5" SPC
             " 0    0    0";
    lifetime = 0.20;
    loop = cycle;
    mult = 0.05;
  };
  //
  datablock afxXM_PathConformData(FB_FireRingLight_TLK_2_path_XM)
  {
    paths = "FB_FireRingLight_TLK_2_Path";
  };

  // ring-of-fire lights  (illuminate dts beyond radius???)
  datablock afxLightData(FB_FireRingLight_TLK_CE)
  {
    type = "Point";
    radius = 5;
    sgCastsShadows = false;
    sgDoubleSidedAmbient = true;  // necessary for interiors?

    sgLightingModelName = "SG - Near Linear (Lighting Pack)";
    color = 1.0*%FB_FireRingLight_TLK_intensity SPC
            0.5*%FB_FireRingLight_TLK_intensity SPC
            0.0*%FB_FireRingLight_TLK_intensity;
  };
  //
  datablock afxEffectWrapperData(FB_FireRingLight_1_TLK_EW)
  {
    effect = FB_FireRingLight_TLK_CE;
    posConstraint = caster;

    delay = 1.35; //1.5-.25
    fadeInTime  = 0.5;
    fadeOutTime = 0.5;
    lifetime = 1.6; //1.25
    xfmModifiers[0] = "FB_FireRingLight_offset_XM";

    xfmModifiers[1] = FB_FireRingLight_TLK_1_path_XM;
  };
  datablock afxEffectWrapperData(FB_FireRingLight_2_TLK_EW : FB_FireRingLight_1_TLK_EW)
  {
    xfmModifiers[1] = FB_FireRingLight_TLK_2_path_XM;
  };

  datablock afxXM_LocalOffsetData(FB_FireRingSpotLight_offset_XM)
  {
    localOffset = "0 2 -4";
  };
  datablock afxXM_SpinData(FB_FireRingSpotLight_spin1_XM)
  {
    spinAxis = "0 0 1";
    spinAngle = 0;
    spinRate = -30;
  };
  datablock afxXM_SpinData(FB_FireRingSpotLight_spin2_XM : FB_FireRingSpotLight_spin1_XM)
  {
    spinAngle = 120;
  };
  datablock afxXM_SpinData(FB_FireRingSpotLight_spin3_XM : FB_FireRingSpotLight_spin1_XM)
  {
    spinAngle = 240;
  };
  datablock afxLightData(FB_FireRingSpotLight_TLK_CE)
  {
    type = "Spot";
    radius = 5;
    direction = "0 -0.313 -0.95";
    sgSpotAngle = 100;
    sgCastsShadows = false;

    sgLocalAmbientAmount = 0.2;
    sgDoubleSidedAmbient = true;

    color = 1.0*%FB_FireRingLight_TLK_intensity*2 SPC
            0.5*%FB_FireRingLight_TLK_intensity*2 SPC
            0.0*%FB_FireRingLight_TLK_intensity*2;
    ambientColor = 1.0*%FB_FireRingLight_TLK_intensity SPC
            0.5*%FB_FireRingLight_TLK_intensity SPC
            0.0*%FB_FireRingLight_TLK_intensity;
  };
  datablock afxEffectWrapperData(FB_FireRingSpotLight_1_TLK_EW)
  {
    effect = FB_FireRingSpotLight_TLK_CE;
    posConstraint = caster;
    delay = 1.35;
    fadeInTime  = 0.5;
    fadeOutTime = 0.5;
    lifetime = 1.6;
    xfmModifiers[0] = FB_FireRingSpotLight_spin1_XM;
    xfmModifiers[1] = FB_FireRingSpotLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_FireRingSpotLight_2_TLK_EW : FB_FireRingSpotLight_1_TLK_EW)
  {
    xfmModifiers[0] = FB_FireRingSpotLight_spin2_XM;
    xfmModifiers[1] = FB_FireRingSpotLight_offset_XM;
  };
  datablock afxEffectWrapperData(FB_FireRingSpotLight_3_TLK_EW : FB_FireRingSpotLight_1_TLK_EW)
  {
    xfmModifiers[0] = FB_FireRingSpotLight_spin3_XM;
    xfmModifiers[1] = FB_FireRingSpotLight_offset_XM;
  };

  $FB_FireRingLight_1_TLK = FB_FireRingLight_1_TLK_EW;
  $FB_FireRingLight_2_TLK = FB_FireRingLight_2_TLK_EW;

  $FB_FireRingSpotLight_1_TLK = FB_FireRingSpotLight_1_TLK_EW;
  $FB_FireRingSpotLight_2_TLK = FB_FireRingSpotLight_2_TLK_EW;
  $FB_FireRingSpotLight_3_TLK = FB_FireRingSpotLight_3_TLK_EW;
}
else
{
  $FB_FireRingLight_1_TLK = "";
  $FB_FireRingLight_2_TLK = "";
  $FB_FireRingSpotLight_1_TLK = "";
  $FB_FireRingSpotLight_2_TLK = "";
  $FB_FireRingSpotLight_3_TLK = "";
}


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// SPELLCASTER ANIMATION
//

// caster performs a summoning animation 
datablock afxAnimClipData(FB_SummonFire_Clip_CE)
{
  clipName = "summon";
  rate = 0.45;
};
datablock afxEffectWrapperData(FB_SummonFire_Clip_EW)
{
  effect = FB_SummonFire_Clip_CE;
  constraint = "caster";
  lifetime = 1.0;
  delay = 0.5;
};

// caster performs a casting animation 
datablock afxAnimClipData(FB_Casting1_Clip_CE)
{
  clipName = "casting1";
  rate = 1.8;
};
datablock afxEffectWrapperData(FB_Casting1_Clip_EW)
{
  effect = FB_Casting1_Clip_CE;
  constraint = "caster";
  delay = 1.8;
};

// caster performs a throwing animation 
datablock afxAnimClipData(FB_Casting2_Clip_CE)
{
  clipName = "finish1";
  rate = 0.7;
};
datablock afxEffectWrapperData(FB_Casting2_Clip_EW)
{
  effect = FB_Casting2_Clip_CE;
  constraint = "caster";
  delay = 2.8;
  lifetime = 2.0; 
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// FIREBALL

//
// here the fire particles are used to make a fireball
// appear in the caster's right hand.
//
datablock afxEffectWrapperData(FB_FireballEmerge_EW)
{
  effect = FB_Flames_E;
  posConstraint = "caster.Bip01 R Hand";  
  delay = 2.0;
  fadeInTime  = 0.1;
  fadeOutTime = 0.3;
  lifetime = 0.7;
};

// this light coordinates with FB_FireballEmerge_EW to create
// a fireball in the caster's right hand.
//
datablock afxLightData(FB_FireballRevealLight_CE)
{
  type = "Point";  
  radius = 4;
  color  = "1.0 0.6 0.0";
};
//
datablock afxEffectWrapperData(FB_FireballRevealLight_EW)
{
  effect = FB_FireballRevealLight_CE;
  posConstraint = "caster.Bip01 R Hand";  
  delay = 2.7;
  fadeInTime  = 0.4;
  fadeOutTime = 0.1;
  lifetime = 0.9;
};

if ($AdvancedLighting)
{
  datablock sgUniversalStaticLightData(FB_FireballLight1_TLK_CE) 
  {
    CastsShadows = false;
    Radius = 3.0;
    Brightness = 0.75*0.5;
    Colour = "1.0 0.6 0.0";

    FlareOn = true;
    LinkFlare = true;
    FlareBitmap = $afxSpellDataPath @ "/GBoF/lights/GBoF_firePortalFlare";
    NearSize = 1*2.0;
    FarSize  = 0.5*2.0;
    NearDistance = 2;
    FarDistance  = 50;

    AnimBrightness = true;
    LerpBrightness = true;
    MinBrightness = 0.3;
    MaxBrightness = 0.9;
    BrightnessKeys = "AZA";
    BrightnessTime = 0.1;

    AnimRotation = true;
    LerpRotation = true;
    MinRotation = 0;
    MaxRotation = 359;
    RotationKeys = "AZA";
    RotationTime = 1.5*0.2;
  };
  datablock sgUniversalStaticLightData(FB_FireballLight2_TLK_CE : FB_FireballLight1_TLK_CE) 
  {
    BrightnessTime = 0.15;
    RotationTime   = 2.0*0.2;
  };

  datablock afxEffectWrapperData(FB_FireballRevealLight1_TLK_EW : FB_FireballRevealLight_EW)
  {
    effect = FB_FireballLight1_TLK_CE;
    delay = 2.7-0.5;
    fadeInTime  = 0.2;
    lifetime = 0.9+0.5;
  };
  datablock afxEffectWrapperData(FB_FireballRevealLight2_TLK_EW : FB_FireballRevealLight1_TLK_EW)
  {
    effect = FB_FireballLight2_TLK_CE;
  };

  $FB_FireballRevealLight1 = FB_FireballRevealLight1_TLK_EW;
  $FB_FireballRevealLight2 = FB_FireballRevealLight2_TLK_EW;
}
else
{
  $FB_FireballRevealLight1 = FB_FireballRevealLight_EW;
  $FB_FireballRevealLight2 = "";
}


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// IMPACT SHOCKWAVE
//

datablock afxZodiacData(FB_ImpactZodeFast_CE)
{  
  texture = $afxSpellDataPath @ "/shared/zodiacs/zode_impactA";
  radius = 1.0;
  startAngle = 0.0;
  rotationRate = 0.0;  
  color = "1.0 1.0 1.0 0.10";
  blend = additive;
  growthRate = 110.0;
  showOnInteriors = false;
};

// A fast growing zodiac used as an impact shockwave.
datablock afxEffectWrapperData(FB_ImpactZodeFast_EW)
{
  effect = FB_ImpactZodeFast_CE;
  posConstraint = "impactPoint";
  delay = 0.05;
  fadeInTime = 0.0;
  fadeOutTime = 0.5;
  lifetime = 0.5;
  xfmModifiers[0] = SHARED_freeze_XM;
  execConditions[0] = $AFX::IMPACTED_PRIMARY;
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// SOUNDS

// casting sounds //

datablock AudioProfile(FB_ZodeSnd_CE)
{
   fileName = $afxSpellDataPath @ "/GBoF/sounds/gbof_zodiac.ogg";
   description = SpellAudioCasting_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_ZodeSnd_EW)
{
  effect = FB_ZodeSnd_CE;
  constraint = "caster";
  delay = 0;
  lifetime = 1.907;
};

datablock AudioProfile(FB_ConjureSnd_CE)
{
   fileName = $afxSpellDataPath @ "/FB/sounds/fb_conjure.ogg";
   description = SpellAudioCasting_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_ConjureSnd_EW)
{
  effect = FB_ConjureSnd_CE;
  constraint = "caster";
  delay = 0.6;
  lifetime = 1.907;
};

datablock AudioProfile(FB_FireRingSnd_CE)
{
   fileName = $afxSpellDataPath @ "/FB/sounds/fb_firering.ogg";
   description = SpellAudioCasting_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_FireRingSnd_EW)
{
  effect = FB_FireRingSnd_CE;
  constraint = "caster";
  delay = 1.33;
  lifetime = 2.296;
};

// impact sounds //

datablock AudioProfile(FB_Impact1ASnd_CE)
{
   fileName = $afxSpellDataPath @ "/fb/sounds/fb_impact1a.ogg";
   description = SpellAudioImpact_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_Impact1ASnd_EW)
{
  effect = FB_Impact1ASnd_CE;
  constraint = "impactedObject";
  delay = 0;
  lifetime = 2.417;
};

datablock AudioProfile(FB_Impact1BSnd_CE)
{
   fileName = $afxSpellDataPath @ "/fb/sounds/fb_impact1b.ogg";
   description = SpellAudioImpact_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_Impact1BSnd_EW)
{
  effect = FB_Impact1BSnd_CE;
  posConstraint = "impactPoint";
  delay = 0;
  lifetime = 2.191;
  execConditions[0] = $AFX::IMPACTED_SOMETHING;
};

// fireball sounds //

datablock AudioProfile(FB_FireBallSnd_CE)
{
   fileName = $afxSpellDataPath @ "/GBoF/sounds/projectile_loopFire1a_SR.ogg";
   description = SpellAudioMissileLoop_AD;
   preload = false;
};
datablock afxEffectWrapperData(FB_FireBallSnd_EW)
{
  effect = FB_FireBallSnd_CE;
  posConstraint = "caster.Bip01 R Hand";  
  delay = 1.8;
  lifetime = 1.5;
  fadeInTime = 0.5;
  fadeOutTime = 0.5;
};

datablock AudioProfile(FB_FireCrackle_CE)
{
   fileName = $afxSpellDataPath @ "/FB/sounds/fireloop.ogg";
   description = SpellAudioLoop_AD;
   preload = false;
};

datablock afxEffectWrapperData(FB_FireCrackle1_EW)
{
  effect = FB_FireCrackle_CE;
  constraint = "caster";
  delay = 1.33;
  lifetime = 1.35;
  fadeInTime = 0.6;
  fadeOutTime = 1.25;
  scaleFactor = 0.4;
  xfmModifiers[0] = "FB_FireRing_spin6_XM";
  xfmModifiers[1] = "FB_FireRing_offset_XM";
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// DAMAGE

datablock afxDamageData(FB_dot_damage_CE)
{
  label = "fb_dot";
  flavor = "fire";
  directDamage = 3;
  directDamageRepeats = 6;
};

datablock afxEffectWrapperData(FB_dot_damage_EW)
{
  effect = FB_dot_damage_CE;
  posConstraint = "impactPoint";
  posConstraint2 = "impactedObject"; 
  lifetime = 6;
  execConditions[0] = $AFX::IMPACTED_PRIMARY;
};


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// FIREBALL MISSILE

datablock afxMagicMissileData(FB_Fireball)
{
  particleEmitter = FB_Flames_E;
  muzzleVelocity = 30;
  velInheritFactor = 0;
  lifetime = 20000;
  isBallistic = true;
  ballisticCoefficient = 0.95;
  gravityMod = 0.05;
  isGuided  = true;
  precision = 50;
  trackDelay  = 7;
  sound = FB_FireBallSnd_CE;

  // NOTE - Replace launchNode with best node given the character's skeleton
  // and casting animation.
  launchNode = "Bip01 R Hand";

  // NOTE - The character is not animating on the server, so a fixed launch point
  // approximating the correct location is set. (launchOffsetServer overrides
  // launchNode on the server.) By setting echoLaunchOffset to true, you can see
  // in the console what offset is used on the client and use that for the
  // launchOffsetServer value.
  launchOffsetServer = "0.49 1.20 1.88";
  echoLaunchOffset = false;
};

if ($AdvancedLighting)
{
  datablock afxEffectWrapperData(FB_FireballFlare1_TLK_EW)
  {
    effect = FB_FireballLight1_TLK_CE;
    constraint = missile;
  };
  datablock afxEffectWrapperData(FB_FireballFlare2_TLK_EW : FB_FireballFlare1_TLK_EW)
  {
    effect = FB_FireballLight2_TLK_CE;
  };

  $FB_MissileLight_Flare1 = FB_FireballFlare1_TLK_EW;
  $FB_MissileLight_Flare2 = FB_FireballFlare2_TLK_EW;
}
else
{
  datablock afxEffectWrapperData(FB_FireballFlare_EW)
  {
    effect = FB_FireballRevealLight_CE;
    constraint = missile;
  };

  $FB_MissileLight_Flare1 = FB_FireballFlare_EW;
  $FB_MissileLight_Flare2 = 0;
}



if ($AdvancedLighting)
{
  %FireFX_ImpactLight1_TLK_intensity = 10.0;
  datablock afxLightData(FireFX_ImpactLight1_TLK_CE)
  {
    type = "Point";
    radius = 9;
    sgCastsShadows = false;
    sgDoubleSidedAmbient = true;
    color = 1.0*%FireFX_ImpactLight1_TLK_intensity SPC
            1.0*%FireFX_ImpactLight1_TLK_intensity SPC
            1.0*%FireFX_ImpactLight1_TLK_intensity;
  };
  datablock sgUniversalStaticLightData(FireFX_ImpactLight1_flare_TLK_CE) 
  {
    CastsShadows = false;
    Radius = 10;
    Brightness = %FireFX_ImpactLight1_TLK_intensity;
    Colour = "1.0 1.0 1.0";

    FlareOn = true;
    LinkFlare = true;
    FlareBitmap = "common/lighting/lightFalloffMono"; //corona"; //lightFalloffMono";
    NearSize = 20;
    FarSize  = 8;
    NearDistance = 2;
    FarDistance  = 50;
  };
  // flare line-of-sight...
  datablock afxXM_LocalOffsetData(FB_ImpactFlare_offset_XM)
  {
    localOffset = "0 0 1.5";
  };
  //
  datablock afxEffectWrapperData(FireFX_ImpactLight1_TLK_EW : FireFX_ImpactLight1_EW)
  {
    effect = FireFX_ImpactLight1_flare_TLK_CE; //FireFX_ImpactLight1_TLK_CE;
    xfmModifiers[0] = "FB_ImpactFlare_offset_XM";
  };

  %FireFX_ImpactLight2_TLK_intensity = 5.0;
  datablock afxLightData(FireFX_ImpactLight2_TLK_CE)
  {
    type = "Point";
    radius = 18;
    sgCastsShadows = true;
    sgDoubleSidedAmbient = true;
    color = 1.0*%FireFX_ImpactLight2_TLK_intensity SPC
            0.2*%FireFX_ImpactLight2_TLK_intensity SPC
            0.0*%FireFX_ImpactLight2_TLK_intensity;
  };
  datablock sgUniversalStaticLightData(FireFX_ImpactLight2_flare_TLK_CE) 
  {
    CastsShadows = false;
    Radius = 18;
    Brightness = %FireFX_ImpactLight2_TLK_intensity;
    Colour = "1.0 0.2 0.0";

    FlareOn = true;
    LinkFlare = true;
    FlareBitmap = "common/lighting/corona"; //corona"; //lightFalloffMono";
    NearSize = 20*1.5;
    FarSize  = 8*1.5;
    NearDistance = 2;
    FarDistance  = 50;
  };
  //
  datablock afxEffectWrapperData(FireFX_ImpactLight2_TLK_EW : FireFX_ImpactLight1_EW)
  {
    effect = FireFX_ImpactLight2_flare_TLK_CE; //FireFX_ImpactLight2_TLK_CE;
    delay    = 0.05;
    xfmModifiers[0] = "FB_ImpactFlare_offset_XM";
  };

  $FB_ImpactLight_1 = FireFX_ImpactLight1_TLK_EW;
  $FB_ImpactLight_2 = FireFX_ImpactLight2_TLK_EW;
}
else
{
  $FB_ImpactLight_1 = FireFX_ImpactLight1_EW;
  $FB_ImpactLight_2 = FireFX_ImpactLight1_EW;
}


//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//
// FLAME BROIL SPELL
//

datablock afxMagicSpellData(FlameBroilSpell)
{
  castingDur = 3.0;
  lingerDur = 6.0;

    // magic missile //
  missile = FB_Fireball;

    // casting zodiac //
  addCastingEffect = FB_ZodeReveal_EW;
  addCastingEffect = $FB_MainZodeRevealLight_1_TLK;
  addCastingEffect = $FB_MainZodeRevealLight_2_TLK;
  addCastingEffect = $FB_MainZodeRevealLight_3_TLK;
  addCastingEffect = FB_Zode1_TLKunderglow_EW;
  addCastingEffect = FB_Zode1_EW;
  addCastingEffect = FB_Zode2_TLKunderglow_EW;
  addCastingEffect = FB_Zode2_EW;
  addCastingEffect = FB_Zode3_EW;
  addCastingEffect = FB_ZodeGlowRing_EW;
  addCastingEffect = $FB_ZodeGlowRingLight_1_TLK;
  addCastingEffect = $FB_ZodeGlowRingLight_2_TLK;
  addCastingEffect = $FB_ZodeGlowRingLight_3_TLK;
    // ring-of-fire //
  addCastingEffect = FB_FireRing1_EW;
  addCastingEffect = FB_FireRing2_EW;
  addCastingEffect = FB_FireRing3_EW;
  addCastingEffect = FB_FireRing4_EW;
  addCastingEffect = FB_FireRing5_EW;
  addCastingEffect = FB_FireRing6_EW;
  addCastingEffect = FB_FireRing7_EW;
  addCastingEffect = FB_FireRing8_EW;
  addCastingEffect = FB_FireRing9_EW;
  addCastingEffect = FB_FireRing10_EW;
   // ring-of-fire lights //
  addCastingEffect = $FB_FireRingLight_1_TLK;
  addCastingEffect = $FB_FireRingLight_2_TLK;
  addCastingEffect = $FB_FireRingSpotLight_1_TLK;
  addCastingEffect = $FB_FireRingSpotLight_2_TLK;
  addCastingEffect = $FB_FireRingSpotLight_3_TLK;
   // spellcaster animation //
  addCastingEffect = FB_SummonFire_Clip_EW;
  addCastingEffect = FB_Casting1_Clip_EW;
  addCastingEffect = FB_Casting2_Clip_EW;
    // fireball //
  addCastingEffect = $FB_FireballRevealLight1;
  addCastingEffect = $FB_FireballRevealLight2;
  addCastingEffect = FB_FireballEmerge_EW;
    // sounds //
  addCastingEffect = FB_ZodeSnd_EW;
  addCastingEffect = FB_ConjureSnd_EW;
  addCastingEffect = FB_FireRingSnd_EW;
  addCastingEffect = FB_FireBallSnd_EW;
  addCastingEffect = FB_FireCrackle1_EW;

  addDeliveryEffect = $FB_MissileLight_Flare1;
  addDeliveryEffect = $FB_MissileLight_Flare2;

    // impact effects //
  addImpactEffect = FireFX_Explosion1_EW;
  addImpactEffect = $FB_ImpactLight_1;
  addImpactEffect = $FB_ImpactLight_2;
  addImpactEffect = FB_Impact1BSnd_EW;
  addImpactEffect = FB_ImpactZodeFast_EW;
  addImpactEffect = FB_dot_damage_EW;
};
//
datablock afxRPGMagicSpellData(FlameBroilSpell_RPG)
{
  name = "Flame Broil";
  desc = "Conjure up a broiling ring of fire and fling a fiery charcoal briquette " @
         "to inflict " @ 35 @ " damage plus an additional " @ 18 @ 
         " over " @ 6 @ " seconds." @
         "\n" @
         "\nspell design: Matthew Durante" @
         "\nsound effects: Dave Schroeder" @ 
         "\nspell concept: Jeff Faust";
  iconBitmap = "arcane.fx/data/spells/icons/fb";

  target = "enemy";
  range = 75;
  manaCost = 10;

  directDamage = 35.0;

  castingDur = FlameBroilSpell.castingDur;
};

// set a level of detail
function FlameBroilSpell::onActivate(%this, %spell, %caster, %target)
{
  Parent::onActivate(%this, %spell, %caster, %target);
  if (MissionInfo.hasBrightLighting)
    %spell.setExecConditions($BrightLighting_mask);
}

//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
