//TESH.scrollpos=0
//TESH.alwaysfold=0
Name | Type | is_array | initial_value |
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// API:
//
// >>CreateDelayedEffect(whichEffect, X, Y, Delay, Timeout)
// - whichEffect is of type string and contains the path of the
// effect-to-be-spawned
// - X and Y indicate where the effect should be spawned
// - Delay is of type real and indicates how long to wait before spawning the
// effect
// - Timeout is of type real and indicates how long to wait before destroying
// the effect after it has been created
//
// >>CreateDelayedEffectZ(whichEffect, X, Y, Z, Delay, Timeout)
// - whichEffect: see above
// - X, Y and Z indicate where to spawn the effect
// - Delay: see above
// - Timeout: see above
//
// >>CreateDelayedEffectTarget(whichEffect, Target, AttachmentPoint, Delay, Timeout)
// - whichEffect: see above
// - Target is of type widget and indicates on which widget the effect should
// be spawned
// - AttachmentPoint is of type string and holds the attachment point where
// the effect should be spawned on target widget
// - Delay: see above
// - Timeout: see above
//
// CREDITS:
// - Vexorian (JassHelper; TimerUtils)
// - Anitarf (Suggestions)
// - KaTTaNa (AddSpecialEffectZ function @ wc3jass.com)
// - PitzerMike (JassNewGenPack)
// - Pipedream (Grimoire)
// - SFilip (TESH)
library DelFX uses TimerUtils
private struct DELFX
private effect fx
private string path
private boolean target
private widget tar
private string attpt
private real x
private real y
private real z
private timer t
private real timeout
private method onDestroy takes nothing returns nothing
if .fx!=null then
call DestroyEffect(.fx)
set .fx=null
endif
set .tar=null
call ReleaseTimer(.t)
endmethod
private static method Release takes nothing returns nothing
call DELFX.destroy(GetTimerData(GetExpiredTimer()))
endmethod
private static method Callback takes nothing returns nothing
local DELFX s=GetTimerData(GetExpiredTimer())
local destructable d
debug if s.fx==null then
if s.target then
set s.fx=AddSpecialEffectTarget(s.path, s.tar, s.attpt)
elseif s.z==0 then
set s.fx=AddSpecialEffect(s.path, s.x, s.y)
else
set d=CreateDestructableZ('OTip', s.x, s.y, s.z, 0,1.,0)
set s.fx=AddSpecialEffect(s.path, s.x, s.y)
call RemoveDestructable(d)
set d=null
endif
call TimerStart(s.t, s.timeout, false, function DELFX.Release)
debug else
debug call BJDebugMsg("DELFX["+I2S(s)+"].Callback: Effect already spawned!")
debug endif
endmethod
static method Create takes string path, boolean target, widget tar, string attpt, real x, real y, real z, real delay, real timeout returns DELFX
local DELFX s=DELFX.allocate()
set s.t=NewTimer()
call SetTimerData(s.t, s)
set s.path=path
set s.target=target
set s.tar=tar
set s.attpt=attpt
set s.x=x
set s.y=y
set s.z=z
set s.timeout=timeout
call TimerStart(s.t, delay, false, function DELFX.Callback)
return s
endmethod
endstruct
// The functions below have been explained above.
function CreateDelayedEffect takes string path, real x, real y, real delay, real timeout returns nothing
call DELFX.Create(path, false, null, "", x, y, 0, delay, timeout)
endfunction
function CreateDelayedEffectZ takes string path, real x, real y, real z, real delay, real timeout returns nothing
call DELFX.Create(path, false, null, "", x, y, z, delay, timeout)
endfunction
function CreateDelayedEffectTarget takes string path, widget target, string attachmentpoint, real delay, real timeout returns nothing
call DELFX.Create(path, true, target, attachmentpoint, 0, 0, 0, delay, timeout)
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// **************************************************************
// * PHOENIX-FORM V1.3.3
// * a really HOT spell
// *
// * CREDITS:
// * - Anitarf (suggestions, and a little help with parabolas)
// * - cohadar (PUI)
// * - Vexorian (Dummy Model, JassHelper)
// * - Pipedream (Grimoire)
// * - PitzerMike (NewGenPack)
// *
// * NOTES:
// * - Remember to change Mana consumption on Phoenix-Form.
// * - Increase TICK to lower CPU-load.
// *
// **************************************************************
library Phoenix initializer Init uses MissileSys, DelFX, PUI // I like to know all dependencies, though scope might be more adequate
// *************************************************************
// --- SETUP START
globals
private integer array PHOENIX_UID // units spawned when hero burned
private constant integer AID = 'A000' // Phoenix-Form
private constant integer FIREBALL_MISSILE_UID = 'h001' // unit resembling a fireball // collision size: 0
private constant integer BURN_FX_COUNT = 4 // number of effects used to simulate burning
private constant string FIREBALL_EXPLOSION_EFFECT = "Abilities\\Spells\\Human\\FlameStrike\\FlameStrike1.mdl" // effect that gets spawned when a Fireball hits the ground
private constant string IMMOLATION_FX = "Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
private constant string IMMOLATION_FX_ATTPT = "head"
private constant string CONVERSION_FX = "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl"
private string array BURN_FX // effect spawned when hero starts burning.
private string array BURN_FX_ATTPTS // attachment points of burning effects
private real array DEGRATE // HP degenerated every second // currently unused (initialized for use though)
private real array SPEWING_FREQ // time between spilling off fireballs
private real array SPEWING_RANGE // how far do fireballs fly? // NOTE: This is a mean value
private real array SPEWING_RANGE_DEVIATION // deviation from mean value defined above
private real array AOEDAMAGE // how much damage does a fireball deal?
private real array IMMOLATION_RANGE // units in this area get burned
private real array IMMOLATION_DAMAGE // units in IMMOLATION_RANGE take this much damage per second
private constant real IMMOLATION_FX_STAY = 1.25
private constant real CONVERSION_FX_TIMEOUT = 3.
private constant real FIREBALL_LAUNCH_HEIGHT = 100.
private constant real FIREBALL_IMPACT_HEIGHT = 15.
private constant real FIREBALL_ARC = 0.75
private constant real FIREBALL_EFFECT_TIMEOUT = 8. // beforementioned effects get destroyed after this many seconds
private constant real FIREBALL_EFFECT_BUFFER = 0.5 // seconds
private constant real FIREBALL_SPEED = 550. // speed of fireballs
private constant real AOEDMGRADIUS = 250. // Fireballs cause damage in this radius
private constant real TICK = 0.03125 // seconds // 32 calls/second
endglobals
private function Degrate takes integer level, unit u returns real // returns HP degenerated every second
return GetUnitState(u, UNIT_STATE_MAX_LIFE)/(10+(0*level)) // didnt change this because this depends on the heros max life
endfunction
private function Spewing_Freq takes integer level returns real // every ... seconds a fireball is spewed
return SPEWING_FREQ[level]
endfunction
private function Spewing_Range takes integer level returns real // how far do fireballs fly? // NOTE: This is a mean value
return SPEWING_RANGE[level]
endfunction
private function Spewing_Range_Deviation takes integer level returns real
return SPEWING_RANGE_DEVIATION[level]
endfunction
private function Aoedamage takes integer level returns real // how much damage does a fireball deal?
return AOEDAMAGE[level]
endfunction
private function Immolation_Range takes integer level returns real
return IMMOLATION_RANGE[level]
endfunction
private function Immolation_Damage takes integer level returns real
return IMMOLATION_DAMAGE[level]
endfunction
private function Burn_Fx takes integer id returns string
return BURN_FX[id]
endfunction
private function Burn_Fx_Attpts takes integer id returns string
return BURN_FX_ATTPTS[id]
endfunction
private function Phoenix_Uid takes integer level returns integer
return PHOENIX_UID[level]
endfunction
private function SetUpDEGRATE takes nothing returns nothing
set DEGRATE[1]=50.
set DEGRATE[2]=70.
set DEGRATE[3]=100.
endfunction
private function SetUpSPEWING_FREQ takes nothing returns nothing
set SPEWING_FREQ[1]=1.0
set SPEWING_FREQ[2]=0.9
set SPEWING_FREQ[3]=0.8
endfunction
private function SetUpSPEWING_RANGE takes nothing returns nothing
set SPEWING_RANGE[1]=500.
set SPEWING_RANGE[2]=600.
set SPEWING_RANGE[3]=700.
endfunction
private function SetUpSPEWING_RANGE_DEVIATION takes nothing returns nothing
set SPEWING_RANGE_DEVIATION[1]=0.5
set SPEWING_RANGE_DEVIATION[2]=0.5
set SPEWING_RANGE_DEVIATION[3]=0.5
endfunction
private function SetUpAOEDAMAGE takes nothing returns nothing
set AOEDAMAGE[1]=200.
set AOEDAMAGE[2]=250.
set AOEDAMAGE[3]=300.
endfunction
private function SetUpIMMOLATION_RANGE takes nothing returns nothing
set IMMOLATION_RANGE[1]=250
set IMMOLATION_RANGE[2]=275
set IMMOLATION_RANGE[3]=300
endfunction
private function SetUpIMMOLATION_DAMAGE takes nothing returns nothing
set IMMOLATION_DAMAGE[1]=45.
set IMMOLATION_DAMAGE[2]=60.
set IMMOLATION_DAMAGE[3]=75.
endfunction
private function SetUpBURN_FX takes nothing returns nothing
set BURN_FX[0]="Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
set BURN_FX[1]="Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
set BURN_FX[2]="Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
set BURN_FX[3]="Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl"
endfunction
private function SetUpBURN_FX_ATTPTS takes nothing returns nothing
set BURN_FX_ATTPTS[0]="origin"
set BURN_FX_ATTPTS[1]="hand, right"
set BURN_FX_ATTPTS[2]="hand, left"
set BURN_FX_ATTPTS[3]="head"
endfunction
private function SetUpPHOENIX_UID takes nothing returns nothing
set PHOENIX_UID[1]='h002'
set PHOENIX_UID[2]='h003'
set PHOENIX_UID[3]='h004'
endfunction
// --- SETUP END
// *************************************************************
// I dont really recommend changing anything below this line.
private keyword PhData
globals
private group g
private player tmpp
private boolexpr FSCond
private integer StrCnt=0
private PhData array Structs
private timer T
private effect array ImmoFX
private timer array ImmoT
endglobals
private struct PhData
unit c
unit phoenix
integer counter
integer level
integer spfreq
real HP
real degrate
real PrevHP
effect array Flames[BURN_FX_COUNT]
boolean sel
endstruct
private function FSCondFunc takes nothing returns boolean // unit isnt dead/a structure/magic-immune/a friend
return IsUnitType(GetFilterUnit(), UNIT_TYPE_DEAD)==false and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE)==false and IsUnitType(GetFilterUnit(),UNIT_TYPE_MAGIC_IMMUNE)==false and GetWidgetLife(GetFilterUnit())>0.405 and IsUnitEnemy(GetFilterUnit(), tmpp)
endfunction
private function SpewFS takes nothing returns boolean
local Missile s=GetMissile()
local PhData i=GetMissileData(s)
set tmpp=GetOwningPlayer(i.c)
call GroupEnumUnitsInRange(g, s.sx+(s.d*s.cos), s.sy+(s.d*s.sin), AOEDMGRADIUS, FSCond)
// Damage units // lame...
loop
exitwhen FirstOfGroup(g)==null
call UnitDamageTarget(i.c, FirstOfGroup(g), Aoedamage(i.level), false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(g, FirstOfGroup(g))
endloop
return false // safety, possible mac-desync
endfunction
private function ImmolationCallback takes nothing returns nothing
local integer i=GetTimerData(GetExpiredTimer())
call DestroyEffect(ImmoFX[i])
set ImmoFX[i]=null
call ReleaseTimer(ImmoT[i])
endfunction
private function Callback takes nothing returns nothing
local integer i=0
local integer j=0
local PhData s
local player p
local unit u
local real sr
local real rad
local real dist
local real x
local real y
loop
exitwhen i>=StrCnt
set s=Structs[i]
set s.HP=GetWidgetLife(s.c)-s.degrate // precalculate death
if s.HP<=0.405 and s.phoenix==null then // caster would be dead
set p=GetOwningPlayer(s.c)
set s.phoenix=CreateUnit(p, Phoenix_Uid(s.level), GetUnitX(s.c), GetUnitY(s.c), GetUnitFacing(s.c)) // summon the phoenix
if GetLocalPlayer()==p and IsUnitSelected(s.c, p) then // reselect the phoenix
call ClearSelection()
call SelectUnit(s.phoenix, true)
endif
call SetUnitPathing(s.c, false)
call ShowUnit(s.c, false)
call PauseUnit(s.c, true)
call CreateDelayedEffect(CONVERSION_FX, GetUnitX(s.c), GetUnitY(s.c), 0, CONVERSION_FX_TIMEOUT)
elseif s.HP>0.405 and s.phoenix==null then
call SetWidgetLife(s.c, s.HP)
set s.counter=s.counter+1
if ((s.counter-(s.counter/s.spfreq)*s.spfreq)==0) then // spew some fire
// this will get messy
set sr=Spewing_Range(s.level)
set rad=GetRandomReal(0, 2*bj_PI)
set dist=GetRandomReal(sr*Spewing_Range_Deviation(s.level), sr*(1.+Spewing_Range_Deviation(s.level)))
set x=GetUnitX(s.c)+dist*Cos(rad)
set y=GetUnitY(s.c)+dist*Sin(rad)
call Missile.create(GetOwningPlayer(s.c), FIREBALL_MISSILE_UID, GetUnitX(s.c), GetUnitY(s.c), FIREBALL_LAUNCH_HEIGHT, x, y, FIREBALL_IMPACT_HEIGHT, FIREBALL_SPEED, FIREBALL_ARC*FIREBALL_SPEED, function SpewFS, s)
set dist=SquareRoot(((x-GetUnitX(s.c))*(x-GetUnitX(s.c)))+((y-GetUnitY(s.c))*(y-GetUnitY(s.c))))
call CreateDelayedEffect(FIREBALL_EXPLOSION_EFFECT, x, y, (dist/FIREBALL_SPEED)-FIREBALL_EFFECT_BUFFER, FIREBALL_EFFECT_TIMEOUT)
endif
// immolation effect
set tmpp=GetOwningPlayer(s.c)
call GroupEnumUnitsInRange(g, GetUnitX(s.c), GetUnitY(s.c), Immolation_Range(s.level), FSCond) // get all units taking damage
loop // loop through them
set u=FirstOfGroup(g)
exitwhen u==null
if (ImmoFX[GetUnitIndex(u)]==null) then
set ImmoFX[GetUnitIndex(u)]=AddSpecialEffectTarget(IMMOLATION_FX, u, IMMOLATION_FX_ATTPT) // some nice FX
set ImmoT[GetUnitIndex(u)]=NewTimer()
call SetTimerData(ImmoT[GetUnitIndex(u)], GetUnitIndex(u))
call TimerStart(ImmoT[GetUnitIndex(u)], IMMOLATION_FX_STAY, false, function ImmolationCallback)
else
call TimerStart(ImmoT[GetUnitIndex(u)], IMMOLATION_FX_STAY, false, function ImmolationCallback)
endif
// damage them
call UnitDamageTarget(s.c, u, Immolation_Damage(s.level)*TICK, false, false, ATTACK_TYPE_MAGIC, DAMAGE_TYPE_FIRE, WEAPON_TYPE_WHOKNOWS)
call GroupRemoveUnit(g, u)
endloop
// end immolation effect
elseif s.phoenix!=null then
call SetWidgetLife(s.c, 1)
if IsUnitType(s.phoenix, UNIT_TYPE_DEAD)==true then // phoenix died again; reset to previous state
call SetWidgetLife(s.c, s.PrevHP*GetUnitState(s.c, UNIT_STATE_MAX_LIFE)) // life
call ShowUnit(s.c, true) // obvious?
call PauseUnit(s.c, false) // obvious!
call SetUnitInvulnerable(s.c, false) // this one too
call SetUnitPosition(s.c, GetUnitX(s.phoenix), GetUnitY(s.phoenix)) // move the hero to the position of the phoenix; SetUnitPosition to reset all orders
if GetLocalPlayer()==GetOwningPlayer(s.c) and s.sel then // reselect the hero
call ClearSelection()
call SelectUnit(s.c, true)
endif
set i=0
// cleanup
set s.c=null
set s.phoenix=null
set s.counter=0
loop
exitwhen j>=BURN_FX_COUNT
call DestroyEffect(s.Flames[j])
set s.Flames[j]=null
set j=j+1
endloop
set j=0
set StrCnt=StrCnt-1
set Structs[i]=Structs[StrCnt] // swap them
set Structs[StrCnt]=s
set i=i-1
if StrCnt==0 then
call PauseTimer(T)
endif
endif
set s.sel=IsUnitSelected(s.phoenix, GetOwningPlayer(s.phoenix)) //
endif
set i=i+1
endloop
endfunction
private function Actions takes nothing returns nothing
local PhData s
local integer i=0
local unit c=GetTriggerUnit()
if GetSpellAbilityId()==AID then
if Structs[StrCnt]==0 then
set Structs[StrCnt]=PhData.create()
endif
set s=Structs[StrCnt]
set s.c=c
set s.HP=GetWidgetLife(c)
set s.PrevHP=GetWidgetLife(c)/GetUnitState(c, UNIT_STATE_MAX_LIFE)
set s.level=GetUnitAbilityLevel(c, AID)
set s.degrate=Degrate(s.level, c)*TICK
set s.spfreq=R2I(Spewing_Freq(s.level)/TICK)
// Set hero on fire
loop
exitwhen i>=BURN_FX_COUNT
set s.Flames[i]=AddSpecialEffectTarget(Burn_Fx(i), c, Burn_Fx_Attpts(i))
set i=i+1
endloop
if StrCnt==0 then
call TimerStart(T, TICK, true, function Callback)
endif
// Global Array Setup
set StrCnt=StrCnt+1
call SetUnitInvulnerable(c, true) // Make hero invulnerable
endif
set c=null
endfunction
private function Init takes nothing returns nothing
local trigger t=CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, function Actions)
// initializer necessary globals
set g=CreateGroup()
set FSCond=Condition(function FSCondFunc)
set T=CreateTimer()
// Setup Spell constants
call SetUpDEGRATE()
call SetUpSPEWING_FREQ()
call SetUpSPEWING_RANGE()
call SetUpSPEWING_RANGE_DEVIATION()
call SetUpAOEDAMAGE()
call SetUpIMMOLATION_RANGE()
call SetUpIMMOLATION_DAMAGE()
call SetUpBURN_FX()
call SetUpBURN_FX_ATTPTS()
call SetUpPHOENIX_UID()
endfunction
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
//==============================================================================
// 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
//TESH.scrollpos=-1
//TESH.alwaysfold=0
// WARNING: messy code and a half-done library straight ahead!
// Do NOT use unless you KNOW what youre doing!
library MissileSys initializer Init
globals
private constant real TICK = 0.03125 //32/sec
private constant integer CROW_FORM = 'Amrf'
endglobals
globals
private Missile array Structs
private integer Count=0
private timer T
private Missile Current
private integer Data
endglobals
struct Missile
private unit m
readonly real speed
readonly real d
readonly real x
readonly real y
readonly real sx
readonly real sy
readonly real sz
readonly real tz
readonly real h
readonly real sin
readonly real cos
readonly integer data
private trigger trig
static method Parabola takes real s, real t, real h, real d, real x returns real
return ( -((h-s)/(((d*d)/8)+((d/2)*SquareRoot(((d*d)/16)-(((s*t)-(2*h*t)-(2*h*s))/(2*h*t*s))))-(((s*t)-(2*h*t)-(2*h*s))/(2*h*t*s))))*((x-(d/4)-SquareRoot(((d*d)/16)-(((s*t)-(2*h*t)-(2*h*s))/(2*h*t*s))))*(x-(d/4)-SquareRoot(((d*d)/16)-(((s*t)-(2*h*t)-(2*h*s))/(2*h*t*s)))))+h )
endmethod
static method Callback takes nothing returns nothing
local integer i=0
local Missile s
loop
exitwhen i>=Count
set s=Structs[i]
set s.x=s.x+(s.speed*TICK)
set s.y=Missile.Parabola(s.sz, s.tz, s.h, s.d, s.x)
call SetUnitFlyHeight(s.m, s.y, 0)
call SetUnitX(s.m, s.sx+(s.x*s.cos))
call SetUnitY(s.m, s.sy+(s.x*s.sin))
if s.d-s.x<s.speed*TICK then
call KillUnit(s.m)
set Data=s.data
set Current=s
call TriggerEvaluate(s.trig)
set s.m=null
call s.destroy()
set Count=Count-1
set Structs[i]=Structs[Count]
set i=i-1
if Count==0 then
call PauseTimer(T)
endif
endif
set i=i+1
endloop
endmethod
// Parameters: self-explanatory, UnitTypeID, start x, start y, start z, target x, target y, target z, missile speed, maximum height the missile reaches, executed when missile hits the ground, attached to the missile
static method create takes player owner, integer ID, real sx, real sy, real sz, real tx, real ty, real tz, real speed, real maxheight, code onHit, integer data returns Missile
local Missile s=Missile.allocate()
local real ang=Atan2(ty-sy, tx-sx)
set s.m=CreateUnit(owner, ID, sx, sy, ang*(180/bj_PI))
set s.speed=speed
set s.d=SquareRoot(((tx-sx)*(tx-sx))+((ty-sy)*(ty-sy)))
set s.x=0
set s.y=sz
set s.sx=sx
set s.sy=sy
set s.sz=sz
set s.tz=tz
set s.h=maxheight
set s.sin=Sin(ang)
set s.cos=Cos(ang)
set s.data=data
if s.trig==null then
set s.trig=CreateTrigger()
else
call TriggerClearConditions(s.trig)
endif
call TriggerAddCondition(s.trig, Condition(onHit))
call UnitAddAbility(s.m, CROW_FORM)
call UnitRemoveAbility(s.m, CROW_FORM)
call SetUnitFlyHeight(s.m, s.y, 0)
if Count==0 then
call TimerStart(T, TICK, true, function Missile.Callback)
endif
set Structs[Count]=s
set Count=Count+1
return s
endmethod
endstruct
// Only to be used in onHit callbacks
function GetMissileData takes Missile m returns integer
return m.data
endfunction
// Only to be used in onHit callbacks
function GetMissile takes nothing returns Missile
return Current
endfunction
private function Init takes nothing returns nothing
set T=CreateTimer()
endfunction
endlibrary
//TESH.scrollpos=-1
//TESH.alwaysfold=0
library Basic initializer Init
globals
unit HERO
boolexpr BTRUE
endglobals
function H2I takes handle h returns integer
return GetHandleId(h)
endfunction
private function BOOLTRUE takes nothing returns boolean
return true
endfunction
private function Init takes nothing returns nothing
set HERO=CreateUnit(Player(0), 'H000', 0, 0, 0)
set BTRUE=Condition(function BOOLTRUE)
endfunction
endlibrary
//TESH.scrollpos=-1
//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, " - |cffffcc00Anitarf|r (WC3C) for his suggestions")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00KaTTaNa|r (WC3Jass.com) for his AddSpecialEffectZ function")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Vexorian|r (WC3C) for JassHelper and TimerUtils")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Pipedream|r (WC3C) for Grimoire")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00Pitzermike|r (WC3C) for JassNewGenPack")
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,30, " - |cffffcc00SFilip|r (WC3C) 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=-1
//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 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