function PlaySoundAtPoint takes string f, real x, real y, real p, integer v returns nothing
local sound s = CreateSound( f, false, true, true, 10, 10, "" )
call SetSoundDuration( s, GetSoundFileDuration(f) )
call SetSoundChannel( s, 0 )
call SetSoundVolume( s, v )
call SetSoundPitch( s, p )
call SetSoundPosition(s, x, y, 0)
call StartSound(s)
call KillSoundWhenDone(s)
set s = null
endfunction
Name | Type | is_array | initial_value |
ALE_LOC | location | No | |
ALE_UNIT | unit | No | |
AMR_Pick | unit | No | |
AMR_Point | location | No | |
AMR_Unit | unit | No | |
B1T | integer | No | |
BB_ATCKD | unit | No | |
BB_ATCKR | unit | No | |
BB_Infamy_Condition | boolean | Yes | |
BB_Loc | location | No | |
BloodsailPick | integer | No | |
BloodsailTH | location | No | |
BloodsailWorker | location | No | |
Bombardment_TempPoint | location | No | |
Bounty_Killer | unit | No | |
Bounty_Player | player | No | |
CargoEvent | real | No | |
CargoTransportGroup | group | Yes | |
CargoTransportUnit | unit | Yes | |
Caster | unit | No | |
CBall_Angle | real | No | |
CBall_Caster_Unit | unit | No | |
CBall_Damage | real | No | |
CBall_Damaged_UnitGroup | group | No | |
CBall_Hashtable | hashtable | No | |
CBall_Speed | real | No | |
CBall_Travel_Range | real | No | |
CBall_UnitGroup | group | No | |
CBallKey | integer | No | |
CBallPoint1 | location | No | |
CBallPoint2 | location | No | |
CBallPoint3 | location | No | |
CBallUnit | unit | No | |
CheckDeathInList | boolean | Yes | |
CheckDeathList | integer | Yes | |
CheckDeathTimer | timer | No | |
DeathEvent | real | No | |
Deckhand | unit | No | |
DeckhandPlayer | player | No | |
Defeated | player | No | |
DetectRemoveAbility | abilcode | No | |
DetectTransformAbility | abilcode | No | |
DevilShark | group | No | |
DiveAttackAudioInt | integer | No | |
DiveAttackCanceled | boolean | Yes | |
DiveAttackCaster | unit | Yes | |
DiveAttackChaseDur | real | No | |
DiveAttackCooldownMax | real | No | |
DiveAttackCooldownMin | real | No | |
DiveAttackCooldownTimer | real | Yes | |
DiveAttackDamage | real | Yes | |
DiveAttackDamageMax | real | No | |
DiveAttackDamageMin | real | No | |
DiveAttackDir | real | No | |
DiveAttackDist | real | No | |
DiveAttackGroup | group | No | |
DiveAttackGroupAutocast | group | No | |
DiveAttackHeal | real | Yes | |
DiveAttackHealMultiplier | real | No | |
DiveAttackHeight | real | Yes | |
DiveAttackHeightLoss | real | No | |
DiveAttackIndex | integer | No | |
DiveAttackLocCasterCurrent | location | No | |
DiveAttackLocCasterNew | location | No | |
DiveAttackLocCursor | location | No | |
DiveAttackLoop | integer | No | |
DiveAttackMaxDur | real | Yes | |
DiveAttackMoveSpeed | real | No | |
DiveAttackSpeed | real | Yes | |
DiveAttackSpeedMultiplier | real | No | |
DiveAttackState | integer | Yes | |
DiveAttackTarget | unit | Yes | |
DiveAttackUnit | unit | Yes | |
EnemyBlue | force | No | |
EnemyGreen | force | No | |
EnemyOrange | force | No | |
EnemyPink | force | No | |
EnemyPurple | force | No | |
EnemyRed | force | No | |
EnemyTeal | force | No | |
EnemyYellow | force | No | |
EngulfSha_Damage | real | No | |
EngulfSha_Number | integer | No | |
EngulfSha_Point | location | No | |
EngulfSha_Unit | unit | No | |
FD | integer | No | |
FD_Angle | real | Yes | |
FD_Distance | real | Yes | |
FD_Hero | unit | Yes | |
FD_Off | boolean | Yes | |
FD_Point | location | Yes | |
FD_Skip | integer | No | |
FD_Spam | integer | Yes | |
FD_Speed | real | Yes | |
FD_Times | integer | No | |
Flare_Shot_Caster | unit | No | |
Flare_Shot_Point | location | No | |
GDD__Integers | integer | Yes | |
GDD__LeftMapGroup | group | No | |
GDD__TriggerArray | trigger | Yes | |
GDD__UnitArray | unit | Yes | |
GDD_Damage | real | No | |
GDD_DamagedUnit | unit | No | |
GDD_DamageSource | unit | No | |
GDD_Event | real | No | |
GREEN_Angle | real | No | |
GREEN_Caster_Unit | unit | No | |
GREEN_Damage | real | No | |
GREEN_Damaged_UnitGroup | group | No | |
GREEN_Hashtable | hashtable | No | |
GREEN_Speed | real | No | |
GREEN_Travel_Range | real | No | |
GREEN_UnitGroup | group | No | |
Hashtable | hashtable | No | |
HunterBox_Chance | integer | No | |
HunterBox_Loc | location | No | |
HunterBox_User | unit | No | |
I | integer | No | |
I_Angle | real | Yes | |
I_Arc | real | Yes | |
I_Caster | unit | Yes | |
I_CastNumber | integer | No | |
I_ConstDistance | real | Yes | |
I_Damage | real | Yes | |
I_Distance | real | Yes | |
I_Dummie | unit | Yes | |
I_Group | group | No | |
I_Integer | integer | No | |
I_Missile1 | unit | Yes | |
I_Missile2 | unit | Yes | |
I_Off | boolean | Yes | |
I_Offset | real | Yes | |
I_Point | location | Yes | |
I_Speed | real | Yes | |
I_Switch | integer | No | |
InfamyPickUnit | unit | No | |
InfamyPickUnitType | unitcode | No | |
InfamyPlayer | player | No | |
InfamyTrained | unit | No | |
InfamyUnitGroup | group | No | |
InfamyUnitType | unitcode | No | |
Integer | integer | Yes | |
IS_Condition | boolean | Yes | |
IsUnitAlive | boolean | Yes | |
IsUnitBeingUnloaded | boolean | Yes | |
IsUnitNew | boolean | Yes | |
IsUnitPreplaced | boolean | Yes | |
IsUnitReincarnating | boolean | Yes | |
IsUnitRemoved | boolean | Yes | |
IsUnitTransforming | boolean | Yes | |
KB | integer | No | |
KB_Angle | real | Yes | |
KB_Distance | real | Yes | |
KB_Off | boolean | Yes | |
KB_Point | location | Yes | |
KB_Skip | integer | No | |
KB_Spam | integer | Yes | |
KB_Speed | real | Yes | |
KB_Target | unit | Yes | |
KB_Times | integer | No | |
KillerOfUnit | unit | Yes | |
KUS_animation | animationname | No | |
KUS_effect | modelfile | No | |
KUS_group | group | No | |
KUS_hash | hashtable | No | |
KUS_height | real | No | |
KUS_knockup | boolean | No | |
KUS_speed | real | No | |
KUS_target | unit | No | |
KUS_temp_loc | location | No | |
KUS_temp_speed | real | No | |
Leapers | group | No | |
Level_1_Ruins | unitcode | Yes | |
Level_2_Ruins | unitcode | Yes | |
Level_3_Ruins | unitcode | Yes | |
MS_build_point | location | Yes | |
MS_Caster | unit | No | |
MS_create_point | location | No | |
MS_Group | group | No | |
MS_Loc | location | Yes | |
MS_Rect | rect | No | |
MS_target_point | location | No | |
MS_temp_point | location | Yes | |
Neptune_Point | location | No | |
NeptuneCaster | unit | No | |
NeptuneGroup | group | No | |
Overcharge_Attacker | unit | No | |
Overcharge_Chance | integer | No | |
Overcharge_ChanceNumber | integer | No | |
Overcharge_Point | location | No | |
Overcharge_Unit_Group | group | No | |
PCD_Ability | abilcode | No | |
PCD_DummyAbility | abilcode | No | |
PCD_DummyCaster | unit | No | |
PCD_DummyCasterId | unitcode | No | |
PCD_Hashtable | hashtable | No | |
PCD_IndicatorStartId | abilcode | No | |
PCD_Manacost | real | No | |
PCD_Time | real | No | |
PCD_Unit | unit | No | |
PCD_ValidTargetCheckId | abilcode | No | |
PCD_VTCBaseOrderId | string | No | |
Player_Infamy | player | No | |
Player_IS | player | No | |
Player_IS_Train | player | No | |
Player_Picked | player | No | |
PlayList | string | No | |
Points | location | Yes | |
QJC_Ally | boolean | No | |
QJC_Amount | real | No | |
QJC_AmountReduce | real | No | |
QJC_AoE | boolean | No | |
QJC_AoERadius | real | No | |
QJC_AoESFX | string | No | |
QJC_AttackType | attacktype | No | |
QJC_Caster | unit | No | |
QJC_ChainEffect | abilcode | No | |
QJC_ChainSFX | lightningtype | No | |
QJC_Damage | boolean | No | |
QJC_DamageType | damagetype | No | |
QJC_Enemy | boolean | No | |
QJC_Gold | boolean | No | |
QJC_Heal | boolean | No | |
QJC_Heatlh | boolean | No | |
QJC_JumpCount | integer | No | |
QJC_JumpDelayTime | real | No | |
QJC_JumpRadius | real | No | |
QJC_Leech | boolean | No | |
QJC_Mana | boolean | No | |
QJC_NoTarget | boolean | No | |
QJC_OnePerUnit | boolean | No | |
QJC_Priority | boolean | No | |
QJC_Slow | boolean | No | |
QJC_SlowEffect | abilcode | No | |
QJC_Stun | boolean | No | |
QJC_StunEffect | abilcode | No | |
QJC_TargetPoint | location | No | |
QJC_TargetSFX | string | No | |
QJC_TargetUnit | unit | No | |
QJCS_aGroup | group | Yes | |
QJCS_Ally | boolean | Yes | |
QJCS_Amount | real | Yes | |
QJCS_AmountReduce | real | Yes | |
QJCS_AoE | boolean | Yes | |
QJCS_AoERadius | real | Yes | |
QJCS_AoESFX | string | No | |
QJCS_AttackType | attacktype | Yes | |
QJCS_baseDummy | unit | Yes | |
QJCS_Caster | unit | Yes | |
QJCS_CasterESFX | string | No | |
QJCS_ChainEffect | abilcode | No | |
QJCS_ChainSFX | lightningtype | Yes | |
QJCS_ChainX | real | Yes | |
QJCS_ChainY | real | Yes | |
QJCS_ChainZ | real | Yes | |
QJCS_currUnit | unit | No | |
QJCS_Damage | boolean | Yes | |
QJCS_DamageType | damagetype | Yes | |
QJCS_dGroup | group | Yes | |
QJCS_Dummy | unit | No | |
QJCS_dummyGroup | group | No | |
QJCS_dummyPOS | location | No | |
QJCS_Enemy | boolean | Yes | |
QJCS_Gold | boolean | Yes | |
QJCS_Heal | boolean | Yes | |
QJCS_Health | boolean | Yes | |
QJCS_index | integer | Yes | |
QJCS_JumpCount | integer | Yes | |
QJCS_JumpDelayTime | real | Yes | |
QJCS_JumpRadius | real | Yes | |
QJCS_Leech | boolean | Yes | |
QJCS_LightningDPos | unit | Yes | |
QJCS_LightningDummy | unit | Yes | |
QJCS_LightningDur | real | Yes | |
QJCS_LightningIndex | integer | Yes | |
QJCS_LightningPos | location | Yes | |
QJCS_LightningSFX | lightning | Yes | |
QJCS_LightningTarget | unit | Yes | |
QJCS_Locust | abilcode | No | |
QJCS_Mana | boolean | Yes | |
QJCS_OnePerUnit | boolean | Yes | |
QJCS_prevTarget | unit | Yes | |
QJCS_Priority | boolean | Yes | |
QJCS_Slow | boolean | Yes | |
QJCS_SlowEffect | abilcode | Yes | |
QJCS_Stun | boolean | Yes | |
QJCS_StunEffect | abilcode | Yes | |
QJCS_SystemCount | integer | Yes | |
QJCS_SystemTime | real | Yes | |
QJCS_TargetSFX | string | Yes | |
QJCS_TargetUnit | unit | Yes | |
QJCS_tempGroup | group | No | |
QJCS_tempPos | location | Yes | |
QJCS_victimGroup | group | No | |
Real | real | Yes | |
SB | integer | No | |
SB_Angle | real | Yes | |
SB_Caster | unit | Yes | |
SB_Colision | real | Yes | |
SB_CountdownTimer | integer | Yes | |
SB_Damage | real | Yes | |
SB_Distance | real | Yes | |
SB_Group | group | No | |
SB_Height | real | Yes | |
SB_Hero | unit | Yes | |
SB_Level | integer | Yes | |
SB_LifeCaster | real | Yes | |
SB_LifeCaster_Reduction | real | Yes | |
SB_Light | lightning | Yes | |
SB_MaxDistance | real | Yes | |
SB_Missile | unit | Yes | |
SB_Off | boolean | Yes | |
SB_On | boolean | Yes | |
SB_Parabola | real | Yes | |
SB_Part | integer | Yes | |
SB_Point | location | Yes | |
SB_Skip | integer | No | |
SB_Special1 | effect | Yes | |
SB_Special2 | effect | Yes | |
SB_Special3 | effect | Yes | |
SB_Speed | real | Yes | |
SB_Sticked | boolean | Yes | |
SB_Target | unit | Yes | |
SB_Timer | real | Yes | |
SB_Times | integer | No | |
SD_Hero | unit | Yes | |
SD_Times | integer | No | |
SeaBlink_Loc | location | Yes | |
SeaBlinkCircle | unit | No | |
SeaBlinkGroup | group | No | |
SeaBlinkUnit | unit | No | |
Shark_Caster | unit | Yes | |
Shark_Damage | integer | Yes | |
Shark_Group | group | Yes | |
Shark_Index | integer | No | |
Shark_Loop | integer | No | |
Shark_MUI | integer | No | |
Shark_Point1 | location | Yes | |
Shark_Point2 | location | Yes | |
Shark_Point3 | location | Yes | |
Shark_Real | real | Yes | |
Shark_Real2 | real | Yes | |
Shark_Spell_Index | integer | Yes | |
Shark_Spell_Max | integer | No | |
Shark_Target | unit | Yes | |
Shock_Mine | unit | No | |
Shock_Mine_Point | location | No | |
Silent_Loc | location | No | |
SinsLanding | group | No | |
SinsRising | group | No | |
SkyraiderGroup | group | No | |
SummonerOfUnit | unit | Yes | |
Target | unit | No | |
TempKey | integer | No | |
TempLoc | location | No | |
TempPoint1 | location | No | |
TempPoint2 | location | No | |
TempPoint3 | location | No | |
TempUnit | unit | No | |
TEST_HERO | unit | No | |
UDex | integer | No | |
UDexLastRecycled | integer | No | |
UDexMax | integer | No | |
UDexNext | integer | Yes | |
UDexPrev | integer | Yes | |
UDexUnits | unit | Yes | |
UnitInAction | boolean | Yes | |
UnitInActionEvent | real | No | |
UnitIndexerEnabled | boolean | No | |
UnitIndexEvent | real | No | |
UnitName | string | Yes | |
UnitTypeEvent | real | No | |
UnitTypeOf | unitcode | Yes | |
Vendetta_Hero | unit | No | |
Vendetta_Point | location | No | |
WorldMaxX | real | No | |
WorldMaxY | real | No |
JeffQ's Basic Chain System v2.00f
Created Date: 22 January 2010
Author: JeffQ a.k.a JeffreyQ, SmileyJeff
**Official version will only be destributed by ME (JeffQ, JeffreyQ. SmileyJeff). Anyone else who upload this is edited.
I have been working on my AoS map and decided to create a chain system that can do pretty much anything.
Because my AoS have alot of chain spells that are in GUI.
So here it is. After 3 days of hardworking and understanding indexing. I present you JeffQ's Basic Chain System (MUI/GUI using Indexing).
======================
Change Log
======================
v2.00f, 24 Feb 2010
- Chain should no longer jump to buildings/structures.
- Some demo ability can still target buildings, this is because i didn't limit the target allowed at the ability editor. (Nothing to do with the system)
v2.00e, 31 Jan 2010
- Fix lightning height to match cliff or raised terrain.
- Added a raised terrain and cliff to test out.
v2.00d, 25 Jan 2010
- Rearrange Folder for easier implementing in other maps.
- Updated "How To Use" in the README to give a step by step tutorial on how to implement. Please do give it a read.
v2.00c, 24 Jan 2010
- Chain now gets unit height +25. Meaning that if you target a flying unit, the chain height will change accordingly.
- Added a few flying units to let you try out the dynamic chain height.
- Added Chain Globals Trigger to store Locust.
- Chain should now only jump to units that doesn't have locust (This should remove the limitation of where you need to only base all other ability dummies on my dummy as long as your custom dummies have locust).
v2.00b, 23 Jan 2010
- Lightning effect now won't stick to ground.
v2.00a, 23 Jan 2010
- Fix 2 major bugs that make the chain not MUI for chain effect and Stun effect.
- Due to setting the wrong index. Now it has been fixed and should no longer containt any more bugs! Thanks to my sis for testing out this with me [:
v2.00, 22 Jan 2010
- Revamp the chain effect system.
- Remove dummy type. You still have to copy the dummy to your map though.
- Remove finger of death limitations. Now you can choose your chain effect freely.
- Added a new Chain Effect Trigger.
- This allows the chain to follow the unit if it is moving.
- Polish code.
- Fixed a few bugs in code.
- Added Implementation Details Trigger and tidy up the Example 1-8 Implementations.
- Removed all (SFX) ability as now you can use the QJC_ChainSFX to set your lightning effect.
v1.14, 22 Jan 2010
- Added 2 new abilities chain sheep and chain invisible to show the flexibility of this system and how to play around with stun/slow effect to your advantages.
v1.13a, 22 Jan 2010
- Added a sleep ability in the implementation after Kingz asked me what if he wanted to create a chain sleep. (No additional system code added).
- Fix several bugs.
v1.12, 21 Jan 2010
- Periodic Time change to 0.03seconds. And System Time update + 0.03 from 0.01.
v1.11a, 21 Jan 2010
- Fixed Implementation Example Comment for Chain Effect.
v1.11, 21 Jan 2010
- Initial Release.
======================
Customizable Features
======================
- Damage (Boolean: Only damage enemies nomatter what. If you want to damage ally use health and set ally = true)
- Heal (Boolean: Only heal Allies nomatter what)
- Health (Boolean: Make enemy lose health depending on Amount of Damage Type)
- Mana (Boolean: Make enemy lose mana depending on Amount of Damage Type)
- Gold (Boolean: Make enemy lose gold depending on Amount of Damage Type)
- Leech (Boolean: Only affects Health, Mana, Gold. If true, it will transfer Health/Mana/Gold over to the caster)
- Slow (Boolean: If true, it will slow units depending on slow effect)
- Slow Effect (Ability: The ability of slow effect, BASE ALL SLOW ON HUMAN SORCERESS SLOW!!)
- Stun (Boolean: If true, it will stun units depending on stun effect)
- Stun Effect (Ability: The ability of stun effect, BASE ALL STUN ON STORM BOLT!!)
- AoE (Boolean: If true, it will do AoE damage.)
- AoE Radius (Real: Set the radius of AoE Effect)
- Target Effect (String: Lets you insert your effect path)
- Chain Effect (LightningType: Feel free to choose your lightning effect for the chain)
- Amount of Damage Type (Real: Damage, Heal, Health, Mana, Gold)
- Amount Reduction (Real: Each jump reduce a percentage of amount of damage type)
- Jump Count (Integer: How many units it will jump)
- Jump Radius (Real: The range of how far the chain can jump between units)
- Jump Delay (Real: Supports the chain jump delay seconds. 0.10 is the effect of chain lightning, 0.00 is "ALMOST" instant)
- One Per Unit (Boolean: Chain will only hit the unit once if set to true)
- Priority (Boolean: Hit lowest health 1st)
- Ally (Boolean: Hit Ally if set to true, if enemy is also true, it will hit both)
- Enemy (Boolean: Hit Enemy if set to true, if elly is also true, it will hit both)
- Target Unit (Unit: Target Unit, set to No unit if no target or have a target point)
- Point (Point: Target Point, if has a target unit or no target disable this)
- No Target (Boolean: If true, disable point and set unit to no unit)
- Attack (Attack Type: Customize your own attack type)
- Damage Type (Damage Type: Customize your own damage type)
======================
Rules
======================
They are some rules applied to use this system. Is more of a technical limitation.
I will talk more about this after letting you know how to use.
1. Do not touch anything in Chain Create, Chain Jump and Chain Effect Trigger. Those are the system.
2. For implementation examples. Please look at the 8 examples of how flexible you can change the chain to what you want.
3. This system needs you to know the usage of Unit Editor and Ability/Buff Editor.
4. QJC_VarName, This is the only variables you can set.
5. QJCS_VarName are for system variables. So don't even touch it unless you know what you are doing.
======================
How to Use?
======================
If your map is a New Map without any triggers:
1. Open JeffQ's Basic Chain System map.
2. Open Trigger Editor.
3. File > Export Triggers.
4. Open your map.
5. Open Trigger Editor.
6. File > Import Triggers.
7. Remember to copy the Dummy over too.
If your map has existing triggers:
1. Open JeffQ's Basic Chain System map.
2. Copy JeffQ's Chain System folder by right-clicking it and select Copy.
3. Open your map.
4. File > Preference > Check "Automatically create unknown variables while pasting trigger data".
5. Open Object Editor. Create a Dummy base on anything, name it Dummy and give it locust and remove its model. Or just copy the dummy from my map.
6. Open Trigger Editor.
7. Right click on the Map Name, or any other trigger/category/comments, and select Paste.
8. Create a variable by pressing CTRL+B and name it QJCS_ChainZ of type Real, array size of 1.
9. Go to "Chain Create" Trigger, find any Disabled Actions, enable it by right clicking and check Enable.
10.Go to "Chain Jump" Trigger, find any Disabled Actions, enable it by right clicking and check Enable.
11.Go to "Chain effect" Trigger, find any Disabled Actions, enable it by right clicking and check Enable.
======================
Vars you need to set
======================
QJC_Caster : Triggering Unit
- Your caster.
QJC_TargetUnit : Target unit of ability being cast
- Set this to No unit if your spell is target point or instant cast.
QJC_TargetPoint : Target point of ability being cast
- Disable this if you have a target unit or instant cast.
QJC_NoTarget : True/False
- Set this to true if your spell is instant cast.
- Remember to disable QJC_TargetPoint and set QJC_TargetUnit to No Unit.
QJC_Priority : True/False
- If true, it will find the lowest health unit in range first.
QJC_OnePerUnit : True/False
- If true, it will only hit the target once.
QJC_Damage : True/False
- If true, this chain will do damage to enemy depending on QJC_Amount.
QJC_Heal : True/False
- If true, this chain will heal ally depending on QJC_Amount.
QJC_Health : True/False
- If true, it will make enemy lose health.
- If leech is on, it will transfer health over to the caster.
QJC_Mana : True/False
- If true, it will make enemy lose mana.
- If leech is on, it will transfer mana over to the caster.
QJC_Gold : True/False
- If true, it will make enemy lose gold.
- If leech is on, it will transfer gold over to the caster.
QJC_Leech : True/False
- If true, it will apply leeching effect to Health/Mana/Gold type.
QJC_Ally : True/False
- If true, it will hit ally.
- If enemy is also true, it will hit both.
QJC_Enemy : True/False
- If true, it will hit enemy.
- If ally is also true, it will hit both.
QJC_Amount : Real
- The amount of damage type you want this chain to do.
- Eg: QJCGold = true, QJC_Amount = 100, it will make enemy lose 100gold.
QJC_ChainSFX : Lightning Type
- Feel free to choose the lightning type for your chain.
QJC_TargetSFX : String
- Lets you set the special effect for unit when hit by chain.
QJC_AttackType : Attack Type
- Nothing much to say about this.
QJC_DamageType : Damage Type
- Nothing much to say about this.
QJC_AmountReduce: Real
- This is base on percentage.
- If it is 0.00, each chain jump won't reduce QJC_Amount
- If it is 0.10, each chain jump will decreament QJC_Amount by 10%.
- Least is 0.00, Max is 1.00.
QJC_JumpCount : Integer
- Set the amount of jumps for the chain.
QJC_JumpDelayTime: Real
- This is base on seconds.
- Least is 0.00, Max is 1.00
- Set to 0.10 to get the effect of Blizzard Chain Lightning
QJC_JumpRadius : Real
- How far can the chain jump between points.
QJC_Slow : Boolean
- Set to true to slow enemies.
- You have to set QJC_SlowEffect if you want this to work.
QJC_SlowEffect : Ability
- Disable this if Slow Effect is False.
- Slow effect must base on HUMAN SLOW. NO BUTS!
- For example, go to "Ability Editor > Custom Abilities > Neutral Hostile > Units".
- Slow effect will have a (Slow) behind the name.
QJC_Stun : Boolean
- Set to true to stun enemies.
- You have to set QJC_StunEffect if you want this to work.
QJC_StunEffect : Ability
- Disable this if stun effect is false.
- Stun effect must base on STORM BOLT. NO BUTS!
- For example, go to "Ability Editor > Custom Abilities > Neutral Hostile > Units".
- Stun effect will have a (Stun) behind the name)
QJC_AoE : Boolean
- Set to true to do AoE.
- You have to set QJC_AoERadius to make this work. If not the radius will be 0.00.
QJC_AoERadius : Real
- The AoE range you want.
Trigger - Run Chain Create <gen> (checking conditions)
- This must always be included in the trigger of your spell. If not the system won't run.
- Must check conditions.
======================
Limitations
======================
Q: Why i need to base Chain Effect on Finger of Death?
A: I order the dummy unit to cast fingerofdeath order command. And also finger of death let's you do chain effects while channel can't for some reason.
Q: Why i need to base Slow on Human Sorceress Slow?
A: I order the dummy unit to cast Human Sorceress - Slow when i do this. If you base it on other spells, it just won't work.
Q: Why i need to base Stun on Storm Bolt?
A: I order the dummy unit to cast Human Mountain King - Storm Bolt.
Q: Why must dummy be invulnerable and not Locust? And why must it have no model?
A: Because i order the dummy to finger of death the next dummy. If it is locust, it can't be finger of death for the chain effect. No model makes it unselectable on map and won't display health if you hold down ALT key.
Q: Why not ask the dummy to chain the target? Is so much simpler.
A: No. After 3 days of testing. If the target dies the dummy won't be fast enough to cast the chain, and thus, no chain effect.
Q: So where did you hide that dummy? Where can i find it to copy it to my map?
A: It's at the Object Editor > Unit > Custom Units > Night Elf > Melee > Units. There you can find Dummy. Say hi.
======================
Flexibility
======================
1. If you fully know how to use this system. It is quite flexible as you can set the Slow and Stun effect by changing the buffs of the Abilities.
2. Alot of things stack except for a few limitations. You can set all to true and see what happens [:
3. You can target point, target unit or No Target!
======================
Bug Reports & Feedback
======================
Please send an email to [email protected] if you find a bug. Or post it on the comment at Hive Work Shop.
======================
Credits
======================
Thanks to the below who shed some light on me about indexing and leaks.
- Kingz
- YourNameHere
- baassee
- Adiktuz
- Maker
- TitanHex
- D4RK_G4ND4LF
- And other people if i miss out.
Special Thanks to Kingz who show me his simple lightning system. I learned alot from it and after understanding i made 1 my own to fit my system.
***Enjoy this system [:
// ---------------------------------------------------------------- //
// Passive Cooldown System [GUI Friendly] v1.04 //
// by Flux //
// http://www.hiveworkshop.com/forums/members/flux/ //
// ---------------------------------------------------------------- //
// //
// This system allows you to make any unit's ability goes into cooldown via trigger //
// Though written in Jass, it has GUI support and easy to use for GUI users //
// Even if the name shows "Passive Cooldown", it can be applied on Active Abilities as well //
// (as show in Demo 3) but this system is mostly intended for Passive Abilities. //
// //
// HOW TO IMPORT: //
// 1. Copy the PCD_IndicatorStart and PCD_ValidTargetCheck Ability to your map //
// 2. Copy the PCD_DummyCaster Unit to your map //
// 3. Configure the PCD_DummyCasterId, PCD_IndicatorStartId, PCD_ValidTargetCheckId //
// and PCD_VTCBaseOrderId in PCD System Configuration Trigger. //
// 4. Copy PCD Variable Creator to your map to automatically create the system's variables. //
// Make sure you check the "Automatically create unknown variables while pasting trigger //
// data" in File->Preferences of World Editor. After the variables are created, you can //
// then delete the 'PCD Variable Creator' trigger. //
// //
// //
// HOW TO USE: //
// 1. Set the PCD_Unit variable. This refers to the unit that will have its ability //
// goes into cooldown via trigger. //
// 2. Set the PCD_Ability variable. This refers to the ability that will go into cooldown. //
// 3. Set the PCD_DummyAbility variable. This refers to the ability based on Spell Shield //
// that you have created. It must have the same tooltip, manacost and icon. //
// 4. Set the PCD_Time variable. This refers how long the PCD_Ability will be replaced by //
// the PCD_DummyAbility. It should match the 'Stats - Cooldown' of the PCD_DummyAbility. //
// 5. Set the PCD_Manacost variable. This is the manacost of the PCD_Ability which should //
// match the manacost of the PCD_DummyAbility 'Stats - Manacost' if you don't want //
// the unit to lose mana when you trigger it's cooldown. //
// 6. Execute by "Trigger - Run Trigger Cooldown System <gen> (checking conditions)" //
// //
// //
// Notes: //
// - When triggering the cooldown of an active ability, it will reset the original //
// ability's cooldown. Example: Original Ability's is on cooldown for 20 seconds but //
// the triggered cooldown only last 5 seconds, when that 5 seconds is finished, //
// the original ability is now ready to be use again. //
// - Can only trigger Unit ability so far, so to trigger a Hero's ability, a dummy hero //
// ability must be used and when the dummy ability is learned, add the real ability. //
// (As shown in Map Demo 3) //
// //
// Works on: //
// - Invulnerable, Spell Immune, Structures, Ancient, //
// Mechanical, Invisible (but removes it) //
// Does not work on: //
// - Hidden, Cycloned //
// //
// CREDITS: //
// Xonok - for the Spell Block trick to simulate cooldown //
// Wietlol - for finding bugs and suggesting solutions to it. //
//-------------------------------------------------------------------------------------------------//
//-------------------------------------- SYSTEM CORE ----------------------------------------------//
//-------------------------------------------------------------------------------------------------//
function Trig_Passive_Cooldown_System_TimerExpires takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer id = GetHandleId(t)
local unit u = LoadUnitHandle(udg_PCD_Hashtable, id, 0)
local integer origAbil = LoadInteger(udg_PCD_Hashtable, id, 0)
local integer fakeAbil = LoadInteger(udg_PCD_Hashtable, id, 1)
local integer lvl = GetUnitAbilityLevel(u, fakeAbil)
call UnitAddAbility(u, origAbil)
if lvl > 1 then
call SetUnitAbilityLevel(u, origAbil, lvl)
endif
call UnitRemoveAbility(u, fakeAbil)
//Destroy the timer reference data
call FlushChildHashtable(udg_PCD_Hashtable, id)
//Destroy the unit reference data
call FlushChildHashtable(udg_PCD_Hashtable, GetHandleId(u))
call DestroyTimer(t)
set t = null
set u = null
endfunction
function Trig_Passive_Cooldown_System_Execute takes nothing returns boolean
local timer t
local integer id
local integer unitId
local integer lvl
set lvl = GetUnitAbilityLevel(udg_PCD_Unit, udg_PCD_Ability)
call SetUnitX(udg_PCD_DummyCaster, GetUnitX(udg_PCD_Unit))
call SetUnitY(udg_PCD_DummyCaster, GetUnitY(udg_PCD_Unit))
//For checking if it is castable
call SetPlayerAlliance(Player(14), GetOwningPlayer(udg_PCD_Unit), ALLIANCE_PASSIVE, true)
if IssueTargetOrder(udg_PCD_DummyCaster, udg_PCD_VTCBaseOrderId, udg_PCD_Unit) then
if lvl > 0 then
call UnitRemoveAbility(udg_PCD_Unit, udg_PCD_Ability)
else
set lvl = GetUnitAbilityLevel(udg_PCD_Unit, udg_PCD_DummyAbility)
call UnitRemoveAbility(udg_PCD_Unit, udg_PCD_DummyAbility)
endif
//Add the fake ability
call UnitAddAbility(udg_PCD_Unit, udg_PCD_DummyAbility)
call SetUnitAbilityLevel(udg_PCD_Unit, udg_PCD_DummyAbility, lvl)
call IssueTargetOrderById(udg_PCD_DummyCaster, 852075, udg_PCD_Unit)
set unitId = GetHandleId(udg_PCD_Unit)
//[unitId][5] is for timers
//If there is already a timer, just reset it
if HaveSavedHandle(udg_PCD_Hashtable, unitId, udg_PCD_Ability) then
call TimerStart(LoadTimerHandle(udg_PCD_Hashtable, unitId, udg_PCD_Ability), udg_PCD_Time, false, function Trig_Passive_Cooldown_System_TimerExpires)
else
set t = CreateTimer()
set id = GetHandleId(t)
//Save the timer in reference to the unit
call SaveTimerHandle(udg_PCD_Hashtable, unitId, udg_PCD_Ability, t)
call TimerStart(t, udg_PCD_Time, false, function Trig_Passive_Cooldown_System_TimerExpires)
set t = null
//Save the unit
call SaveUnitHandle(udg_PCD_Hashtable, id, 0, udg_PCD_Unit)
//Save the original ability replaced
call SaveInteger(udg_PCD_Hashtable, id, 0, udg_PCD_Ability)
//Save the fake ability
call SaveInteger(udg_PCD_Hashtable, id, 1, udg_PCD_DummyAbility)
endif
if udg_PCD_Manacost > 0 then
call SetUnitState(udg_PCD_Unit, UNIT_STATE_MANA, GetUnitState(udg_PCD_Unit, UNIT_STATE_MANA) + udg_PCD_Manacost)
endif
endif
call SetPlayerAlliance(Player(14), GetOwningPlayer(udg_PCD_Unit), ALLIANCE_PASSIVE, false)
return false
endfunction
function Trig_Passive_Cooldown_System_LastInit takes nothing returns nothing
set udg_PCD_DummyCaster = CreateUnit(Player(14), udg_PCD_DummyCasterId, 0, 0, 0)
call SetHeroLevel(udg_PCD_DummyCaster, 6, false)
call UnitAddAbility(udg_PCD_DummyCaster, udg_PCD_IndicatorStartId)
call SelectHeroSkill(udg_PCD_DummyCaster, udg_PCD_IndicatorStartId)
call UnitAddAbility(udg_PCD_DummyCaster, udg_PCD_ValidTargetCheckId)
call DestroyTimer(GetExpiredTimer())
endfunction
//===========================================================================
function InitTrig_Passive_Cooldown_System takes nothing returns nothing
set gg_trg_Passive_Cooldown_System = CreateTrigger()
set udg_PCD_Hashtable = InitHashtable()
call TimerStart(CreateTimer(), 0, false, function Trig_Passive_Cooldown_System_LastInit)
call TriggerAddCondition(gg_trg_Passive_Cooldown_System, Condition(function Trig_Passive_Cooldown_System_Execute))
endfunction
//===========================================================================
function UnitEventDestroyGroup takes integer i returns nothing
if udg_CargoTransportGroup[i] != null then
call DestroyGroup(udg_CargoTransportGroup[i])
set udg_CargoTransportGroup[i] = null
endif
endfunction
function UnitEventCheckAfter takes nothing returns nothing
local integer i = 0
loop
set i = udg_CheckDeathList[i]
exitwhen i == 0
if udg_IsUnitNew[i] then
//The unit was just created.
set udg_IsUnitNew[i] = false
elseif udg_IsUnitTransforming[i] then
//Added 21 July 2017 to fix the issue re-adding this ability in the same instant
set udg_UDex = i
set udg_UnitTypeEvent = 0.00
set udg_UnitTypeEvent = 1.00
set udg_UnitTypeOf[i] = GetUnitTypeId(udg_UDexUnits[i]) //Set this afterward to give the user extra reference
set udg_IsUnitTransforming[i] = false
call UnitAddAbility(udg_UDexUnits[i], udg_DetectTransformAbility)
elseif udg_IsUnitAlive[i] then
//The unit has started reincarnating.
set udg_IsUnitReincarnating[i] = true
set udg_IsUnitAlive[i] = false
set udg_UDex = i
set udg_DeathEvent = 0.50
set udg_DeathEvent = 0.00
endif
set udg_CheckDeathInList[i] = false
endloop
//Empty the list
set udg_CheckDeathList[0] = 0
endfunction
function UnitEventCheckAfterProxy takes integer i returns nothing
if udg_CheckDeathList[0] == 0 then
call TimerStart(udg_CheckDeathTimer, 0.00, false, function UnitEventCheckAfter)
endif
if not udg_CheckDeathInList[i] then
set udg_CheckDeathList[i] = udg_CheckDeathList[0]
set udg_CheckDeathList[0] = i
set udg_CheckDeathInList[i] = true
endif
endfunction
function UnitEventOnUnload takes nothing returns nothing
local integer i = udg_UDex
call GroupRemoveUnit(udg_CargoTransportGroup[GetUnitUserData(udg_CargoTransportUnit[i])], udg_UDexUnits[i])
set udg_IsUnitBeingUnloaded[i] = true
set udg_CargoEvent = 0.00
set udg_CargoEvent = 2.00
set udg_CargoEvent = 0.00
set udg_IsUnitBeingUnloaded[i] = false
if not IsUnitLoaded(udg_UDexUnits[i]) or IsUnitType(udg_CargoTransportUnit[i], UNIT_TYPE_DEAD) or GetUnitTypeId(udg_CargoTransportUnit[i]) == 0 then
set udg_CargoTransportUnit[i] = null
endif
endfunction
function UnitEventOnDeath takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_UDex != 0 then
set udg_KillerOfUnit[udg_UDex] = GetKillingUnit() //Added 29 May 2017 for GIMLI_2
set udg_IsUnitAlive[udg_UDex] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
set udg_KillerOfUnit[udg_UDex] = null
if udg_CargoTransportUnit[udg_UDex] != null then
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnOrder takes nothing returns boolean
local integer pdex = udg_UDex
local unit u = GetFilterUnit()
local integer i = GetUnitUserData(u)
if i > 0 then
set udg_UDex = i
if GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
if not udg_IsUnitRemoved[i] then
set udg_IsUnitRemoved[i] = true
set udg_IsUnitAlive[i] = false
set udg_SummonerOfUnit[i] = null
//For backwards-compatibility:
set udg_DeathEvent = 0.00
set udg_DeathEvent = 3.00
set udg_DeathEvent = 0.00
//Fire deindex event for UDex:
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 2.00
set udg_UnitIndexEvent = 0.00
set udg_UDexNext[udg_UDexPrev[i]] = udg_UDexNext[i]
set udg_UDexPrev[udg_UDexNext[i]] = udg_UDexPrev[i]
// Recycle the index for later use
set udg_UDexUnits[i] = null
set udg_UDexPrev[i] = udg_UDexLastRecycled
set udg_UDexLastRecycled = i
call UnitEventDestroyGroup(i)
endif
elseif not udg_IsUnitAlive[i] then
if not IsUnitType(u, UNIT_TYPE_DEAD) then
set udg_IsUnitAlive[i] = true
set udg_DeathEvent = 0.00
set udg_DeathEvent = 2.00
set udg_DeathEvent = 0.00
set udg_IsUnitReincarnating[i] = false
endif
elseif IsUnitType(u, UNIT_TYPE_DEAD) then
if udg_IsUnitNew[i] then
//This unit was created as a corpse.
set udg_IsUnitAlive[i] = false
set udg_DeathEvent = 0.00
set udg_DeathEvent = 1.00
set udg_DeathEvent = 0.00
elseif udg_CargoTransportUnit[i] == null or not IsUnitType(u, UNIT_TYPE_HERO) then
//The unit may have just started reincarnating.
call UnitEventCheckAfterProxy(i)
endif
elseif GetUnitAbilityLevel(u, udg_DetectTransformAbility) == 0 and not udg_IsUnitTransforming[i] then
set udg_IsUnitTransforming[i] = true
call UnitEventCheckAfterProxy(i) //This block has been updated on 21 July 2017
endif
if udg_CargoTransportUnit[i] != null and not udg_IsUnitBeingUnloaded[i] and not IsUnitLoaded(u) or IsUnitType(u, UNIT_TYPE_DEAD) then
call UnitEventOnUnload()
endif
set udg_UDex = pdex
endif
set u = null
return false
endfunction
function UnitEventOnSummon takes nothing returns boolean
local integer pdex = udg_UDex
set udg_UDex = GetUnitUserData(GetTriggerUnit())
if udg_IsUnitNew[udg_UDex] then
set udg_SummonerOfUnit[udg_UDex] = GetSummoningUnit()
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 0.50
set udg_UnitIndexEvent = 0.00
endif
set udg_UDex = pdex
return false
endfunction
function UnitEventOnLoad takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = GetUnitUserData(GetTriggerUnit())
local integer index
if i != 0 then
set udg_UDex = i
if udg_CargoTransportUnit[i] != null then
call UnitEventOnUnload()
endif
//Loaded corpses do not issue an order when unloaded, therefore must
//use the enter-region event method taken from Jesus4Lyf's Transport.
if not udg_IsUnitAlive[i] then
call SetUnitX(udg_UDexUnits[i], udg_WorldMaxX)
call SetUnitY(udg_UDexUnits[i], udg_WorldMaxY)
endif
set udg_CargoTransportUnit[i] = GetTransportUnit()
set index = GetUnitUserData(udg_CargoTransportUnit[i])
if udg_CargoTransportGroup[index] == null then
set udg_CargoTransportGroup[index] = CreateGroup()
endif
call GroupAddUnit(udg_CargoTransportGroup[index], udg_UDexUnits[i])
set udg_CargoEvent = 0.00
set udg_CargoEvent = 1.00
set udg_CargoEvent = 0.00
set udg_UDex = pdex
endif
return false
endfunction
function UnitEventEnter takes nothing returns boolean
local integer pdex = udg_UDex
local integer i = udg_UDexLastRecycled
local unit u = GetFilterUnit()
if udg_UnitIndexerEnabled and GetUnitAbilityLevel(u, udg_DetectRemoveAbility) == 0 then
//Generate a unique integer index for this unit
if i == 0 then
set i = udg_UDexMax + 1
set udg_UDexMax = i
else
set udg_UDexLastRecycled = udg_UDexPrev[i]
endif
//Link index to unit, unit to index
set udg_UDexUnits[i] = u
call SetUnitUserData(u, i)
//For backwards-compatibility, add the unit to a linked list
set udg_UDexNext[i] = udg_UDexNext[0]
set udg_UDexPrev[udg_UDexNext[0]] = i
set udg_UDexNext[0] = i
set udg_UDexPrev[i] = 0
set udg_CheckDeathInList[i] = false
call UnitAddAbility(u, udg_DetectRemoveAbility)
call UnitMakeAbilityPermanent(u, true, udg_DetectRemoveAbility)
call UnitAddAbility(u, udg_DetectTransformAbility)
set udg_UnitTypeOf[i] = GetUnitTypeId(u)
set udg_IsUnitNew[i] = true
set udg_IsUnitAlive[i] = true
set udg_IsUnitRemoved[i] = false
set udg_IsUnitReincarnating[i] = false
set udg_IsUnitPreplaced[i] = udg_IsUnitPreplaced[0] //Added 29 May 2017 for Spellbound
call UnitEventCheckAfterProxy(i)
//Fire index event for UDex
set udg_UDex = i
set udg_UnitIndexEvent = 0.00
set udg_UnitIndexEvent = 1.00
set udg_UnitIndexEvent = 0.00
else
set udg_UDex = GetUnitUserData(u)
if udg_CargoTransportUnit[udg_UDex] != null and not IsUnitLoaded(u) then
//The unit was dead, but has re-entered the map.
call UnitEventOnUnload()
endif
endif
set udg_UDex = pdex
set u = null
return false
endfunction
//===========================================================================
function UnitEventInit takes nothing returns nothing
local integer i = bj_MAX_PLAYER_SLOTS //update to make it work with 1.29
local player p
local trigger t = CreateTrigger()
local trigger load = CreateTrigger()
local trigger death = CreateTrigger()
local trigger summon = CreateTrigger()
local rect r = GetWorldBounds()
local region re = CreateRegion()
local boolexpr enterB = Filter(function UnitEventEnter)
local boolexpr orderB = Filter(function UnitEventOnOrder)
set udg_WorldMaxX = GetRectMaxX(r)
set udg_WorldMaxY = GetRectMaxY(r)
call RegionAddRect(re, r)
call RemoveRect(r)
call UnitEventDestroyGroup(0)
call UnitEventDestroyGroup(1)
set udg_CheckDeathList[0] = 0
set udg_UnitIndexerEnabled = true
call TriggerRegisterEnterRegion(CreateTrigger(), re, enterB)
call TriggerAddCondition(load, Filter(function UnitEventOnLoad))
call TriggerAddCondition(death, Filter(function UnitEventOnDeath))
call TriggerAddCondition(summon, Filter(function UnitEventOnSummon))
loop
set i = i - 1
set p = Player(i)
call SetPlayerAbilityAvailable(p, udg_DetectRemoveAbility, false)
call SetPlayerAbilityAvailable(p, udg_DetectTransformAbility, false)
call TriggerRegisterPlayerUnitEvent(summon, p, EVENT_PLAYER_UNIT_SUMMON, null)
call TriggerRegisterPlayerUnitEvent(t, p, EVENT_PLAYER_UNIT_ISSUED_ORDER, orderB)
call TriggerRegisterPlayerUnitEvent(death, p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerRegisterPlayerUnitEvent(load, p, EVENT_PLAYER_UNIT_LOADED, null)
call GroupEnumUnitsOfPlayer(bj_lastCreatedGroup, p, enterB)
exitwhen i == 0
endloop
set summon = null
set death = null
set load = null
set re = null
set enterB = null
set orderB = null
set p = null
set r = null
set t = null
endfunction
function InitTrig_Unit_Event takes nothing returns nothing
endfunction
// GUI-Friendly Damage Detection -- v1.2.1 -- by Weep
// http:// www.thehelper.net/forums/showthread.php?t=137957
//
// Requires: only this trigger and its variables.
//
// -- What? --
// This snippet provides a leak-free, GUI-friendly implementation of an "any unit takes
// damage" event. It requires no JASS knowledge to use.
//
// It uses the Game - Value Of Real Variable event as its method of activating other
// triggers, and passes the event responses through a few globals.
//
// -- Why? --
// The traditional GUI method of setting up a trigger than runs when any unit is damaged
// leaks trigger events. This snippet is easy to implement and removes the need to do
// you own GUI damage detection setup.
//
// -- How To Implement --
// 0. Before you copy triggers that use GDD into a new map, you need to copy over GDD
// with its GDD Variable Creator trigger, or there will be a problem: the variables
// won't be automatically created correctly.
//
// 1. Be sure "Automatically create unknown variables while pasting trigger data" is
// enabled in the World Editor general preferences.
// 2. Copy this trigger category ("GDD") and paste it into your map.
// (Alternately: create the variables listed in the globals block below, create a
// trigger named "GUI Friendly Damage Detection", and paste in this entire text.)
// 3. Create your damage triggers using Game - Value Of Real Variable as the event,
// select GDD_Event as the variable, and leave the rest of the settings to the default
// "becomes Equal to 0.00".
// The event responses are the following variables:
// GDD_Damage is the amount of damage, replacing Event Response - Damage Taken.
// GDD_DamagedUnit is the damaged unit, replacing Event Response - Triggering Unit.
// Triggering Unit can still be used, if you need to use waits.
// Read the -- Notes -- section below for more info.
// GDD_DamageSource is the damaging unit, replacing Event Response - Damage Source.
//
// -- Notes --
// GDD's event response variables are not wait-safe; you can't use them after a wait in
// a trigger. If you need to use waits, Triggering Unit (a.k.a. GetTriggerUnit()) can
// be used in place of GDD_DamageSource. There is no usable wait-safe equivalent to
// Event Damage or Damage Source; you'll need to save the values yourself.
//
// Don't write any values to the variables used as the event responses, or it will mess
// up any other triggers using this snippet for their triggering. Only use their values.
//
// This uses arrays, so can detect damage for a maximum of 8190 units at a time, and
// cleans up data at a rate of 33.33 per second, by default. This should be enough for
// most maps, but if you want to change the rate, change the value returned in the
// GDD_RecycleRate function at the top of the code, below.
//
// By default, GDD will not register units that have Locust at the moment of their
// entering the game, and will not recognize when they take damage (which can only
// happen if the Locust ability is later removed from the unit.) To allow a unit to have
// Locust yet still cause GDD damage events if Locust is removed, you can either design
// the unit to not have Locust by default and add it via triggers after creation, or
// edit the GDD_Filter function at the top of the code, below.
//
// -- Credits --
// Captain Griffin on wc3c.net for the research and concept of GroupRefresh.
//
// Credit in your map not needed, but please include this README.
//
// -- Version History --
// 1.2.1: Minor code cleaning. Added configuration functions. Updated documentation.
// 1.2.0: Made this snippet work properly with recursive damage.
// 1.1.1: Added a check in order to not index units with the Locust ability (dummy units).
// If you wish to check for damage taken by a unit that is unselectable, do not
// give the unit-type Locust in the object editor; instead, add the Locust ability
// 'Aloc' via a trigger after its creation, then remove it.
// 1.1.0: Added a check in case a unit gets moved out of the map and back.
// 1.0.0: First release.
//===================================================================
// Configurables.
function GDD_RecycleRate takes nothing returns real //The rate at which the system checks units to see if they've been removed from the game
return 0.03
endfunction
function GDD_Filter takes unit u returns boolean //The condition a unit has to pass to have it registered for damage detection
return GetUnitAbilityLevel(u, 'Aloc') == 0 //By default, the system ignores Locust units, because they normally can't take damage anyway
endfunction
//===================================================================
// This is just for reference.
// If you use JassHelper, you could uncomment this section instead of creating the variables in the trigger editor.
// globals
// real udg_GDD_Event = 0.
// real udg_GDD_Damage = 0.
// unit udg_GDD_DamagedUnit
// unit udg_GDD_DamageSource
// trigger array udg_GDD__TriggerArray
// integer array udg_GDD__Integers
// unit array udg_GDD__UnitArray
// group udg_GDD__LeftMapGroup = CreateGroup()
// endglobals
//===================================================================
// System code follows. Don't touch!
function GDD_Event takes nothing returns boolean
local unit damagedcache = udg_GDD_DamagedUnit
local unit damagingcache = udg_GDD_DamageSource
local real damagecache = udg_GDD_Damage
set udg_GDD_DamagedUnit = GetTriggerUnit()
set udg_GDD_DamageSource = GetEventDamageSource()
set udg_GDD_Damage = GetEventDamage()
set udg_GDD_Event = 1.
set udg_GDD_Event = 0.
set udg_GDD_DamagedUnit = damagedcache
set udg_GDD_DamageSource = damagingcache
set udg_GDD_Damage = damagecache
set damagedcache = null
set damagingcache = null
return false
endfunction
function GDD_AddDetection takes nothing returns boolean
// if(udg_GDD__Integers[0] > 8190) then
// call BJDebugMsg("GDD: Too many damage events! Decrease number of units present in the map or increase recycle rate.")
// ***Recycle rate is specified in the GDD_RecycleRate function at the top of the code. Smaller is faster.***
// return
// endif
if(IsUnitInGroup(GetFilterUnit(), udg_GDD__LeftMapGroup)) then
call GroupRemoveUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
elseif(GDD_Filter(GetFilterUnit())) then
set udg_GDD__Integers[0] = udg_GDD__Integers[0]+1
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = GetFilterUnit()
set udg_GDD__TriggerArray[udg_GDD__Integers[0]] = CreateTrigger()
call TriggerRegisterUnitEvent(udg_GDD__TriggerArray[udg_GDD__Integers[0]], udg_GDD__UnitArray[udg_GDD__Integers[0]], EVENT_UNIT_DAMAGED)
call TriggerAddCondition(udg_GDD__TriggerArray[udg_GDD__Integers[0]], Condition(function GDD_Event))
endif
return false
endfunction
function GDD_PreplacedDetection takes nothing returns nothing
local group g = CreateGroup()
local integer i = 0
loop
call GroupEnumUnitsOfPlayer(g, Player(i), Condition(function GDD_AddDetection))
set i = i+1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call DestroyGroup(g)
set g = null
endfunction
function GDD_GroupRefresh takes nothing returns nothing
// Based on GroupRefresh by Captain Griffen on wc3c.net
if (bj_slotControlUsed[5063] == true) then
call GroupClear(udg_GDD__LeftMapGroup)
set bj_slotControlUsed[5063] = false
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetEnumUnit())
endfunction
function GDD_Recycle takes nothing returns nothing
if(udg_GDD__Integers[0] <= 0) then
return
elseif(udg_GDD__Integers[1] <= 0) then
set udg_GDD__Integers[1] = udg_GDD__Integers[0]
endif
if(GetUnitTypeId(udg_GDD__UnitArray[udg_GDD__Integers[1]]) == 0) then
call DestroyTrigger(udg_GDD__TriggerArray[udg_GDD__Integers[1]])
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = null
set udg_GDD__TriggerArray[udg_GDD__Integers[1]] = udg_GDD__TriggerArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[1]] = udg_GDD__UnitArray[udg_GDD__Integers[0]]
set udg_GDD__UnitArray[udg_GDD__Integers[0]] = null
set udg_GDD__Integers[0] = udg_GDD__Integers[0]-1
endif
set udg_GDD__Integers[1] = udg_GDD__Integers[1]-1
endfunction
function GDD_LeaveMap takes nothing returns boolean
local boolean cached = bj_slotControlUsed[5063]
if(udg_GDD__Integers[2] < 64) then
set udg_GDD__Integers[2] = udg_GDD__Integers[2]+1
else
set bj_slotControlUsed[5063] = true
call ForGroup(udg_GDD__LeftMapGroup, function GDD_GroupRefresh)
set udg_GDD__Integers[2] = 0
endif
call GroupAddUnit(udg_GDD__LeftMapGroup, GetFilterUnit())
set bj_slotControlUsed[5063] = cached
return false
endfunction
// ===========================================================================
function InitTrig_GUI_Friendly_Damage_Detection takes nothing returns nothing
local region r = CreateRegion()
call RegionAddRect(r, GetWorldBounds())
call TriggerRegisterEnterRegion(CreateTrigger(), r, Condition(function GDD_AddDetection))
call TriggerRegisterLeaveRegion(CreateTrigger(), r, Condition(function GDD_LeaveMap))
call GDD_PreplacedDetection()
call TimerStart(CreateTimer(), GDD_RecycleRate(), true, function GDD_Recycle)
set r = null
endfunction