cr4xzZz
Also known as azwraith_ftL.
- Reaction score
- 51
Hey there.
I'm creating some sort of casting trigger for my boss on my map but I ran into a little problem with the newest PUI. I'm also using Cohadar's Damage Deteciton system (that requires PUI).
I get this error:
on this line:
But I need to check when DP is true...
Other way maybe is to use ordinary GetUnitIndex with an assigned global array, if this can't be accomplished with the nasty macro properties, right?
PUI:
Damage Detection:
I'm creating some sort of casting trigger for my boss on my map but I ran into a little problem with the newest PUI. I'm also using Cohadar's Damage Deteciton system (that requires PUI).
I get this error:
on this line:
JASS:
if DP(illidan) == true then
But I need to check when DP is true...
Other way maybe is to use ordinary GetUnitIndex with an assigned global array, if this can't be accomplished with the nasty macro properties, right?
JASS:
scope WhenToCast
//! runtextmacro PUI_PROPERTY("private", "boolean", "DP", "true")
private function DemPact takes unit illidan returns nothing
call TriggerSleepAction(60.)
set DP[illidan] = true
endfunction
private function Cast takes nothing returns boolean
local unit illidan = GetTriggerUnit()
local unit dmgr = GetEventDamageSource()
local real x
local real y
if IsUnitType(illidan, UNIT_TYPE_HERO) == true and GetOwningPlayer(illidan) == Player(PLAYER_NEUTRAL_AGGRESSIVE) == true then
if GetWidgetLife(illidan) < 4700. then
if DP(illidan) == true then
set x = GetUnitX(dmgr)
set y = GetUnitY(dmgr)
call IssuePointOrder(illidan, "carrionswarm", x, y)
set DP[illidan] = false
call DemPact.execute(illidan)
endif
endif
endif
set illidan = null
set dmgr = null
return true
endfunction
function InitTrig_WhenToCast takes nothing returns nothing
call TriggerAddCondition(GlobalOnDamageTrigger, Condition(function Cast))
endfunction
endscope
PUI:
JASS:
//==============================================================================
// 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
Damage Detection:
JASS:
//==============================================================================
// DD -- DAMAGE DETECTION SYSTEM BY COHADAR -- v1.0
//==============================================================================
//
// PURPOUSE:
// * detects when unit is damaged (not when it is attacked)
//
// HOW TO USE:
// * To register damage you will have to assign conditions to a GlobalOnDamageTrigger
//
// ---------------------------------------------------------------------------------
// call TriggerAddCondition( GlobalOnDamageTrigger, Condition(function YourCondition) )
// ---------------------------------------------------------------------------------
//
// * Or assign an action to a GlobalOnDamageTrigger
// ---------------------------------------------------------------------------------
// call TriggerAddAction( GlobalOnDamageTrigger, function YourAction )
// ---------------------------------------------------------------------------------
//
// * Condition functions MUST take nothing and return boolean
//
// * Condition functions MUST ALWAYS RETURN TRUE or system will not work
//
// * System will first execute all conditions and then all actions
//
// * Do NOT use waits in Conditions, you can use waits in actions
//
// * Conditions are faster than actions
//
// * Do NOT destroy, null or in any other way modify GlobalOnDamageTrigger
//
// * Inside your Action or Condition you can use this functions
//
// ---------------------------------------------------------------------------------
// GetTriggerUnit() - damaged unit
// GetEventDamage() - amount of damage (real)
// GetEventDamageSource() - unit that did the damage, this can be null.
// ---------------------------------------------------------------------------------
//
// PROS:
// * This is the most optimized OnDamage system of all times,
// also the most simple one to use. (I am so modest<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite1" alt=":)" title="Smile :)" loading="lazy" data-shortname=":)" />
//
// * You can use UnitDamageTarget() and similar functions in your actions and conditions
// This system is resistant to requrzion. (thanks to PUI)
//
// CONS:
// * None by itself,
// but it uses PUI and hence has all PROS and CONS that come with PUI
//
// DETAILS:
// * Just read the code, it is short and comments are good
//
// THANKS TO:
// * emjlr3 for showing me his OnAttack sys
//
// HOW TO IMPORT:
// * Just create a trigger named DamageDetection
// * convert it to text and replace the whole trigger text with this one
//
//==============================================================================
library DamageDetection initializer Init uses PUI
globals
//===========================================================================
// This trigger is the only thing this system exports
// This trigger will be executed when ever ANY unit on the map is damaged
//===========================================================================
trigger GlobalOnDamageTrigger
// prevents requrzion
private boolean array ignore
// array of OnDamage triggers, one unit - one trigger
private trigger array OnDamagePerUnit
endglobals
//===========================================================================
// Per Unit OnDamage triggers call this function,
// This function then calls GlobalOnDamageTrigger
//===========================================================================
private function OnDamage takes nothing returns boolean
local unit u = GetTriggerUnit()
local integer index = GetUnitIndex(u)
//call BJDebugMsg("|c0000FF00" + "OnDamage")
if ignore[index] then
//call BJDebugMsg("|c0000FF00" + "endless requrzion prevented")
else
// mutex <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" class="smilie smilie--sprite smilie--sprite8" alt=":D" title="Big Grin :D" loading="lazy" data-shortname=":D" />
set ignore[index] = true
if TriggerEvaluate(GlobalOnDamageTrigger) then
call TriggerExecute(GlobalOnDamageTrigger)
else
call BJDebugMsg("|c00FF0000" + "ERROR: Conditions for GlobalOnDamageTrigger MUST return TRUE")
endif
set ignore[index] = false
endif
set u = null
return false
endfunction
// makes sure one and only one OnDamage trigger is created per unit
private function LinkOnDamageTrigger takes unit u returns nothing
local integer index = GetUnitIndex(u)
local trigger trig = OnDamagePerUnit[index]
// index was recycled so we destroy trigger because
// it belongs to previous unit on that index
if (trig != null) then
call DestroyTrigger(trig)
endif
set trig = CreateTrigger()
//call BJDebugMsg("Registering OnDamage for " + GetUnitName(u))
call TriggerRegisterUnitEvent(trig, u, EVENT_UNIT_DAMAGED)
call TriggerAddCondition(trig,Condition(function OnDamage))
set trig = null
endfunction
//Add damage trigger to units who enter map
private function AddTriggers takes nothing returns boolean
local unit u = GetTriggerUnit()
call LinkOnDamageTrigger(u)
set u = null
return false
endfunction
//Add damage trigger to preplaced units
private function FirstGroup takes nothing returns nothing
local unit u = GetEnumUnit()
call LinkOnDamageTrigger(u)
set u = null
endfunction
// Init
private function Init takes nothing returns nothing
local trigger entmap_trig
local group g
// One trigger to OnDamage them all
set GlobalOnDamageTrigger = CreateTrigger()
// register OnDamage for preplaced units
set g = CreateGroup()
call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea, null)
call ForGroup(g,function FirstGroup)
call DestroyGroup(g)
set g = null
// create trigger that registers OnDamage for units that enter the map
set entmap_trig = CreateTrigger()
call TriggerRegisterEnterRectSimple(entmap_trig, bj_mapInitialPlayableArea)
call TriggerAddCondition(entmap_trig,Condition(function AddTriggers))
set entmap_trig = null
endfunction
endlibrary