Name | Type | is_array | initial_value |
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//Credits:
// - Blaxor for the inspiration
// - cohadar for his PUI library
// - Rising_Dusk for his GroupUtils library
// - Vexorian for JassHelper and TimerUtils
// - PipeDream for Grimoire and all his help with spirals
// - PitzerMike for JassNewGenPack
// - SFilip for TESH
// How to import:
// - Copy the code into a trigger on your map, adjust the constants below (especially AID) and youre done.
// - Note that you have to copy over the required libraries as well
library FireSpiral uses TimerUtils, GroupUtils, PUI, xefx
globals
private constant integer AID = 'A000' // rawcode of the triggering abiltiy (press Ctrl+D to display the rawcode of objects, in the object editor)
private constant real FX_INTERVAL = 0.15 // effects are spawned in this interval
private constant string FIRE_FX = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl" // this is the effect the spiral consits of
private constant real FIRE_FX_RADIUS = 24. // collision size of the beforementioned effect
private constant real FIRE_FX_SCALE = 1. // scale of beforementioned effect
private real array FIRE_DMG // Units receive this much damage per second
private constant real FIRE_DMG_RADIUS = 96 // this is the radius in which units around the effects get receive damage
private constant real FIRE_DMG_TICK = 1./8 // this is the granulation of damage
private constant string FIRE_DMG_FX = "Environment\\LargeBuildingFire\\LargeBuildingFire2.mdl" // this is the effect spawned on units receiving damage by the spiral
private constant string FIRE_DMG_FX_ATTPT = "head" // this is the attachmentpoint where the beforementioned effect gets attached to
private constant real FIRE_DMG_FX_STAY = 2. // the beforementioned effect stays on units this long after they receive no more damage
private constant attacktype FIRE_DMG_ATTACKTYPE = ATTACK_TYPE_MAGIC // attacktype of the damage units receive
private constant damagetype FIRE_DMG_DAMAGETYPE = DAMAGE_TYPE_MAGIC // damagetype of the damage units receive
private real array SPIRAL_INITIAL_RADIUS // initial radius of the spiral
private real array SPIRAL_END_RADIUS // radius of the spiral
private real array SPIRAL_CIRCLES // how often does a spiral reach ((angle) modulo (2*PI))==0
private integer array SPIRAL_ENDINGS // number of spirals spawned
private real array DURATION // Duration of the spiral after all effects have been spawned
private constant integer MAX_FIRE_FX_PER_INSTANCE = 255
endglobals
private function SetUpFIRE_DMG takes nothing returns nothing
set FIRE_DMG[1]=50.
set FIRE_DMG[2]=75.
set FIRE_DMG[3]=100.
endfunction
private function SetUpSPIRAL_INITIAL_RADIUS takes nothing returns nothing
set SPIRAL_INITIAL_RADIUS[1]=200
set SPIRAL_INITIAL_RADIUS[2]=200
set SPIRAL_INITIAL_RADIUS[3]=200
endfunction
private function SetUpSPIRAL_END_RADIUS takes nothing returns nothing
set SPIRAL_END_RADIUS[1]=400.
set SPIRAL_END_RADIUS[2]=500.
set SPIRAL_END_RADIUS[3]=600.
endfunction
private function SetUpSPIRAL_CIRCLES takes nothing returns nothing
set SPIRAL_CIRCLES[1]=0.6
set SPIRAL_CIRCLES[2]=0.8
set SPIRAL_CIRCLES[3]=1.0
endfunction
private function SetUpSPIRAL_ENDINGS takes nothing returns nothing
set SPIRAL_ENDINGS[1]=3
set SPIRAL_ENDINGS[2]=3
set SPIRAL_ENDINGS[3]=3
endfunction
private function SetUpDURATION takes nothing returns nothing
set DURATION[1]=5.
set DURATION[2]=7.
set DURATION[3]=9.
endfunction
// proxy functions
// if you want to use formulae, edit these
private function Fire_Dmg takes integer level returns real
return FIRE_DMG[level]
endfunction
private function Spiral_Initial_Radius takes integer level returns real
return SPIRAL_INITIAL_RADIUS[level]
endfunction
private function Spiral_End_Radius takes integer level returns real
return SPIRAL_END_RADIUS[level]
endfunction
private function Spiral_Circles takes integer level returns real
return SPIRAL_CIRCLES[level]
endfunction
private function Spiral_Endings takes integer level returns integer
return SPIRAL_ENDINGS[level]
endfunction
private function Duration takes integer level returns real
return DURATION[level]
endfunction
// I wouldnt edit anything below this line, if i were you
private struct Data
unit c
integer level
integer i
timer t
real x
real y
real a
real b
real f
real d
integer fxcount=0
xefx array FX[MAX_FIRE_FX_PER_INSTANCE]
real array FXX[MAX_FIRE_FX_PER_INSTANCE]
real array FXY[MAX_FIRE_FX_PER_INSTANCE]
static Data array Structs
static integer Count=0
static timer T=CreateTimer()
static Data tmps
static boolexpr FireDmg
static timer array ImmoT
static effect array ImmoFX
static method ImmoCallback takes nothing returns nothing
local timer t=GetExpiredTimer()
local integer i=GetTimerData(t)
call DestroyEffect(Data.ImmoFX[i])
set Data.ImmoFX[i]=null
call ReleaseTimer(t)
endmethod
static method FireDmgFunc takes nothing returns boolean
local unit u=GetFilterUnit()
local integer i
local integer j=0
local timer t
local boolean b=false
if IsUnitEnemy(u, GetOwningPlayer(Data.tmps.c)) and IsUnitType(u, UNIT_TYPE_DEAD)==false and IsUnitType(u, UNIT_TYPE_MAGIC_IMMUNE)==false and IsUnitType(u, UNIT_TYPE_STRUCTURE)==false then
loop
exitwhen j>=Data.tmps.fxcount
if (((Data.tmps.FXX[j]-GetUnitX(u))*(Data.tmps.FXX[j]-GetUnitX(u)))+((Data.tmps.FXY[j]-GetUnitY(u))*(Data.tmps.FXY[j]-GetUnitY(u))))<=FIRE_DMG_RADIUS*FIRE_DMG_RADIUS then
set b=true
exitwhen true
endif
set j=j+1
endloop
if b then
call UnitDamageTarget(Data.tmps.c, u, Fire_Dmg(Data.tmps.level)*FIRE_DMG_TICK, false, false, FIRE_DMG_ATTACKTYPE, FIRE_DMG_DAMAGETYPE, WEAPON_TYPE_WHOKNOWS)
set i=GetUnitIndex(u)
if Data.ImmoFX[i]==null then
set Data.ImmoFX[i]=AddSpecialEffectTarget(FIRE_DMG_FX, u, FIRE_DMG_FX_ATTPT)
set t=NewTimer()
call SetTimerData(t, i)
call TimerStart(t, FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
set Data.ImmoT[i]=t
else
call TimerStart(Data.ImmoT[i], FIRE_DMG_FX_STAY, false, function Data.ImmoCallback)
endif
endif
endif
set u=null
return false
endmethod
method onDestroy takes nothing returns nothing
set .c=null
call ReleaseTimer(.t)
set Data.Count=Data.Count-1
set Data.Structs[.i]=Data.Structs[Data.Count]
set Data.Structs[.i].i=.i
if Data.Count==0 then
call PauseTimer(Data.T)
endif
endmethod
static method EndingCB takes nothing returns nothing
local Data s=GetTimerData(GetExpiredTimer())
local integer i=0
loop
exitwhen i>=Spiral_Endings(s.level)
set s.fxcount=s.fxcount-1
call s.FX[s.fxcount].destroy()
set i=i+1
endloop
if s.fxcount<=0 then
call s.destroy()
endif
endmethod
static method Ending takes nothing returns nothing
call TimerStart(GetExpiredTimer(), FX_INTERVAL, true, function Data.EndingCB)
endmethod
static method SpawnCB takes nothing returns nothing
local Data s=GetTimerData(GetExpiredTimer())
local integer i=0
local real d=2*bj_PI/Spiral_Endings(s.level)
local real f=s.a+(bj_PI/2)
loop
exitwhen i>=Spiral_Endings(s.level)
debug if s.fxcount>=MAX_FIRE_FX_PER_INSTANCE then
debug call BJDebugMsg("FireSpiral: Array overflow! Try increasing MAX_FIRE_FX_PER_INSTANCE!")
debug exitwhen true
debug endif
set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
set s.FX[s.fxcount].fxpath=FIRE_FX
set s.FX[s.fxcount].scale=FIRE_FX_SCALE
set s.fxcount=s.fxcount+1
set i=i+1
endloop
set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
set s.d=s.b*s.a
if s.d>Spiral_End_Radius(s.level) then
call TimerStart(s.t, Duration(s.level), false, function Data.Ending)
endif
endmethod
static method Callback takes nothing returns nothing
local integer i=Data.Count-1
loop
exitwhen i<0
set Data.tmps=Data.Structs[i]
call GroupEnumUnitsInRange(ENUM_GROUP, Data.tmps.x, Data.tmps.y, Spiral_End_Radius(Data.tmps.level)+FIRE_DMG_RADIUS, Data.FireDmg)
call GroupClear(ENUM_GROUP)
set i=i-1
endloop
endmethod
static method Cond takes nothing returns boolean
return GetSpellAbilityId()==AID
endmethod
static method Create takes nothing returns nothing
local Data s=Data.allocate()
local real d
local integer i=0
local real f
set s.c=GetTriggerUnit()
set s.level=GetUnitAbilityLevel(s.c, AID)
set s.t=NewTimer()
set s.f=GetUnitFacing(s.c)*bj_DEGTORAD
set s.x=GetUnitX(s.c)
set s.y=GetUnitY(s.c)
set s.b=(Spiral_End_Radius(s.level)-Spiral_Initial_Radius(s.level))/(2*bj_PI*Spiral_Circles(s.level))
set s.d=Spiral_Initial_Radius(s.level)
set s.a=s.d/s.b
set d=2*bj_PI/Spiral_Endings(s.level)
set f=s.a+(bj_PI/2)
loop
exitwhen i>=Spiral_Endings(s.level)
set s.FXX[s.fxcount]=s.x+(s.d*Cos(s.f+s.a+(i*d)))
set s.FXY[s.fxcount]=s.y+(s.d*Sin(s.f+s.a+(i*d)))
set s.FX[s.fxcount]=xefx.create(s.FXX[s.fxcount], s.FXY[s.fxcount], f)
set s.FX[s.fxcount].fxpath=FIRE_FX
set s.FX[s.fxcount].scale=FIRE_FX_SCALE
set s.fxcount=s.fxcount+1
set i=i+1
endloop
if s.d==0 then
set s.a=2*FIRE_FX_RADIUS/s.b
else
set s.a=2*Asin((2*FIRE_FX_RADIUS)/(2*s.d))+s.a
endif
set s.d=s.b*s.a
call SetTimerData(s.t, s)
call TimerStart(s.t, FX_INTERVAL, true, function Data.SpawnCB)
set Data.Structs[Data.Count]=s
set s.i=Data.Count
if Data.Count==0 then
call TimerStart(Data.T, FIRE_DMG_TICK, true, function Data.Callback)
endif
set Data.Count=Data.Count+1
endmethod
static method onInit takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, function Data.Create)
call TriggerAddCondition(t, Condition(function Data.Cond))
set Data.FireDmg=Condition(function Data.FireDmgFunc)
call SetUpFIRE_DMG()
call SetUpSPIRAL_INITIAL_RADIUS()
call SetUpSPIRAL_END_RADIUS()
call SetUpSPIRAL_CIRCLES()
call SetUpSPIRAL_ENDINGS()
call SetUpDURATION()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Messages initializer Init
private function CreditsProxy takes nothing returns nothing
call ExecuteFunc(SCOPE_PRIVATE+"Credits")
endfunction
private function Commands takes nothing returns nothing
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, "|cff00bfffCommands:")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-reset|r: Spawns some footmen around you.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-level |cff0000e0<level>|r: Sets the level of your hero to the specified level.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " Note that you cannot decrease your hero's level this way.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-handleid|r: Creates a location, displays its index - 0x1000001 and destroys it.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-commands|r: Shows this list.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-credits|r: Shows the credits.")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " |cffffcc00-clear|r: Clears all text-messages.")
if GetExpiredTimer()!=null then
call TimerStart(GetExpiredTimer(), 60., false, function CreditsProxy)
endif
endfunction
private function Credits takes nothing returns nothing
call ClearTextMessages()
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, "|cff00bfffCredits:")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Blaxor|r for the inspiration")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00cohadar|r for his PUI library")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Rising_Dusk|r for his GroupUtils library")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Vexorian|r for JassHelper and TimerUtils")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00PipeDream|r for Grimoire and all his help with spirals")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00PitzerMike|r for JassNewGenPack")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00SFilip|r for TESH")
if GetExpiredTimer()!=null then
call TimerStart(GetExpiredTimer(), 60., false, function Commands)
endif
endfunction
private function ClearActions takes nothing returns nothing
call ClearTextMessages()
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterPlayerChatEvent(t, Player(0), "-clear", true)
call TriggerAddAction(t, function ClearActions)
set t=CreateTrigger()
call TriggerRegisterPlayerChatEvent(t, Player(0), "-commands", true)
call TriggerAddAction(t, function Commands)
set t=CreateTrigger()
call TriggerRegisterPlayerChatEvent(t, Player(0), "-credits", true)
call TriggerAddAction(t, function Credits)
call TimerStart(CreateTimer(), 60., false, function Commands)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Basic initializer Init
globals
unit HERO
endglobals
function H2I takes handle h returns integer
return GetHandleId(h)
endfunction
private function Init takes nothing returns nothing
set HERO=CreateUnit(Player(0), 'HERO', 0,0,0)
call PanCameraToTimed(0,0,0)
call FogEnable(false)
call FogMaskEnable(false)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Reset initializer Init
private function Actions takes nothing returns nothing
local real r
set r=0
loop
call CreateUnit(Player(12), 'hfoo', 0+(256*Cos(r)), 512+(256*Sin(r)), 0)
set r=r+(bj_PI/4)
exitwhen r>=(7*bj_PI)/4
endloop
set r=0
loop
call CreateUnit(Player(12), 'hfoo', 512+(256*Cos(r)), 0+(256*Sin(r)), 0)
set r=r+(bj_PI/4)
exitwhen r>=(7*bj_PI)/4
endloop
set r=0
loop
call CreateUnit(Player(12), 'hfoo', 0+(256*Cos(r)), -512+(256*Sin(r)), 0)
set r=r+(bj_PI/4)
exitwhen r>=(7*bj_PI)/4
endloop
set r=0
loop
call CreateUnit(Player(12), 'hfoo', -512+(256*Cos(r)), 0+(256*Sin(r)), 0)
set r=r+(bj_PI/4)
exitwhen r>=(7*bj_PI)/4
endloop
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerAddAction(t, function Actions)
call TriggerRegisterPlayerChatEvent(t, Player(0), "-reset", true)
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library LevelUp initializer Init uses Basic
private function LevelAction takes nothing returns nothing
local integer newlvl
local string s = GetEventPlayerChatString()
if SubString(s, 0, 7)=="-level " then
set newlvl=S2I(SubString(s, 7, StringLength(s)))
if newlvl>GetUnitLevel(HERO) and newlvl<=10 then
call SetHeroLevel(HERO, newlvl, true)
else
debug call BJDebugMsg("LevelUp - Wrong new level!")
endif
else
debug call BJDebugMsg("LevelUp - Don't try to trick my triggers!")
endif
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterPlayerChatEvent(t, Player(0), "-level ", false)
call TriggerAddAction(t, function LevelAction)
set t=null
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
function Trig_handleid_Actions takes nothing returns nothing
local location l=Location(0,0)
call BJDebugMsg("Max Handle ID: "+I2S(H2I(l)-0x100001))
call RemoveLocation(l)
set l=null
endfunction
//===========================================================================
function InitTrig_handleid takes nothing returns nothing
set gg_trg_handleid = CreateTrigger( )
call TriggerRegisterPlayerChatEvent(gg_trg_handleid, Player(0), "-handleid", true)
call TriggerAddAction( gg_trg_handleid, function Trig_handleid_Actions )
endfunction
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library xebasic
//**************************************************************************
//
// xebasic 0.4
// =======
// XE_DUMMY_UNITID : Rawcode of the dummy unit in your map. It should
// use the dummy.mdx model, so remember to import it as
// well, just use copy&paste to copy the dummy from the
// xe map to yours, then change the rawcode.
//
// XE_HEIGHT_ENABLER: Medivh's raven form ability, you may need to change
// this rawcode to another spell that morphs into a flier
// in case you modified medivh's spell in your map.
//
// XE_TREE_RECOGNITION: The ancients' Eat tree ability, same as with medivh
// raven form, you might have to change it.
//
// XE_ANIMATION_PERIOD: The global period of animation used by whatever
// timer that depends on it, if you put a low value
// the movement will look good but it may hurt your
// performance, if instead you use a high value it
// will not lag but will be fast.
//
// XE_MAX_COLLISION_SIZE: The maximum unit collision size in your map, if
// you got a unit bigger than 197.0 it would be
// a good idea to update this constant, since some
// enums will not find it. Likewise, if none of
// your units can go bellow X and X is much smaller
// than 197.0, it would be a good idea to update
// as well, since it will improve the performance
// those enums.
//
// Notice you probably don't have to update this library, unless I specify
// there are new constants which would be unlikely.
//
//**************************************************************************
//===========================================================================
globals
constant integer XE_DUMMY_UNITID = 'dumm'
constant integer XE_HEIGHT_ENABLER = 'Amrf'
constant integer XE_TREE_RECOGNITION = 'Aeat'
constant real XE_ANIMATION_PERIOD = 0.025
constant real XE_MAX_COLLISION_SIZE = 197.0
endglobals
endlibrary
library xefx initializer init requires xebasic
//**************************************************
// xefx 0.6
// --------
// Recommended: ARGB (adds ARGBrecolor method)
// For your movable fx needs
//
//**************************************************
//==================================================
globals
private constant integer MAX_INSTANCES = 8190 //change accordingly.
private constant real RECYCLE_DELAY = 4.0
//recycling, in order to show the effect correctly, must wait some time before
//removing the unit.
private timer recycler
private timer NOW
endglobals
private struct recyclebin extends array
unit u
real schedule
static recyclebin end=0
static recyclebin begin=0
static method Recycle takes nothing returns nothing
call RemoveUnit(.begin.u) //this unit is private, systems shouldn't mess with it.
set .begin.u=null
set .begin=recyclebin(integer(.begin)+1)
if(.begin==.end) then
set .begin=0
set .end=0
else
call TimerStart(recycler, .begin.schedule-TimerGetElapsed(NOW), false, function recyclebin.Recycle)
endif
endmethod
endstruct
private function init takes nothing returns nothing
set recycler=CreateTimer()
set NOW=CreateTimer()
call TimerStart(NOW,43200,true,null)
endfunction
struct xefx[MAX_INSTANCES]
public integer tag=0
private unit dummy
private effect fx=null
private real zang=0.0
private integer r=255
private integer g=255
private integer b=255
private integer a=255
private integer abil=0
static method create takes real x, real y, real facing returns xefx
local xefx this=xefx.allocate()
set this.dummy= CreateUnit(Player(15), XE_DUMMY_UNITID, x,y, facing*bj_RADTODEG)
call UnitAddAbility(this.dummy,XE_HEIGHT_ENABLER)
call UnitAddAbility(this.dummy,'Aloc')
call UnitRemoveAbility(this.dummy,XE_HEIGHT_ENABLER)
call SetUnitX(this.dummy,x)
call SetUnitY(this.dummy,y)
return this
endmethod
method operator owner takes nothing returns player
return GetOwningPlayer(this.dummy)
endmethod
method operator owner= takes player p returns nothing
call SetUnitOwner(this.dummy,p,false)
endmethod
method operator teamcolor= takes playercolor c returns nothing
call SetUnitColor(this.dummy,c)
endmethod
method operator scale= takes real value returns nothing
call SetUnitScale(this.dummy,value,value,value)
endmethod
//! textmacro XEFX_colorstuff takes colorname, colorvar
method operator $colorname$ takes nothing returns integer
return this.$colorvar$
endmethod
method operator $colorname$= takes integer value returns nothing
set this.$colorvar$=value
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
//! endtextmacro
//! runtextmacro XEFX_colorstuff("red","r")
//! runtextmacro XEFX_colorstuff("green","g")
//! runtextmacro XEFX_colorstuff("blue","b")
//! runtextmacro XEFX_colorstuff("alpha","a")
method recolor takes integer r, integer g , integer b, integer a returns nothing
set this.r=r
set this.g=g
set this.b=b
set this.a=a
call SetUnitVertexColor(this.dummy,this.r,this.g,this.b,this.a)
endmethod
implement optional ARGBrecolor
method operator abilityid takes nothing returns integer
return this.abil
endmethod
method operator abilityid= takes integer a returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(a!=0) then
call UnitAddAbility(this.dummy,a)
endif
set this.abil=a
endmethod
method flash takes string fx returns nothing
call DestroyEffect(AddSpecialEffectTarget(fx,this.dummy,"origin"))
endmethod
method operator xyangle takes nothing returns real
return GetUnitFacing(this.dummy)*bj_DEGTORAD
endmethod
method operator xyangle= takes real value returns nothing
call SetUnitFacing(this.dummy,value*bj_RADTODEG)
endmethod
method operator zangle takes nothing returns real
return this.zang
endmethod
method operator zangle= takes real value returns nothing
local integer i=R2I(value*bj_RADTODEG+90.5)
set this.zang=value
if(i>=180) then
set i=179
elseif(i<0) then
set i=0
endif
call SetUnitAnimationByIndex(this.dummy, i )
endmethod
method operator x takes nothing returns real
return GetUnitX(this.dummy)
endmethod
method operator y takes nothing returns real
return GetUnitY(this.dummy)
endmethod
method operator z takes nothing returns real
return GetUnitFlyHeight(this.dummy)
endmethod
method operator z= takes real value returns nothing
call SetUnitFlyHeight(this.dummy,value,0)
endmethod
method operator x= takes real value returns nothing
call SetUnitX(this.dummy,value)
endmethod
method operator y= takes real value returns nothing
call SetUnitY(this.dummy,value)
endmethod
method operator fxpath= takes string newpath returns nothing
if (this.fx!=null) then
call DestroyEffect(this.fx)
endif
if (newpath=="") then
set this.fx=null
else
set this.fx=AddSpecialEffectTarget(newpath,this.dummy,"origin")
endif
endmethod
private method onDestroy takes nothing returns nothing
if(this.abil!=0) then
call UnitRemoveAbility(this.dummy,this.abil)
endif
if(this.fx!=null) then
call DestroyEffect(this.fx)
set this.fx=null
endif
if (recyclebin.end==MAX_INSTANCES) then
call TimerStart(recycler,0,false,function recyclebin.Recycle)
call ExplodeUnitBJ(this.dummy)
else
set recyclebin.end.u=this.dummy
set recyclebin.end.schedule=TimerGetElapsed(NOW)+RECYCLE_DELAY
set recyclebin.end= recyclebin( integer(recyclebin.end)+1)
if( recyclebin.end==1) then
call TimerStart(recycler, RECYCLE_DELAY, false, function recyclebin.Recycle)
endif
call SetUnitOwner(this.dummy,Player(15),false)
endif
set this.dummy=null
endmethod
endstruct
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library_once TimerUtils initializer init
//*********************************************************************
//* TimerUtils (Blue flavor for 1.23b or later)
//* ----------
//*
//* To implement it , create a custom text trigger called TimerUtils
//* and paste the contents of this script there.
//*
//* To copy from a map to another, copy the trigger holding this
//* library to your map.
//*
//* (requires vJass) More scripts: htt://www.wc3campaigns.net
//*
//* For your timer needs:
//* * Attaching
//* * Recycling (with double-free protection)
//*
//* set t=NewTimer() : Get a timer (alternative to CreateTimer)
//* ReleaseTimer(t) : Relese a timer (alt to DestroyTimer)
//* SetTimerData(t,2) : Attach value 2 to timer
//* GetTimerData(t) : Get the timer's value.
//* You can assume a timer's value is 0
//* after NewTimer.
//*
//* Blue Flavor: Slower than the red flavor, it got a 408000 handle id
//* limit, which means that if more than 408000 handle ids
//* are used in your map, TimerUtils might fail, this
//* value is quite big and it is much bigger than the
//* timer limit in Red flavor.
//*
//********************************************************************
//==================================================================================================
globals
private hashtable hasht //I <3 blizz
endglobals
//It is dependent on jasshelper's recent inlining optimization in order to perform correctly.
function SetTimerData takes timer t, integer value returns nothing
call SaveInteger(hasht,0, GetHandleId(t), value)
endfunction
function GetTimerData takes timer t returns integer
return LoadInteger(hasht, 0, GetHandleId(t))
endfunction
//==========================================================================================
globals
private timer array tT
private integer tN = 0
private constant integer HELD=0x28829022
//use a totally random number here, the more improbable someone uses it, the better.
endglobals
//==========================================================================================
function NewTimer takes nothing returns timer
if (tN==0) then
set tT[0]=CreateTimer()
else
set tN=tN-1
endif
call SetTimerData(tT[tN],0)
return tT[tN]
endfunction
//==========================================================================================
function ReleaseTimer takes timer t returns nothing
if(t==null) then
debug call BJDebugMsg("Warning: attempt to release a null timer")
return
endif
if (tN==8191) then
debug call BJDebugMsg("Warning: Timer stack is full, destroying timer!!")
//stack is full, the map already has much more troubles than the chance of bug
call DestroyTimer(t)
else
call PauseTimer(t)
if(GetTimerData(t)==HELD) then
debug call BJDebugMsg("Warning: ReleaseTimer: Double free!")
return
endif
call SetTimerData(t,HELD)
set tT[tN]=t
set tN=tN+1
endif
endfunction
private function init takes nothing returns nothing
set hasht = InitHashtable()
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library GroupUtils
//******************************************************************************
//* BY: Rising_Dusk
//*
//* This library is a simple implementation of a stack for groups that need to
//* be in the user's control for greater than an instant of time. Additionally,
//* this library provides a single, global group variable for use with user-end
//* enumerations. It is important to note that users should not be calling
//* DestroyGroup() on the global group, since then it may not exist for when it
//* it is next needed.
//*
//* The group stack removes the need for destroying groups and replaces it with
//* a recycling method.
//* function NewGroup takes nothing returns group
//* function ReleaseGroup takes group g returns boolean
//* function GroupRefresh takes group g returns nothing
//*
//* NewGroup grabs a currently unused group from the stack or creates one if the
//* stack is empty. You can use this group however you'd like, but always
//* remember to call ReleaseGroup on it when you are done with it. If you don't
//* release it, it will 'leak' and your stack may eventually overflow if you
//* keep doing that.
//*
//* GroupRefresh cleans a group of any shadow references which may be clogging
//* its hash table. If you remove a unit from the game who is a member of a unit
//* group, it will 'effectively' remove the unit from the group, but leave a
//* shadow in its place. Calling GroupRefresh on a group will clean up any
//* shadow references that may exist within it.
//*
globals
//* Group for use with all instant enumerations
group ENUM_GROUP = CreateGroup()
//* Temporary references for GroupRefresh
private boolean Flag = false
private group Refr = null
//* Assorted constants
private constant integer MAX_HANDLE_COUNT = 408000
private constant integer MIN_HANDLE_ID = 0x100000
//* Arrays and counter for the group stack
private group array Groups
private integer array Status[MAX_HANDLE_COUNT]
private integer Count = 0
endglobals
private function AddEx takes nothing returns nothing
if Flag then
call GroupClear(Refr)
set Flag = false
endif
call GroupAddUnit(Refr, GetEnumUnit())
endfunction
function GroupRefresh takes group g returns nothing
set Flag = true
set Refr = g
call ForGroup(Refr, function AddEx)
if Flag then
call GroupClear(g)
endif
endfunction
function NewGroup takes nothing returns group
if Count == 0 then
set Groups[0] = CreateGroup()
else
set Count = Count - 1
endif
set Status[GetHandleId(Groups[Count])-MIN_HANDLE_ID] = 1
return Groups[Count]
endfunction
function ReleaseGroup takes group g returns boolean
local integer stat = Status[GetHandleId(g)-MIN_HANDLE_ID]
local boolean b = true
if g == null then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Null groups cannot be released")
set b = false
elseif stat == 0 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Group not part of stack")
set b = false
elseif stat == 2 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Groups cannot be multiply released")
set b = false
elseif Count == 8191 then
debug call BJDebugMsg(SCOPE_PREFIX+" Error: Max groups achieved, destroying group")
call DestroyGroup(g)
set b = false
else
call GroupClear(g)
set Groups[Count] = g
set Count = Count + 1
set Status[GetHandleId(g)-MIN_HANDLE_ID] = 2
endif
return b
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
//==============================================================================
// PUI -- Perfect Unit Indexing by Cohadar -- v5.1
//==============================================================================
//
// PURPOUSE:
// * Extending UnitUserData()
// * This is basically perfect hashing algorithm for units
//
// HOW TO USE:
// * You have only one function at your disposal GetUnitIndex(unit)
// It will return a unique index for each unit in range 1..8190
//
// * What you will do with that index is all up to you
// Of course using global arrays is the most obvious choice
// Advanced jassers will think of a couple of more clever ones ofc.
//
// * There are also 2 textmacros available at the end of library code
// They can be used for easier attaching to units
// PUI for structs
// PUI_PROPERTY for unit, integer, real, boolean and string variables
//
// PROS:
// * You can use any number of systems that previously could not work together
// because they all required exclusive access of UnitUserData()
//
// * You can also use this to attach spell data structs to casters
//
// * There are no SetUnitIndex() or ClearUnitIndex() functions here
// Each unit gets assigned one index that cannot be changed
// That index will be automatically recycled when unit is removed from the game.
//
// CONS:
// * This system uses UnitUserData() itself
// That means that if you want to use PUI you must recode
// any other system that uses UnitUserData() to use GetUnitIndex() instead
//
// * If you use UnitIndex for arrays of non-native types (timers, effects and similar)
// you must check if timer on that index already exists before you create a new one.
// This can happen if GetUnitIndex() assigns a recycled index (index of some dead and removed unit)
// to the newly created unit for which you intended to use timer for
//
// * All in all this is not a sys for newbies, it gives great power,
// but it requires knowledge and carefull handling
//
// DETAILS:
// * System is using unit array to keep track of all units with an index.
// Array is periodically checked for removed units,
// when removed unit is found, index is recycled.
// Indexes have "decay time" to prevent bugs
// caused by attaching to "Can't Raise, Does not decay" type units,
// or by using RemoveUnit() function
//
// SYSTEM COMMANDS: (debug mode only, red player only)
//
// * type -pui to display indexes of currently selected units
// * type -puistats to display some stats
//
// THANKS TO:
// * Vexorian - for his help with PUI textmacro
//
// HOW TO IMPORT:
// * Just create a trigger named PUI
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library PUI initializer Init
//==============================================================================
globals
//-----------------------------------------------
private constant real INDEX_DECAY_TIME = 5. // seconds
//-----------------------------------------------
private constant real PERIOD = 0.03125 // 32 fps
//-----------------------------------------------
private constant integer DECAY_TICKS = R2I(INDEX_DECAY_TIME/PERIOD)
//-----------------------------------------------
private integer array Indexz
private unit array Unitz
private integer array Decayz
private integer array Tickz
private integer maxindex = 0
private integer topindex = 0
private integer decayindex = 0
private integer checker = 0
private integer decayer = 0
private integer tick = 0
endglobals
//==============================================================================
private function PeriodicRecycler takes nothing returns boolean
local integer temp
set tick = tick + 1
if topindex > decayindex then
set checker = checker + 1
if checker > topindex then
set checker = decayindex + 1
endif
if (GetUnitUserData(Unitz[checker])==0) then
set decayindex = decayindex + 1
set Unitz[checker] = Unitz[decayindex]
// swap(checker, decayindex)
set temp = Indexz[checker]
set Indexz[checker] = Indexz[decayindex]
set Indexz[decayindex] = temp
set Decayz[decayindex] = DECAY_TICKS
set Tickz[decayindex] = tick
endif
endif
if decayindex > 0 then
set decayer = decayer + 1
if decayer > decayindex then
set decayer = 1
endif
set Decayz[decayer] = Decayz[decayer] - (tick-Tickz[decayer])
if Decayz[decayer] > 0 then
set Tickz[decayer] = tick
else
// swap(decayer, decayindex)
set temp = Indexz[decayer]
set Indexz[decayer] = Indexz[decayindex]
set Indexz[decayindex] = temp
set Unitz[decayindex] = Unitz[topindex]
// swap(decayindex, topindex)
set temp = Indexz[decayindex]
set Indexz[decayindex] = Indexz[topindex]
set Indexz[topindex] = temp
set decayindex = decayindex - 1
set topindex = topindex - 1
endif
endif
return false
endfunction
//==============================================================================
// Main and only function exported by this library
//==============================================================================
function GetUnitIndex takes unit whichUnit returns integer
local integer index
debug if whichUnit == null then
debug call BJDebugMsg("|c00FF0000ERROR: PUI - Index requested for null unit")
debug return 0
debug endif
set index = GetUnitUserData(whichUnit)
if index == 0 then
set topindex = topindex + 1
if topindex > maxindex then
set maxindex = topindex
set Indexz[topindex] = topindex
endif
set index = Indexz[topindex]
set Unitz[topindex] = whichUnit
call SetUnitUserData(whichUnit, index)
set index = GetUnitUserData(whichUnit)
// this happens when requesting unit index for removed unit
debug if index == 0 then
debug call BJDebugMsg("|c00FFCC00WARNING: PUI - Bad unit handle")
debug endif
//debug call BJDebugMsg("|c00FFCC00PUI: Index assigned #" + I2S(index))
endif
return index
endfunction
//==============================================================================
private function DisplayStats takes nothing returns nothing
call BJDebugMsg("=============================================")
call BJDebugMsg("Biggest index ever = " + I2S(maxindex))
call BJDebugMsg("Indexes in use = " + I2S(topindex-decayindex))
call BJDebugMsg("Decaying indexes = " + I2S(decayindex))
call BJDebugMsg("Released indexes = " + I2S(maxindex-topindex))
call BJDebugMsg("=============================================")
endfunction
//===========================================================================
private function DisplaySelectedEnum takes nothing returns nothing
call BJDebugMsg( "PUI(" + ( GetUnitName(GetEnumUnit()) + ( ") = " + I2S(GetUnitUserData(GetEnumUnit())) ) ) )
endfunction
//===========================================================================
private function DisplaySelected takes nothing returns nothing
local group g = CreateGroup()
call SyncSelections()
call GroupEnumUnitsSelected(g, Player(0), null)
call ForGroup(g, function DisplaySelectedEnum)
call DestroyGroup(g)
set g = null
endfunction
//==============================================================================
private function Init takes nothing returns nothing
local trigger trig
set trig = CreateTrigger()
call TriggerRegisterTimerEvent( trig, PERIOD, true )
call TriggerAddCondition( trig, Condition(function PeriodicRecycler) )
debug set trig = CreateTrigger()
debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-pui", true )
debug call TriggerAddAction( trig, function DisplaySelected )
debug set trig = CreateTrigger()
debug call TriggerRegisterPlayerChatEvent( trig, Player(0), "-puistats", true )
debug call TriggerAddAction( trig, function DisplayStats )
endfunction
endlibrary
//===========================================================================
// Allowed PUI_PROPERTY TYPES are: unit, integer, real, boolean, string
// Do NOT put handles that need to be destroyed here (timer, trigger, ...)
// Instead put them in a struct and use PUI textmacro
//===========================================================================
//! textmacro PUI_PROPERTY takes VISIBILITY, TYPE, NAME, DEFAULT
$VISIBILITY$ struct $NAME$
private static unit array pui_unit
private static $TYPE$ array pui_data
//-----------------------------------------------------------------------
// Returns default value when first time used
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns $TYPE$
local integer pui = GetUnitIndex(whichUnit)
if .pui_unit[pui] != whichUnit then
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = $DEFAULT$
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, $TYPE$ whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
endmethod
endstruct
//! endtextmacro
//===========================================================================
// Never destroy PUI structs directly.
// Use .release() instead, will call .destroy()
//===========================================================================
//! textmacro PUI
private static unit array pui_unit
private static integer array pui_data
private static integer array pui_id
//-----------------------------------------------------------------------
// Returns zero if no struct is attached to unit
//-----------------------------------------------------------------------
static method operator[] takes unit whichUnit returns integer
local integer pui = GetUnitIndex(whichUnit)
if .pui_data[pui] != 0 then
if .pui_unit[pui] != whichUnit then
// recycled handle detected
call .destroy(.pui_data[pui])
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endif
endif
return .pui_data[pui]
endmethod
//-----------------------------------------------------------------------
// This will overwrite already attached struct if any
//-----------------------------------------------------------------------
static method operator[]= takes unit whichUnit, integer whichData returns nothing
local integer pui = GetUnitIndex(whichUnit)
if .pui_data[pui] != 0 then
call .destroy(.pui_data[pui])
endif
set .pui_unit[pui] = whichUnit
set .pui_data[pui] = whichData
set .pui_id[whichData] = pui
endmethod
//-----------------------------------------------------------------------
// If you do not call release struct will be destroyed when unit handle gets recycled
//-----------------------------------------------------------------------
method release takes nothing returns nothing
local integer pui= .pui_id[integer(this)]
call .destroy()
set .pui_unit[pui] = null
set .pui_data[pui] = 0
endmethod
//! endtextmacro