//巸ڮ铨SH.scrollpos=0
//TESH.alwaysfold=0
// ====================================================================================
// Spell: Chain Frost
// Autor: Dark Dragon (Spell from DotA)
//
// Installation:
//
// 1) Make sure you have opened the JNGP editor
// 2) Copy from object editor: Chain Frost ('CFro'), Chain Frost (Upgraded) ('CFru'), Chain Frost Upgrade (Scepter) and "Unit Chill" and match its rawcode in "DD Library"
// 3) Triggers: This trigger "Chain Frost" and "DD Library"
// 4) Paste all of that in your map, save map, give abilities to your units and enjoy!
// 5) Please do note that bellow you can edit spell constants to change spell style to your own needs.
//
// Credits:
// ('Hey its X' and 'Chriz' - FrostEffect.mdx)
// ====================================================================================
//! zinc
library ChainFrost requires DDLib
{
// -------------------------------------------------------------------
// EDITABLE GLOBALS
// -------------------------------------------------------------------
private {
// *** Main spell rawcode ***
// Default: 'CFro'
constant integer CHAIN_FROST = 'CFro';
// *** Main spell updated rawcode, if you dont use upgraded, then just change 'CFru' to 0 ***
// Default: 'CFru'
constant integer CHAIN_FROST_UPGRADED = 'CFru';
// *** Frost nova for chain frost rawcode / NOTE: Now modify in DD Library DD_CHILL rawcode ***
// Default: 'A000'
//constant integer FROST_NOVA = 'CfFn';
// *** Frost nova dummy order / NOTE: no longer in use ***
// Default: "frostnova"
//constant string FROST_NOVA_ORDER = "frostnova";
// *** Missile effect path ***
// Default: "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl"
constant string MISSILE_PATH = "Abilities\\Weapons\\FrostWyrmMissile\\FrostWyrmMissile.mdl";
// *** Nova effect path ***
// Default: "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl"
constant string FROST_PATH = "Abilities\\Spells\\Undead\\FrostNova\\FrostNovaTarget.mdl";
// *** Missile speed ***
// Default: 600.
constant real MISSILE_SPEED = 600.;
// *** Missile size ***
// Default: 1.4
constant real MISSILE_SCALE = 1.4;
// *** Missile height offset, that is the min z of missile ***
// Default: 80.
constant real MISSILE_Z_OFFSET = 80.;
// *** Jumps to nerby units first or any within aoe range
// Default: true
constant boolean CF_AOE_PICK_NERBY_UNIT = true;
// *** Use custom sound ***
// Default: true
constant boolean USE_CSOUND = true;
// *** Custom sound path ***
// Default: "Abilities\\Spells\\Other\\BreathOfFrost\\BreathOfFrost1.wav"
constant string SOUND_PATH = "Abilities\\Spells\\Other\\BreathOfFrost\\BreathOfFrost1.wav";
// *** Use custom graphic ***
// Default: true
constant boolean USE_CGRAPHIC = true;
// *** Custom nova remenant effect path ***
// Default: "SpecialEffects\\FrostEffect.mdx"
constant string NOVA_PATH = "SpecialEffects\\FrostEffect.mdx";
// *** Nova effect lifespan in seconds ***
// Default: 6.
constant real NOVA_LIFESPAN = 6.;
// *** Nova percentage size ***
// Default: 1.25
constant real NOVA_SCALE = 1.25;
// *** Nova decay time in seconds ***
// Default: .4
constant real NOVA_DECAY_TIME = .4;
// *** Custom graphic effect path ***
// Default: "Abilities\\Weapons\\ZigguratFrostMissile\\ZigguratFrostMissile.mdl"
constant string GRAPHIC_EFFECT_PATH = "Abilities\\Weapons\\ZigguratFrostMissile\\ZigguratFrostMissile.mdl";
// *** Particles of graphic count ***
// Default: 8
constant integer PARTICLE_COUNT = 10;
// *** Particles travel distance ***
// Default: 180.
constant real PARTICLE_MIN_RADIUS = 100.;
// Default: 300.
constant real PARTICLE_MAX_RADIUS = 300.;
// *** Particle start height offset, that is the min z of particle ***
// Default: 10.
constant real PARTICLE_MIN_HEIGHT = 10.;
// *** Particles travel height, MIN_HEIGHT + MAX_HEIGHT is overall max height ***
// Default: 180.
constant real PARTICLE_MAX_HEIGHT = 180.;
// *** Particles lifespan in seconds ***
// Default: .8
constant real PARTICLE_LIFESPAN = 1.2;
// *** Particles percentage size ***
// Default: .9
constant real PARTICLE_SCALE = .8;
// *** Custom graphic aftereffect path ***
// Default: "Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorDamage.mdl"
constant string GRAPHIC_AFTEREFFECT_PATH = "Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorDamage.mdl";
// *** every x seconds play animation
// Default: .6
constant real GRAPHIC_AFTEREFFECT_ANIMTIME = .6;
// *** how many seconds does aftereffect last?
// Default: 4.2
constant real GRAPHIC_AFTEREFFECT_DURATION = 4.2;
// *** Make sure missile is created at caster position, if in debug mode it tells you to enable this, you should ***
// Default: false
constant boolean CHECK_MISSILE_POSITION = false;
// *** Level data ***
// * Jump range
function JumpRange(integer level) -> real {
real jrange[];
// ----------------------
// The range the spell uses to pick next target
// Default: 500., 550., 550., 600.
jrange[1] = 500.;
jrange[2] = 550.;
jrange[3] = 550.;
jrange[4] = 600.;
// ----------------------
return jrange[level];
}
// * Max Damage per jump
function NovaDamage(integer level) -> real {
real dmg[];
// ----------------------
// Max damage per jump
// Default: 250, 360, 475, 600
dmg[1] = 250.;
dmg[2] = 360.;
dmg[3] = 475.;
dmg[4] = 600.;
// ----------------------
return dmg[level];
}
// * Nova hero damage percentage alternation, heros will receive percentage of NovaDamage(level)
function NovaHeroDamagePercentage(integer level) -> real {
real hero_dmg_perc[];
hero_dmg_perc[1] = 77.;
hero_dmg_perc[2] = 79.;
hero_dmg_perc[3] = 81.;
hero_dmg_perc[4] = 81.;
return hero_dmg_perc[level];
}
// * Energy contained in nova/max damge spell can deal per cast
function CFMaxDamage(integer level) -> real {
real mdmg[];
// ----------------------
// Max damage per jump
// Default: 1500, 2520, 3325, 4800
mdmg[1] = 6. * 250.;
mdmg[2] = 7. * 360.;
mdmg[3] = 7. * 475.;
mdmg[4] = 8. * 600.;
return mdmg[level];
}
// * Frost / slow duration in seconds
function FrostSlowDuration(integer level) -> real {
real dur[];
// ----------------------
// Duration of freezing effect
// Default: 8, 9, 10, 10
dur[1] = 8.;
dur[2] = 9.;
dur[3] = 10.;
dur[4] = 10.;
return dur[level];
}
// *** this is filter for choosing next unit to jump on
function JumpUnitFilter() -> code {
return function() -> boolean {
cfdata cf = DDMemUnitData(); // data access from filterd spell instance
return (!IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) &&
!IsUnitType(GetFilterUnit(), UNIT_TYPE_MECHANICAL) &&
!IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) &&
!IsUnitType(GetFilterUnit(), UNIT_TYPE_MAGIC_IMMUNE) &&
!IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD) &&
IsUnitVisible(GetFilterUnit(), cf.owner) &&
IsUnitEnemy(GetFilterUnit(), cf.owner) &&
!DDIsUnitWard(GetFilterUnit()) &&
BlzIsUnitSelectable(GetFilterUnit()) &&
!BlzIsUnitInvulnerable(GetFilterUnit()) &&
(cf.target != GetFilterUnit())); // (cf.target is current target, so choose next target should not be same unit)
};
}
}
//===================================================================================
// DO NOT EDIT BELOW IF YOU DONT KNOW JASS
//===================================================================================
// *** custom types ***
//type iceparticles extends effect[PARTICLE_COUNT];
struct iceparticles {
effect e[PARTICLE_COUNT];
real dx[PARTICLE_COUNT], dy[PARTICLE_COUNT];
method operator [](integer index) -> effect {
return this.e[index];
}
method operator []=(integer index, effect e) {
this.e[index] = e;
}
}
// ----------------------------------------------
// *** Chain frost data struct ***
struct cfdata {
unit caster, target, ltarget /*,dummy*/;
integer lvl;
real aoe, mx_dmg;
player owner;
ddeffect missile;
//static sound CastSnd = null;
//static constant real CONST_SPEED = DD_INTERVAL*PARTICLE_RADIUS/PARTICLE_LIFESPAN;
//static cfdata Temp = p_null;
//static unit ChainNexus[];
//static integer CNN = 0;
static method create(unit c, unit t, integer lvl) -> cfdata {
cfdata this = allocate();
caster = c;
target = t;
//dummy = null;
owner = GetOwningPlayer(caster);
this.lvl = lvl;
missile = p_null;
mx_dmg = CFMaxDamage(lvl);
aoe = JumpRange(lvl);
//ltarget = null;
return this;
}
// --------------------------------------------------------------------------------------------------------------
// *** Parabolic particle motion
static method ParticleZ(integer mxtick, integer tick) -> real {
return ( (-PARTICLE_MAX_HEIGHT/Pw_2(.5*mxtick)) * Pw_2(tick-(mxtick*.5)) + PARTICLE_MAX_HEIGHT );
}
// --------------------------------------------------------------------------------------------------------------
// *** load custom particles at given target position
static method CreateParticleDispersion(unit target) {
iceparticles ip = iceparticles.create();
integer i;
real x = GetUnitX(target), y = GetUnitY(target);
real spd, rad;
// *** create missiles
for(i=0; i < PARTICLE_COUNT; i+=1) {
ip[i] = AddSpecialEffect(GRAPHIC_EFFECT_PATH, x, y);
BlzSetSpecialEffectRoll(ip[i], i*2.*bj_PI/PARTICLE_COUNT);
BlzSetSpecialEffectScale(ip[i], PARTICLE_SCALE);
BlzSetSpecialEffectZ(ip[i], DDGetUnitZ(target) + PARTICLE_MIN_HEIGHT);
spd = DD_INTERVAL*DDGetRndReal(PARTICLE_MIN_RADIUS, PARTICLE_MAX_RADIUS)/PARTICLE_LIFESPAN;
rad = i*2.*bj_PI/PARTICLE_COUNT;
ip.dx[i] = spd * Cos(rad);
ip.dy[i] = spd * Sin(rad);
//ip[i] = xeffect.create(GRAPHIC_EFFECT_PATH, x, y, i*360./PARTICLE_COUNT, PARTICLE_SCALE);
//ip[i].Z = GetUnitFlyHeight(target) + PARTICLE_MIN_HEIGHT;
}
// *** start loop
DDStartTim(DD_INTERVAL, true, ip, function() {
integer i, tick = DDTimTick(), mxtick = R2I(PARTICLE_LIFESPAN/DD_INTERVAL);
iceparticles ip = DDTimData();
boolean in_air = true;
real x, y;
// *** movement ***
for(i=0; i < PARTICLE_COUNT; i+=1) {
if (in_air) {
//rad = i*2.*bj_PI/PARTICLE_COUNT;
BlzSetSpecialEffectPosition(ip[i], BlzGetLocalSpecialEffectX(ip[i]) + ip.dx[i],
BlzGetLocalSpecialEffectY(ip[i]) + ip.dy[i],
BlzGetLocalSpecialEffectZ(ip[i]) + /*wz-DDEffectTerrZ(ip[i]) +*/ ParticleZ(mxtick, tick) - ParticleZ(mxtick, tick-1));
/*ip[i].X += (PARTICLE_RADIUS/PARTICLE_LIFESPAN)*DD_INTERVAL * Cos(i*2.*bj_PI/PARTICLE_COUNT);
ip[i].Y += (PARTICLE_RADIUS/PARTICLE_LIFESPAN)*DD_INTERVAL * Sin(i*2.*bj_PI/PARTICLE_COUNT);
ip[i].Z += wz-ip[i].WZ + ParticleZ(mxtick, tick) - ParticleZ(mxtick, tick-1);*/
if (BlzGetLocalSpecialEffectZ(ip[i])-DDEffectTerrZ(ip[i]) < 10.) {
in_air = false;
i = -01;
}
} else {
x = BlzGetLocalSpecialEffectX(ip[i]);
y = BlzGetLocalSpecialEffectY(ip[i]);
DestroyEffect(ip[i]);
ip[i] = AddSpecialEffect(GRAPHIC_AFTEREFFECT_PATH, x, y);
BlzSetSpecialEffectScale(ip[i], PARTICLE_SCALE);
}
}
// *** done? ***
if (!in_air) {
DDStartTim(GRAPHIC_AFTEREFFECT_ANIMTIME, true, ip, function() {
iceparticles ip = DDTimData();
integer i;
if (DDTimTick() == GRAPHIC_AFTEREFFECT_DURATION/GRAPHIC_AFTEREFFECT_ANIMTIME) {
for(i=00; i < PARTICLE_COUNT; i+=01) {
DestroyEffect(ip[i]);
ip[i] = null;
}
ip.destroy();
DDQuitTim();
return;
}
for(i=00; i < PARTICLE_COUNT; i+=01)
BlzPlaySpecialEffect(ip[i], ANIM_TYPE_BIRTH);
});
DDQuitTim();
}
});
}
// --------------------------------------------------------------------------------------------------------------
// *** creates nova effect ***
static method CreateNovaEffect(unit target) {
if (!IsUnitType(target, UNIT_TYPE_FLYING))
ddeffect.create(NOVA_PATH, GetUnitX(target), GetUnitY(target), GetRandomReal(0., 2.*bj_PI), NOVA_SCALE).destroyx(NOVA_LIFESPAN);
}
method NewMissile(unit c) {
missile = ddeffect.createZ(MISSILE_PATH,
GetUnitX(c), GetUnitY(c), DDGetUnitZ(c) + MISSILE_Z_OFFSET,
Atan2(-GetUnitY(c)+GetUnitY(target), -GetUnitX(c)+GetUnitX(target)),
MISSILE_SCALE);
}
method MissileHit() {
real dmg = RMinBJ(NovaDamage(lvl), mx_dmg);
/*
dummy = DDLoadDummy();
SetUnitOwner(dummy, owner, false);
SetUnitX(dummy, GetUnitX(target) - 5. * Cos( DmyRad() ));
SetUnitY(dummy, GetUnitY(target) - 5. * Sin( DmyRad() ));
UnitAddAbility(dummy, FROST_NOVA);
*/
missile.destroy();
missile = p_null;
DDUnitShareVisionTimed(target, owner, 1.); // make sure dummy can cast spell
//if (IssueTargetOrder(dummy, FROST_NOVA_ORDER, target)) {
if ( DDUnitChill(owner, target, FrostSlowDuration(lvl)) ) {
static if (USE_CGRAPHIC) {
CreateNovaEffect(target);
CreateParticleDispersion(target);
}
// *** Main effect
DestroyEffect( AddSpecialEffectTarget(FROST_PATH, target, "origin") );
// *** Main damage
if (!IsUnitType(target, UNIT_TYPE_HERO)) {
if (GetWidgetLife(target) > dmg)
SetWidgetLife(target, GetWidgetLife(target)-dmg);
else {
dmg = GetWidgetLife(target);
UnitDamageTarget(caster, target, 32767., true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS);
}
} else {
if (GetWidgetLife(target) > dmg*NovaHeroDamagePercentage(lvl)/100.)
SetWidgetLife(target, GetWidgetLife(target)-dmg*NovaHeroDamagePercentage(lvl)/100.);
else {
dmg = GetWidgetLife(target)*100./NovaHeroDamagePercentage(lvl);
UnitDamageTarget(caster, target, 32767., true, false, ATTACK_TYPE_CHAOS, DAMAGE_TYPE_COLD, WEAPON_TYPE_WHOKNOWS);
}
}
mx_dmg -= dmg;
}
// -------------------------------------------------------------------------------------------------
// *** fill nexus with new targets ***
ltarget = target;
static if (CF_AOE_PICK_NERBY_UNIT) {
// *** get new target in nerby range
DDGroupFillMemArea(GetUnitX(target), GetUnitY(target), aoe*.4, this, JumpUnitFilter());
if (DDMemUnitN() > 00)
target = DDMemUnit(DDGetRndInt(0, DDMemUnitN()-1));
else {
// *** get new target in far range
DDGroupFillMemArea(GetUnitX(target), GetUnitY(target), aoe, this, JumpUnitFilter());
target = DDMemUnit(DDGetRndInt(0, DDMemUnitN()-1));
}
} else {
// *** get new target in far range
DDGroupFillMemArea(GetUnitX(target), GetUnitY(target), aoe*.4, this, JumpUnitFilter());
target = DDMemUnit(DDGetRndInt(0, DDMemUnitN()-1));
}
/*
DDStartTim(1., false, New_pUnit(dummy), function() {
p_unit pu = DDTimData();
UnitRemoveAbility(pu[00], FROST_NOVA);
DDRecycleDummy(pu[00]);
pu.destroy();
DDQuitTim();
});*/
}
method MissileMove() -> boolean {
real rad = Atan2(GetUnitY(target)-missile.Y, GetUnitX(target)-missile.X);
real dist = SquareRoot( DDHypot(GetUnitX(target)-missile.X, GetUnitY(target)-missile.Y) );
real dz = DDGetUnitZ(target) - missile.Z + MISSILE_Z_OFFSET;
missile.PositionZ(missile.X + MISSILE_SPEED*DD_INTERVAL*Cos(rad),
missile.Y + MISSILE_SPEED*DD_INTERVAL*Sin(rad),
missile.Z + ((dz/dist) * MISSILE_SPEED*DD_INTERVAL));
/*missile.X += MISSILE_SPEED*DD_INTERVAL*Cos(rad);
missile.Y += MISSILE_SPEED*DD_INTERVAL*Sin(rad);
missile.Z += (dz/dist) * (MISSILE_SPEED*DD_INTERVAL);*/
missile.Facing = rad;
//BJDebugMsg(R2S(rad*bj_RADTODEG));
return dist <= 3.*MISSILE_SPEED*DD_INTERVAL;
}
}
// =================================================================
// =================================================================
function onInit() {
trigger t = CreateTrigger();
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_CAST);
TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT);
TriggerAddCondition(t, Condition(function() -> boolean {
unit u = GetTriggerUnit(), v = GetSpellTargetUnit();
integer abillvl;
cfdata cf;
// ----------------------------------------------------------------
// *** condition ****
if (GetSpellAbilityId() != CHAIN_FROST && GetSpellAbilityId() != CHAIN_FROST_UPGRADED)
return false;
// ----------------------------------------------------------------
if (GetTriggerEventId() == EVENT_PLAYER_UNIT_SPELL_CAST) {
if (IsUnitType(v, UNIT_TYPE_MAGIC_IMMUNE)) {
IssuePointOrder(u, "move",
GetUnitX(u)+20.*Cos(GetUnitFacing(u)*bj_DEGTORAD),
GetUnitY(u)+20.*Sin(GetUnitFacing(u)*bj_DEGTORAD));
DisplayErrorMsgPlayer(GetOwningPlayer(u), bj_QUEUE_DELAY_HINT, "Can't cast on magic immune units!");
}
u = null; v = null;
return false;
}
// ----------------------------------------------------------------
abillvl = GetUnitAbilityLevel(u, GetSpellAbilityId());
if (GetSpellAbilityId() == CHAIN_FROST_UPGRADED) abillvl += 1;
// *** store data ***
cf = cfdata.create(u, v, abillvl);
cf.NewMissile(cf.caster);
debug if (!IsUnitInRangeXY(cf.caster, cf.missile.X, cf.missile.Y, 100.) && !CHECK_MISSILE_POSITION)
BJDebugMsg("|cffff0000Error:|rChain Frost missile not created at caster position, please enable \"CHECK_MISSILE_POSITION\".");
//UnitShareVision(cf.target, cf.owner, true);
if (USE_CSOUND)
DDGenericSound(SOUND_PATH, 100., GetUnitX(cf.caster), GetUnitY(cf.caster), 3500., 1.);
// *** init timer and start periodic spell actions ***
DDStartTim(DD_INTERVAL, true, cf, function() {
cfdata cf = DDTimData();
static if (CHECK_MISSILE_POSITION) {
if (DDTimTick() == 01)
cf.missile.PositionZ(GetUnitX(cf.caster), GetUnitY(cf.caster), MISSILE_Z_OFFSET);
}
// *** move missile and check if reached target ***
if (cf.MissileMove()) {
// *** hit the target ***
cf.MissileHit();
// *** end spell ***
if (cf.target == null || cf.mx_dmg < 0.1) {
//UnitShareVision(cf.ltarget, cf.owner, false);
cf.destroy();
DDQuitTim();
return;
}
// *** new missile ***
if (cf.missile == p_null && cf.mx_dmg > 0.) {
cf.NewMissile(cf.ltarget);
//UnitShareVision(cf.ltarget, cf.owner, false);
//UnitShareVision(cf.target, cf.owner, true);
}
}
});
u = null; v = null;
return false;
}));
}
}
//! endzinc
// ============================================================================================
// NOTE: This lua script is for old version of spell, I recommend to just copy and paste abilities and dummy to your map
// Change me from /* to // and then back to /* after saving and reopening the map
// |
// ˇ
/*
// Credits: PurgeandFire for lua tutorial
//! externalblock extension=lua ObjectMerger $FILENAME$
//! i -- ===================================================
//! i CHAIN_FROST_DAMAGE_ID = "CfFn"
//! i FREEZING_FIELD_ABIL_ID = "FFld"
//! i FREEZING_FIELD_IMPROVED_ABIL_ID = "FFdu" -- Set this value to "nil" if not using upgrader
//! i CHAIN_FROST_ABIL_ID = "CFro"
//! i CHAIN_FROST_IMPROVED_ABIL_ID = "CFru" -- Set this value to "nil" if not using upgrader or if not using chain frost spell
//! i AGHANIM_SCEPTER_ABIL_ID = "Aghs"
//! i -- ===================================================
//! i setobjecttype("abilities")
//! i createobject("AUfn", CHAIN_FROST_DAMAGE_ID)
//! i makechange(current,"anam", "Chain Frost Chill")
//! i makechange(current,"alev", "1")
//! i makechange(current,"aher", false)
// i local i = 0
// i local dmg = { "250.", "360.", "475.", "600." }
// i for i=1, 4 do
// i local si = tostring(i)
//! i makechange(current,"Ufn1",si,"0.")
//! i makechange(current,"Ufn2",si,0.)
//! i makechange(current,"aare",si,"0.")
//! i makechange(current,"ahdu",si,"10.")
//! i makechange(current,"adur",si,"10.")
//! i makechange(current,"amcs",si,"0")
//! i makechange(current,"aran",si,"99999.")
// i end
//! i createobject("AUsl", CHAIN_FROST_ABIL_ID)
//! i makechange(current,"anam", "Chain Frost")
//! i makechange(current,"alev", "3")
//! i makechange(current,"abpx", "3")
//! i makechange(current,"arpx", "3")
//! i makechange(current,"arhk", "C")
//! i makechange(current,"ahky", "C")
//! i makechange(current,"aart", "ReplaceableTextures\\CommandButtons\\BTNBreathofFrost.blp")
//! i makechange(current,"arar", "ReplaceableTextures\\CommandButtons\\BTNBreathofFrost.blp")
//! i makechange(current,"aret", "Learn |cffffcc00C|rhain Frost - [|cffffcc00Level ".. string.char(37) .."d|r]")
//! i makechange(current,"arut", "Sends a breath of frost that jumps n times through nearby enemys dealing damage and slowing them for 10 seconds. |n|n|cFF0054A6Level 1|r - Each jump deals 250 damage, 6 jumps.|n|cFF0054A6Level 2|r - Each jump deals 360 damage, 7 jumps.|n|cFF0054A6Level 3|r - Each jump deals 475 damage, 7 jumps.")
//! i local i = 0
//! i local manacost = { "200", "325", "500" }
//! i for i=1, 3 do
//! i local si = tostring(i)
//! i makechange(current,"Usl1",si,".01")
//! i makechange(current,"aran",si,"750.")
//! i makechange(current,"abuf",si,nil)
//! i makechange(current,"acdn",si,tostring(22.5-2.5*i))
//! i makechange(current,"ahdu",si,".01")
//! i makechange(current,"adur",si,".01")
//! i makechange(current,"amcs",si, manacost[i])
//! i makechange(current,"atp1",si,"|cffffcc00C|rhain Frost - [|cffffcc00Level "..si.."|r]")
//! i end
//! i makechange(current,"aub1","1", "Sends a breath of frost that jumps 6 times through nearby enemys dealing 250 damage and slowing for 10 seconds.")
//! i makechange(current,"aub1","2", "Sends a breath of frost that jumps 7 times through nearby enemys dealing 360 damage and slowing for 10 seconds.")
//! i makechange(current,"aub1","3", "Sends a breath of frost that jumps 7 times through nearby enemys dealing 475 damage and slowing for 10 seconds.")
//! i if (CHAIN_FROST_IMPROVED_ABIL_ID ~= nil) then
//! i createobject("AUsl", CHAIN_FROST_IMPROVED_ABIL_ID)
//! i makechange(current,"anam", "Chain Frost")
//! i makechange(current,"ansf", " ( Upgraded )")
//! i makechange(current,"alev", "3")
//! i makechange(current,"abpx", "3")
//! i makechange(current,"arpx", "3")
//! i makechange(current,"arhk", "C")
//! i makechange(current,"ahky", "C")
//! i makechange(current,"aart", "ReplaceableTextures\\CommandButtons\\BTNBreathofFrost.blp")
//! i makechange(current,"arar", "ReplaceableTextures\\CommandButtons\\BTNBreathofFrost.blp")
//! i makechange(current,"aret", "Learn |cffffcc00C|rhain Frost - [|cffffcc00Level ".. string.char(37) .."d|r]")
//! i makechange(current,"arut", "Sends a breath of frost that jumps n times through nearby enemys dealing damage and slowing them for 10 seconds. |n|n|cFF0054A6Level 1|r - Each jump deals 360 damage, 7 jumps.|n|cFF0054A6Level 2|r - Each jump deals 475 damage, 7 jumps.|n|cFF0054A6Level 3|r - Each jump deals 600 damage, 8 jumps.")
//! i local i = 0
//! i local manacost = { "200", "325", "500" }
//! i for i=1, 3 do
//! i local si = tostring(i)
//! i makechange(current,"Usl1",si,".01")
//! i makechange(current,"aran",si,"750.")
//! i makechange(current,"abuf",si,nil)
//! i makechange(current,"acdn",si,tostring(22.5-2.5*i))
//! i makechange(current,"ahdu",si,".01")
//! i makechange(current,"adur",si,".01")
//! i makechange(current,"amcs",si, manacost[i])
//! i makechange(current,"atp1",si,"|cffffcc00C|rhain Frost - [|cffffcc00Level "..si.."|r]")
//! i end
//! i makechange(current,"aub1","1", "Sends a breath of frost that jumps 7 times through nearby enemys dealing 360 damage and slowing for 10 seconds.")
//! i makechange(current,"aub1","2", "Sends a breath of frost that jumps 7 times through nearby enemys dealing 475 damage and slowing for 10 seconds.")
//! i makechange(current,"aub1","3", "Sends a breath of frost that jumps 8 times through nearby enemys dealing 600 damage and slowing for 10 seconds.")
//! i end
//! i if (FREEZING_FIELD_IMPROVED_ABIL_ID ~= nil or CHAIN_FROST_IMPROVED_ABIL_ID ~= nil) then
//! i createobject("ANeg", AGHANIM_SCEPTER_ABIL_ID)
//! i makechange(current,"aart", "ReplaceableTextures\\CommandButtons\\BTNINV_Wand_05.blp")
//! i makechange(current,"Neg4","1", CHAIN_FROST_ABIL_ID..","..CHAIN_FROST_IMPROVED_ABIL_ID)
//! i if (FREEZING_FIELD_IMPROVED_ABIL_ID ~= nil) then
//! i makechange(current,"Neg3","1", FREEZING_FIELD_ABIL_ID..","..FREEZING_FIELD_IMPROVED_ABIL_ID)
//! i else
//! i makechange(current,"Neg3","1", nil)
//! i end
//! i makechange(current,"Neg5","1", nil)
//! i makechange(current,"Neg6","1", nil)
//! i makechange(current,"Neg1","1", "0.")
//! i makechange(current,"Neg2","1", "0.")
//! i makechange(current,"aher", false)
//! i makechange(current,"abuf","1", nil)
//! i makechange(current,"alev", "1")
//! i makechange(current,"arac", "nightelf")
//! i makechange(current,"anam", "CF & FF Upgrader")
//! i end
//! endexternalblock
*/
// ^
// |
// Change me from */ to // and then back to */ after saving and reopening the map
// ============================================================================================