Romek
Super Moderator
- Reaction score
- 963
Panda Roll!
By Romek
By Romek
Code: vJASS
MUI / MPI: MUI
Leaks: None
Import Difficulty: Easy / Average
Targets: Instant Cast - Self Buff
Description: The Panda ignites and rolls around the field, leaving a trial of fire which damages enemy units. Destroys trees. Lasts 10 / 15 / 20 seconds
Inspired by a vid I saw on youtube
I Bring Pandemonium!
Screenshot:
To Use:
- Copy Vexorians Dummy.mdx into your map if you don't already have it
- Copy the dummy unit into your map
- Copy ABC into your map if you don't already have it
- Create a new trigger
- Convert it to Custom Text
- Copy this code into that trigger
The Code:
JASS:
scope Roller initializer Init
globals
// =================================
// === C O N F I G U R A T I O N ===
// =================================
// == G L O B A L S == \\
// -- General Config -- \\
// The Raw code of the spell
private constant integer ID = 039;A000039;
// The raw code of the dummy unit.
private constant integer DUMMY = 039;dmmy039;
// The raw code of Crow Form.
private constant integer CROW = 039;Amrf039; // Will probably be the same for every map unless you've
// modified the "Crow Form" ability.
// Should it knock down trees?
private constant boolean TREES = true
// The raw code of a unit used to check for trees
private constant integer TREEDUMMY = 039;nmpe039; // Ignore if TREES is false
// Raw code of Harvest
private constant integer HARVEST = 039;Ahrl039; // Ignore if TREES is false
// The height of the effects
private constant real HEIGHT = 60.
// The effect the unit becomes
private constant string UNITEFFECT = "Units\\Creeps\\FirePandarenBrewmaster\\FirePandarenBrewmaster_Missile.mdl"
// An alternate effect attached to the unit
private constant string ANOTHEREFFECT = "Abilities\\Spells\\Other\\ImmolationRed\\ImmolationRedTarget.mdl"
// The alpha value of the caster during the spell
private constant integer ALPHA = 1 // A number between 0 and 255
// How often the timer expires
private constant real TIMEOUT = 0.03125
// How quickly the unit rolls (Per second)
private constant real SPEED = 500.
// -- Trail Config -- \\
// The trail created by the caster
private constant string BURNEFFECT = "Environment\\SmallBuildingFire\\SmallBuildingFire2.mdl"
// How long the trail lasts
private constant real BURNEFFECT_DURATION = 2.5
// How close you need to be to the trail to take damage
private constant real BURN_RADIUS = 50.
// Should it damage allies
private constant boolean BURN_ALLY = true
// Should it damage the caster
private constant boolean BURN_CASTER = false
// Damage Type of trail
private constant damagetype BURNDAMAGE = DAMAGE_TYPE_UNKNOWN
// Weapon type of trail
private constant weapontype BURNWEAPON = WEAPON_TYPE_WHOKNOWS
// Attack type of trail
private constant attacktype BURNATTACK = ATTACK_TYPE_CHAOS
// -- Hit Config -- \\
// How close you need to be to the caster to take damage
private constant real TOUCH_RADIUS = 100.
// Should it damage allies
private constant boolean TOUCH_ALLY = true
// Damage Type of damage
private constant damagetype TOUCHDAMAGE = DAMAGE_TYPE_UNKNOWN
// Weapon type of damage
private constant weapontype TOUCHWEAPON = WEAPON_TYPE_WHOKNOWS
// Attack type of damage
private constant attacktype TOUCHATTACK = ATTACK_TYPE_CHAOS
endglobals
// =================================
// === C O N F I G U R A T I O N ===
// =================================
// == F U N C T I O N S == \\
// -- General Config -- \\
// How long the spell lasts. 'level' is the ability level.
private constant function DURATION takes integer level returns real
return 5 + level * 5.
// 10, 15, 20 seconds
endfunction
// -- Trial Config -- \\
// Which units should be affected
private constant function BurnDamageFilter takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) == false
endfunction
// How much damage is taken, per second.
private constant function BURNDAMAGE_AMOUNT takes integer level returns real
return level * 100.
// 100, 200, 300
endfunction
// -- Hit Config -- \\
// Which units should be affected
private constant function TouchDamageFilter takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_FLYING) == false and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) == false
endfunction
// How much damage is taken, per second.
private constant function TOUCHDAMAGE_AMOUNT takes integer level returns real
return level * 200.
// 200, 400, 600
endfunction
// ============================================================== \\
// = D O N O T E D I T B E L O W T H I S L I N E = \\
// ============================================================== \\
globals
private boolexpr FiltTrue
private boolexpr DamageFilt
private boolexpr TouchFilt
private boolexpr FiltTree
private real MinX = GetRectMinX(bj_mapInitialPlayableArea)
private real MinY = GetRectMinY(bj_mapInitialPlayableArea)
private real MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
private real MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
private unit TREE
private trigger Trig
private group Casters
endglobals
private struct Data
unit caster
unit dummy
effect main
effect another
real x
real y
real facing
real ticks
static group G = CreateGroup()
private static method Turn takes nothing returns nothing
local unit u = GetTriggerUnit()
call SetUnitFacing(u, (bj_RADTODEG * Atan2(GetOrderPointY() - GetUnitY(u), GetOrderPointX() - GetUnitX(u))))
call TriggerSleepAction(0)
call IssueImmediateOrder(u, "stop")
set u = null
endmethod
private static method Cond takes nothing returns boolean
return GetIssuedOrderId() == OrderId("move") or GetIssuedOrderId() == OrderId("smart") or GetIssuedOrderId() == OrderId("patrol") or GetIssuedOrderId() == OrderId("attack") and IsUnitInGroup(GetTriggerUnit(), Casters)
endmethod
private method onDestroy takes nothing returns nothing
call DestroyEffect(.main)
call DestroyEffect(.another)
call ShowUnit(.dummy, false)
call KillUnit(.dummy)
call SetUnitVertexColor(.caster, 255, 255, 255, 255)
call SetUnitPathing(.caster, true)
call GroupRemoveUnit(Casters, .caster)
endmethod
public static method create takes unit u returns Data
local Data this = Data.allocate()
set .caster = u
set .x = GetUnitX(.caster)
set .y = GetUnitY(.caster)
set .facing = GetUnitFacing(.caster)
set .ticks = 0.
call GroupAddUnit(Casters, .caster)
call SetUnitPathing(.caster, false)
return this
endmethod
private static method onInit takes nothing returns nothing
set Trig = CreateTrigger()
call TriggerAddCondition(Trig, Filter( function Data.Cond))
call TriggerAddAction(Trig, function Data.Turn)
endmethod
endstruct
private function True takes nothing returns boolean
return true
endfunction
private struct TimedEffect
effect eff
timer stop
unit caster
real ticks
real x
real y
static group G = CreateGroup()
private method onDestroy takes nothing returns nothing
// ABC Function:
call ClearTimerStructA(.stop)
// ------------
call DestroyEffect(.eff)
call PauseTimer(.stop)
call DestroyTimer(.stop)
endmethod
endstruct
private function TimedEffectB takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u = null
// ABC Function:
local TimedEffect a = GetTimerStructA(t)
// ------------
if a.ticks >= BURNEFFECT_DURATION then
set t = null
call a.destroy()
return
endif
call GroupEnumUnitsInRange(a.G, a.x, a.y, BURN_RADIUS, DamageFilt)
loop
set u = FirstOfGroup(a.G)
exitwhen u == null
if IsUnitEnemy(u, GetOwningPlayer(a.caster)) then
call UnitDamageTarget(a.caster, u, BURNDAMAGE_AMOUNT(GetUnitAbilityLevel(a.caster, ID)) * 0.1, false, false, BURNATTACK, BURNDAMAGE, BURNWEAPON)
elseif BURN_ALLY and u != a.caster then
call UnitDamageTarget(a.caster, u, BURNDAMAGE_AMOUNT(GetUnitAbilityLevel(a.caster, ID)) * 0.1, false, false, BURNATTACK, BURNDAMAGE, BURNWEAPON)
elseif BURN_CASTER and u == a.caster then
call UnitDamageTarget(a.caster, u, BURNDAMAGE_AMOUNT(GetUnitAbilityLevel(a.caster, ID)) * 0.1, false, false, BURNATTACK, BURNDAMAGE, BURNWEAPON)
endif
call GroupRemoveUnit(a.G, u)
endloop
set t = null
set a.ticks = a.ticks + 0.1
endfunction
private function TimedEffectA takes real x, real y, unit u returns nothing
local TimedEffect a = TimedEffect.create()
set a.stop = CreateTimer()
set a.eff = AddSpecialEffect(BURNEFFECT, x, y)
set a.caster = u
set a.ticks = 0.
set a.x = x
set a.y = y
// ABC Function:
call SetTimerStructA(a.stop, a)
// ------------
call TimerStart(a.stop, 0.1, true, function TimedEffectB)
endfunction
// Credits to PitzerMike. Modified slightly.
private function TreeFilter takes nothing returns boolean
local destructable d = GetFilterDestructable()
local boolean b
call ShowUnit(TREE, true)
call SetUnitX(TREE, GetWidgetX(d))
call SetUnitY(TREE, GetWidgetY(d))
set b = IssueTargetOrder(TREE, "harvest", d)
call IssueImmediateOrder(TREE, "stop")
call ShowUnit(TREE, false)
if b then
call KillDestructable(d)
endif
set d = null
return false
endfunction
private function SafeX takes real x returns real
if x > MaxX then
return MaxX
elseif x < MinX then
return MinX
endif
return x
endfunction
private function SafeY takes real y returns real
if y > MaxY then
return MaxY
elseif y < MinY then
return MinY
endif
return y
endfunction
private function Expire takes nothing returns nothing
local timer t = GetExpiredTimer()
local unit u
local rect r = null
// ABC Function:
local Data d = GetTimerStructA(t)
// ------------
call TimedEffectA(d.x, d.y, d.caster)
set d.facing = GetUnitFacing(d.caster)
set d.x = SafeX(d.x + SPEED * TIMEOUT * Cos(d.facing * bj_DEGTORAD))
set d.y = SafeY(d.y + SPEED * TIMEOUT * Sin(d.facing * bj_DEGTORAD))
call SetUnitX(d.dummy, d.x)
call SetUnitY(d.dummy, d.y)
call SetUnitX(d.caster, d.x)
call SetUnitY(d.caster, d.y)
call GroupEnumUnitsInRange(d.G, d.x, d.y, TOUCH_RADIUS, TouchFilt)
loop
set u = FirstOfGroup(d.G)
exitwhen u == null
if IsUnitEnemy(u, GetOwningPlayer(d.caster)) then
call UnitDamageTarget(d.caster, u, TOUCHDAMAGE_AMOUNT(GetUnitAbilityLevel(d.caster, ID)) * TIMEOUT, false, false, TOUCHATTACK, TOUCHDAMAGE, TOUCHWEAPON)
elseif TOUCH_ALLY and u != d.caster then
call UnitDamageTarget(d.caster, u, TOUCHDAMAGE_AMOUNT(GetUnitAbilityLevel(d.caster, ID)) * TIMEOUT, false, false, TOUCHATTACK, TOUCHDAMAGE, TOUCHWEAPON)
endif
call GroupRemoveUnit(d.G, u)
endloop
if TREES then
set r = Rect(d.x - TOUCH_RADIUS, d.y - TOUCH_RADIUS, d.x + TOUCH_RADIUS, d.y + TOUCH_RADIUS)
call EnumDestructablesInRect(r, FiltTree, function DoNothing)
call RemoveRect(r)
set r = null
endif
call SetUnitFacing(d.dummy, d.facing)
set d.ticks = d.ticks + TIMEOUT
if d.ticks > DURATION(GetUnitAbilityLevel(d.caster, ID)) or GetWidgetLife(d.caster) <= 0.405 then
// ABC Function:
call ClearTimerStructA(t)
// ------------
call PauseTimer(t)
call DestroyTimer(t)
call d.destroy()
endif
set t = null
endfunction
private function Action takes nothing returns nothing
local Data d = Data.create(GetTriggerUnit())
local timer t = CreateTimer()
set d.dummy = CreateUnit(GetOwningPlayer(d.caster), DUMMY, d.x, d.y, d.facing)
call UnitAddAbility(d.dummy, CROW)
call UnitRemoveAbility(d.dummy, CROW)
call SetUnitFlyHeight(d.dummy, HEIGHT, 0.)
call SetUnitVertexColor(d.caster, 255, 255, 255, ALPHA)
set d.main = AddSpecialEffectTarget(UNITEFFECT, d.dummy, "origin")
set d.another = AddSpecialEffectTarget(ANOTHEREFFECT, d.dummy, "origin")
// ABC Function:
call SetTimerStructA(t, d)
// ------------
call TimerStart(t, TIMEOUT, true, function Expire)
set t = null
endfunction
private function Cond takes nothing returns boolean
return GetSpellAbilityId() == ID
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
set MinX = GetRectMinX(bj_mapInitialPlayableArea)
set MinY = GetRectMinY(bj_mapInitialPlayableArea)
set MaxX = GetRectMaxX(bj_mapInitialPlayableArea)
set MaxY = GetRectMaxY(bj_mapInitialPlayableArea)
set FiltTrue = Filter(function True)
set DamageFilt = Filter(function BurnDamageFilter)
set TouchFilt = Filter(function TouchDamageFilter)
set FiltTree = Filter(function TreeFilter)
loop
exitwhen i > 15
call TriggerRegisterPlayerUnitEvent(t, Player(i), EVENT_PLAYER_UNIT_SPELL_EFFECT, FiltTrue)
call TriggerRegisterPlayerUnitEvent(Trig, Player(i), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, FiltTrue)
set i = i + 1
endloop
call TriggerAddAction(t, function Action)
call TriggerAddCondition(t, Filter(function Cond))
set TREE = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), TREEDUMMY, 0, 0, 0)
call SetUnitPathing(TREE, false)
call UnitAddAbility(TREE, 039;Aloc039;)
call UnitAddAbility(TREE, HARVEST)
call ShowUnit(TREE, false)
call Preload(BURNEFFECT)
call Preload(UNITEFFECT)
call Preload(UNITEFFECT)
call PreloadEnd(0.5)
set Casters = CreateGroup()
endfunction
endscope
Requires ABC
The Map: