Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AOEDamageEvent | real | No | |
AOEDamageSource | unit | No | |
ARMOR_TYPE_ETHEREAL | integer | No | |
ARMOR_TYPE_FLESH | integer | No | |
ARMOR_TYPE_METAL | integer | No | |
ARMOR_TYPE_NONE | integer | No | |
ARMOR_TYPE_STONE | integer | No | |
ARMOR_TYPE_WOOD | integer | No | |
ArmorDamageEvent | real | No | |
ArmorTypeDebugStr | string | Yes | |
ATTACK_TYPE_CHAOS | integer | No | |
ATTACK_TYPE_HERO | integer | No | |
ATTACK_TYPE_MAGIC | integer | No | |
ATTACK_TYPE_NORMAL | integer | No | |
ATTACK_TYPE_PIERCE | integer | No | |
ATTACK_TYPE_SIEGE | integer | No | |
ATTACK_TYPE_SPELLS | integer | No | |
AttackTypeDebugStr | string | Yes | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
DAMAGE_TYPE_ACID | integer | No | |
DAMAGE_TYPE_COLD | integer | No | |
DAMAGE_TYPE_DEATH | integer | No | |
DAMAGE_TYPE_DEFENSIVE | integer | No | |
DAMAGE_TYPE_DEMOLITION | integer | No | |
DAMAGE_TYPE_DISEASE | integer | No | |
DAMAGE_TYPE_DIVINE | integer | No | |
DAMAGE_TYPE_ENHANCED | integer | No | |
DAMAGE_TYPE_FIRE | integer | No | |
DAMAGE_TYPE_FORCE | integer | No | |
DAMAGE_TYPE_LIGHTNING | integer | No | |
DAMAGE_TYPE_MAGIC | integer | No | |
DAMAGE_TYPE_MIND | integer | No | |
DAMAGE_TYPE_NORMAL | integer | No | |
DAMAGE_TYPE_PLANT | integer | No | |
DAMAGE_TYPE_POISON | integer | No | |
DAMAGE_TYPE_SHADOW_STRIKE | integer | No | |
DAMAGE_TYPE_SLOW_POISON | integer | No | |
DAMAGE_TYPE_SONIC | integer | No | |
DAMAGE_TYPE_SPIRIT_LINK | integer | No | |
DAMAGE_TYPE_UNIVERSAL | integer | No | |
DAMAGE_TYPE_UNKNOWN | integer | No | |
DamageEvent | real | No | |
DamageEventAmount | real | No | |
DamageEventAOE | integer | No | |
DamageEventAOEGroup | group | No | |
DamageEventArmorPierced | real | No | |
DamageEventArmorT | integer | No | |
DamageEventAttackT | integer | No | |
DamageEventDamageT | integer | No | |
DamageEventDefenseT | integer | No | |
DamageEventLevel | integer | No | |
DamageEventOverride | boolean | No | |
DamageEventPrevAmt | real | No | |
DamageEventSource | unit | No | |
DamageEventTarget | unit | No | |
DamageEventType | integer | No | |
DamageEventWeaponT | integer | No | |
DamageFilterAttackT | integer | No | |
DamageFilterDamageT | integer | No | |
DamageFilterFailChance | real | No | |
DamageFilterMinAmount | real | No | |
DamageFilterRunChance | real | No | |
DamageFilterSource | unit | No | |
DamageFilterSourceA | abilcode | No | |
DamageFilterSourceB | buffcode | No | |
DamageFilterSourceC | integer | No | |
DamageFilterSourceI | itemcode | No | |
DamageFilterSourceT | unitcode | No | |
DamageFilterTarget | unit | No | |
DamageFilterTargetA | abilcode | No | |
DamageFilterTargetB | buffcode | No | |
DamageFilterTargetC | integer | No | |
DamageFilterTargetI | itemcode | No | |
DamageFilterTargetT | unitcode | No | |
DamageFilterType | integer | No | |
DamageModifierEvent | real | No | |
DamageScalingUser | real | No | |
DamageScalingWC3 | real | No | |
DamageTypeBlocked | integer | No | |
DamageTypeCode | integer | No | |
DamageTypeCriticalStrike | integer | No | |
DamageTypeDebugStr | string | Yes | |
DamageTypeExplosive | integer | No | |
DamageTypeHeal | integer | No | |
DamageTypePure | integer | No | |
DamageTypePureExplosive | integer | No | |
DamageTypeReduced | integer | No | |
DEFENSE_TYPE_DIVINE | integer | No | |
DEFENSE_TYPE_FORTIFIED | integer | No | |
DEFENSE_TYPE_HEAVY | integer | No | |
DEFENSE_TYPE_HERO | integer | No | |
DEFENSE_TYPE_LIGHT | integer | No | |
DEFENSE_TYPE_MEDIUM | integer | No | |
DEFENSE_TYPE_NORMAL | integer | No | |
DEFENSE_TYPE_UNARMORED | integer | No | |
DefenseTypeDebugStr | string | Yes | |
EnhancedDamageTarget | unit | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
OnDamageEvent | real | No | |
PreDamageEvent | real | No | |
RemoveDamageEvent | boolean | No | |
SourceDamageEvent | real | No | |
UNIT_CLASS_ANCIENT | integer | No | |
UNIT_CLASS_ATTACKS_FLYING | integer | No | |
UNIT_CLASS_ATTACKS_GROUND | integer | No | |
UNIT_CLASS_DEAD | integer | No | |
UNIT_CLASS_ETHEREAL | integer | No | |
UNIT_CLASS_FLYING | integer | No | |
UNIT_CLASS_GIANT | integer | No | |
UNIT_CLASS_GROUND | integer | No | |
UNIT_CLASS_HERO | integer | No | |
UNIT_CLASS_MAGIC_IMMUNE | integer | No | |
UNIT_CLASS_MECHANICAL | integer | No | |
UNIT_CLASS_MELEE | integer | No | |
UNIT_CLASS_PEON | integer | No | |
UNIT_CLASS_PLAGUED | integer | No | |
UNIT_CLASS_POISONED | integer | No | |
UNIT_CLASS_POLYMORPHED | integer | No | |
UNIT_CLASS_RANGED | integer | No | |
UNIT_CLASS_RESISTANT | integer | No | |
UNIT_CLASS_SAPPER | integer | No | |
UNIT_CLASS_SLEEPING | integer | No | |
UNIT_CLASS_SNARED | integer | No | |
UNIT_CLASS_STRUCTURE | integer | No | |
UNIT_CLASS_STUNNED | integer | No | |
UNIT_CLASS_SUMMONED | integer | No | |
UNIT_CLASS_TAUREN | integer | No | |
UNIT_CLASS_TOWNHALL | integer | No | |
UNIT_CLASS_UNDEAD | integer | No | |
WEAPON_TYPE_AM_CHOP | integer | No | |
WEAPON_TYPE_CH_SLICE | integer | No | |
WEAPON_TYPE_CL_SLICE | integer | No | |
WEAPON_TYPE_CM_SLICE | integer | No | |
WEAPON_TYPE_MH_BASH | integer | No | |
WEAPON_TYPE_MH_CHOP | integer | No | |
WEAPON_TYPE_MH_SLICE | integer | No | |
WEAPON_TYPE_MH_STAB | integer | No | |
WEAPON_TYPE_ML_CHOP | integer | No | |
WEAPON_TYPE_ML_SLICE | integer | No | |
WEAPON_TYPE_MM_BASH | integer | No | |
WEAPON_TYPE_MM_CHOP | integer | No | |
WEAPON_TYPE_MM_SLICE | integer | No | |
WEAPON_TYPE_MM_STAB | integer | No | |
WEAPON_TYPE_NONE | integer | No | |
WEAPON_TYPE_RH_BASH | integer | No | |
WEAPON_TYPE_WH_BASH | integer | No | |
WEAPON_TYPE_WH_SLICE | integer | No | |
WEAPON_TYPE_WL_BASH | integer | No | |
WEAPON_TYPE_WL_SLICE | integer | No | |
WEAPON_TYPE_WL_STAB | integer | No | |
WEAPON_TYPE_WM_BASH | integer | No | |
WEAPON_TYPE_WM_SLICE | integer | No | |
WEAPON_TYPE_WM_STAB | integer | No | |
WeaponTypeDebugStr | string | Yes | |
ZeroDamageEvent | real | No |
//===========================================================================
//
// Damage Engine 5.9.0.0 - update requires re-copying the Damage Engine category.
//
/*
Three GUI Damage systems for the community of The Hive,
Seven vJass Damage systems for the JASS-heads on their pedestals high,
Nine competing Damage systems, doomed to die,
One for Bribe on his dark throne
In the Land of the Hive where the Workshop lies.
One Damage Engine to rule them all, One Damage Engine to find them,
One Damage Engine to bring them all and in cross-compatibility unite them.
*/
//! novjass
JASS API (work in progress - I have a lot of documentation to go through):
struct Damage extends array
readonly static unit source //stores udg_DamageEventSource
readonly static unit target //stores udg_DamageEventTarget
static real amount //stores udg_DamageEventAmount
readonly unit sourceUnit //stores udg_DamageEventSource by index
readonly unit targetUnit //stores udg_DamageEventTarget by index
real damage //stores udg_DamageEventAmount by index
readonly real prevAmt //stores udg_DamageEventPrevAmt by index
attacktype attackType //stores udg_DamageEventAttackT by index
damagetype damageType //stores udg_DamageEventDamageT by index
weapontype weaponType //stores udg_DamageEventWeaponT by index
integer userType //stores udg_DamageEventType by index
readonly integer eFilter //replaces the previous eventFilter variable
readonly boolean isAttack //stores udg_IsDamageAttack by index
readonly boolean isCode //stores udg_IsDamageCode by index
readonly boolean isMelee //stores udg_IsDamageMelee by index
readonly boolean isRanged //stores udg_IsDamageRanged by index
readonly boolean isSpell //stores udg_IsDamageSpell by index
real armorPierced //stores udg_DamageEventArmorPierced by index
integer armorType //stores udg_DamageEventArmorT by index
integer defenseType //stores udg_DamageEventDefenseT by index
static boolean operator enabled
- Set to false to disable the damage event triggers/false to reverse that
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
- Same arguments as "UnitDamageTarget" but has the benefit of being performance-friendly during recursive events.
- Will automatically cause the damage to be registered as Code damage.
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
- A simplified version of the above function that autofills in the booleans, attack type and weapon type.
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
- A different variation of the above which autofills the "attack" boolean and sets the damagetype to DAMAGE_TYPE_NORMAL.
struct DamageTrigger extends array
method operator filter= takes integer filter returns nothing
// Apply primary filters such as DamageEngine_FILTER_MELEE/RANGED/SPELL which are based off of limitop handles to enable easier access for GUI folks
// Full filter list:
- global integer DamageEngine_FILTER_ATTACK
- global integer DamageEngine_FILTER_MELEE
- global integer DamageEngine_FILTER_OTHER
- global integer DamageEngine_FILTER_RANGED
- global integer DamageEngine_FILTER_SPELL
- global integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
method configure takes nothing returns nothing
// Apply custom filters after setting any desired udg_DamageFilter variables (for GUI).
// Alternatively, vJass users can set these instead. Just be mindful to set the variable
// "configured" to true after settings these.
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
real damageMin
integer attackType
integer damageType
integer userType
//The string in the aruments below requires the following API:
// "" for standard damage event
// "Modifier(or Mod if you prefer)/After/Lethal/AOE" for the others
static method registerTrigger takes trigger whichTrig, string var, real value returns nothing
static method unregister takes trigger t, string eventName, real value, boolean reset returns boolean
static method getIndex takes trigger t, string eventName, real value returns integer
//If you already have the index of the trigger you want to unregister.
method unregisterByIndex takes boolean reset returns boolean
// Converts a code argument to a trigger, while checking if the same code had already been registered before.
static method operator [] takes code c returns trigger
//The accepted strings here use the same criteria as DamageTrigger.getIndex/registerTrigger/unregister
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns nothing
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns nothing
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns nothing
function RegisterDamageEngine takes code c, string eventName, real value returns nothing
//! endnovjass
//===========================================================================
library DamageEngine
globals
private constant boolean USE_GUI = true //If you don't use any of the GUI events, set to false to slightly improve performance
private constant boolean USE_SCALING = USE_GUI //If you don't need or want to use DamageScalingUser/WC3 then set this to false
private constant boolean USE_EXTRA = true //If you don't use DamageEventLevel or AOEDamageEvent, set this to false
private constant boolean USE_ARMOR_MOD = true //If you do not modify nor detect armor/defense, set this to false
private constant boolean USE_MELEE_RANGE= true //If you do not detect melee nor ranged damage, set this to false
private constant boolean USE_LETHAL = true //If you do not use LethalDamageEvent nor negative damage (explosive) types, set this to false
private constant integer LIMBO = 16 //When manually-enabled recursion is enabled via DamageEngine_recurion, the engine will never go deeper than LIMBO.
public constant integer TYPE_CODE = 1 //Must be the same as udg_DamageTypeCode, or 0 if you prefer to disable the automatic flag.
public constant integer TYPE_PURE = 2 //Must be the same as udg_DamageTypePure
private constant real DEATH_VAL = 0.405 //In case Blizz ever changes this, it'll be a quick fix here.
private timer alarm = null
private boolean alarmSet = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean canKick = true
private boolean totem = false
private boolean array attacksImmune
private boolean array damagesImmune
//Made global in order to use enable/disable behavior.
private trigger t1 = null
private trigger t2 = null
private trigger t3 = null //Catches, stores recursive events
//These variables coincide with Blizzard's "limitop" type definitions so as to enable users (GUI in particular) with some nice performance perks.
public constant integer FILTER_ATTACK = 0 //LESS_THAN
public constant integer FILTER_MELEE = 1 //LESS_THAN_OR_EQUAL
public constant integer FILTER_OTHER = 2 //EQUAL
public constant integer FILTER_RANGED = 3 //GREATER_THAN_OR_EQUAL
public constant integer FILTER_SPELL = 4 //GREATER_THAN
public constant integer FILTER_CODE = 5 //NOT_EQUAL
public constant integer FILTER_MAX = 6
private integer eventFilter = FILTER_OTHER
public boolean inception = false //When true, it allows your trigger to potentially go recursive up to LIMBO. However it must be set per-trigger throughout the game and not only once per trigger during map initialization.
private boolean dreaming = false
private integer sleepLevel = 0
private group proclusGlobal = null //track sources of recursion
private group fischerMorrow = null //track targets of recursion
private boolean kicking = false
private boolean eventsRun = false
private keyword run
private keyword trigFrozen
private keyword levelsDeep
private keyword inceptionTrig
private boolean hasLethal = false
endglobals
native UnitAlive takes unit u returns boolean
//GUI Vars:
/*
Retained from 3.8 and prior:
----------------------------
unit udg_DamageEventSource
unit udg_DamageEventTarget
unit udg_EnhancedDamageTarget
group udg_DamageEventAOEGroup
integer udg_DamageEventAOE
integer udg_DamageEventLevel
real udg_DamageModifierEvent
real udg_DamageEvent
real udg_AfterDamageEvent
real udg_DamageEventAmount
real udg_DamageEventPrevAmt
real udg_AOEDamageEvent
boolean udg_DamageEventOverride
boolean udg_NextDamageType
boolean udg_DamageEventType
boolean udg_IsDamageSpell
//Added in 5.0:
boolean udg_IsDamageMelee
boolean udg_IsDamageRanged
unit udg_AOEDamageSource
real udg_LethalDamageEvent
real udg_LethalDamageHP
real udg_DamageScalingWC3
integer udg_DamageEventAttackT
integer udg_DamageEventDamageT
integer udg_DamageEventWeaponT
//Added in 5.1:
boolean udg_IsDamageCode
//Added in 5.2:
integer udg_DamageEventArmorT
integer udg_DamageEventDefenseT
//Addded in 5.3:
real DamageEventArmorPierced
real udg_DamageScalingUser
//Added in 5.4.2 to allow GUI users to re-issue the exact same attack and damage type at the attacker.
attacktype array udg_CONVERTED_ATTACK_TYPE
damagetype array udg_CONVERTED_DAMAGE_TYPE
//Added after Reforged introduced the new native BlzGetDamageIsAttack
boolean udg_IsDamageAttack
//Added in 5.6 to give GUI users control over the "IsDamageAttack", "IsDamageRanged" and "DamageEventWeaponT" field
boolean udg_NextDamageIsAttack //The first boolean value in the UnitDamageTarget native
boolean udg_NextDamageIsMelee //Flag the damage classification as melee
boolean udg_NextDamageIsRanged //The second boolean value in the UnitDamageTarget native
integer udg_NextDamageWeaponT //Allows control over damage sound effect
//Added in 5.7 to enable efficient, built-in filtering (see the below "checkConfig" method - I recommend commenting-out anything you don't need in your map)
integer udg_DamageFilterAttackT
integer udg_DamageFilterDamageT //filter for a specific attack/damage type
unit udg_DamageFilterSource
unit udg_DamageFilterTarget //filter for a specific source/target
integer udg_DamageFilterSourceT
integer udg_DamageFilterTargetT //unit type of source/target
integer udg_DamageFilterType //which DamageEventType was used
integer udg_DamageFilterSourceB
integer udg_DamageFilterTargetB //if source/target has a buff
real udg_DamageFilterMinAmount //only allow a minimum damage threshold
//Added in 5.8:
boolean udg_RemoveDamageEvent //Allow GUI users to more fully unregister a damage event trigger. Can only be used from within a damage event (of any kind).
integer udg_DamageFilterSourceA
integer udg_DamageFilterTargetA //Check if a source or target have a specific ability (will overwrite any source or target buff check, I need to use this because GUI differentiates ability ID and buff ID)
integer udg_DamageFilterSourceI
integer udg_DamageFilterTargetI //Check if a source or target have a specific type of item
integer udg_DamageFilterSourceC
integer udg_DamageFilterTargetC //Classification of source/target (e.g. hero, treant, ward)
*/
struct DamageTrigger extends array
static method checkItem takes unit u, integer id returns boolean
local integer i
if IsUnitType(u, UNIT_TYPE_HERO) then
set i = UnitInventorySize(u)
loop
exitwhen i <= 0
set i = i - 1
if GetItemTypeId(UnitItemInSlot(u, i)) == id then
return true
endif
endloop
endif
return false
endmethod
//Map-makers should comment-out any lines they will never need to check for and move to the top any lines
//that are checked more frequently in their map.
method checkConfig takes nothing returns boolean
//call BJDebugMsg("Checking configuration")
if this.sourceType != 0 and GetUnitTypeId(udg_DamageEventSource) != this.sourceType then
elseif this.targetType != 0 and GetUnitTypeId(udg_DamageEventTarget) != this.targetType then
elseif this.sourceBuff != 0 and GetUnitAbilityLevel(udg_DamageEventSource, this.sourceBuff) == 0 then
elseif this.targetBuff != 0 and GetUnitAbilityLevel(udg_DamageEventTarget, this.targetBuff) == 0 then
elseif this.failChance > 0.00 and GetRandomReal(0.00, 1.00) <= this.failChance then
elseif this.userType != 0 and udg_DamageEventType != this.userType then
elseif this.source != null and this.source != udg_DamageEventSource then
elseif this.target != null and this.target != udg_DamageEventTarget then
elseif this.attackType >= 0 and this.attackType != udg_DamageEventAttackT then
elseif this.damageType >= 0 and this.damageType != udg_DamageEventDamageT then
elseif this.sourceItem != 0 and not .checkItem(udg_DamageEventSource, this.sourceItem) then
elseif this.targetItem != 0 and not .checkItem(udg_DamageEventTarget, this.targetItem) then
elseif this.sourceClass >= 0 and not IsUnitType(udg_DamageEventSource, ConvertUnitType(this.sourceClass)) then
elseif this.targetClass >= 0 and not IsUnitType(udg_DamageEventTarget, ConvertUnitType(this.targetClass)) then
elseif udg_DamageEventAmount >= this.damageMin then
//call BJDebugMsg("Configuration passed")
return true
endif
//call BJDebugMsg("Checking failed")
return false
endmethod
//The below variables are to be treated as constant
readonly static thistype MOD = 1
readonly static thistype SHIELD = 4
readonly static thistype DAMAGE = 5
readonly static thistype ZERO = 6
readonly static thistype AFTER = 7
readonly static thistype LETHAL = 8
readonly static thistype AOE = 9
private static integer count = 9
static thistype lastRegistered = 0
private static thistype array trigIndexStack
static thistype eventIndex = 0
static boolean array filters
readonly string eventStr
readonly real weight
boolean usingGUI
//The below variables are to be treated as private
private thistype next
private trigger rootTrig
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer levelsDeep //How deep the user recursion currently is.
boolean inceptionTrig //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent trigger.
//configuration variables:
boolean configured
unit source
unit target
integer sourceType
integer targetType
integer sourceBuff
integer targetBuff
integer sourceItem
integer targetItem
integer sourceClass
integer targetClass
real damageMin
real failChance
integer attackType
integer damageType
integer userType
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
method operator runChance= takes real r returns nothing
set this.failChance = 1.00 - r
endmethod
method configure takes nothing returns nothing
set this.attackType = udg_DamageFilterAttackT
set this.damageType = udg_DamageFilterDamageT
set this.source = udg_DamageFilterSource
set this.target = udg_DamageFilterTarget
set this.sourceType = udg_DamageFilterSourceT
set this.targetType = udg_DamageFilterTargetT
set this.sourceItem = udg_DamageFilterSourceI
set this.targetItem = udg_DamageFilterTargetI
set this.sourceClass = udg_DamageFilterSourceC
set this.targetClass = udg_DamageFilterTargetC
set this.userType = udg_DamageFilterType
set this.damageMin = udg_DamageFilterMinAmount
set this.failChance = 1.00 - (udg_DamageFilterRunChance - udg_DamageFilterFailChance)
if udg_DamageFilterSourceA > 0 then
set this.sourceBuff = udg_DamageFilterSourceA
set udg_DamageFilterSourceA = 0
else
set this.sourceBuff = udg_DamageFilterSourceB
endif
if udg_DamageFilterTargetA > 0 then
set this.targetBuff = udg_DamageFilterTargetA
set udg_DamageFilterTargetA = 0
else
set this.targetBuff = udg_DamageFilterTargetB
endif
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSource = null
set udg_DamageFilterTarget = null
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceI = 0
set udg_DamageFilterTargetI = 0
set udg_DamageFilterMinAmount = 0.00
set udg_DamageFilterFailChance = 0.00
set udg_DamageFilterRunChance = 1.00
set this.configured = true
endmethod
static method setGUIFromStruct takes boolean full returns nothing
set udg_DamageEventAmount = Damage.index.damage
set udg_DamageEventAttackT = GetHandleId(Damage.index.attackType)
set udg_DamageEventDamageT = GetHandleId(Damage.index.damageType)
set udg_DamageEventWeaponT = GetHandleId(Damage.index.weaponType)
set udg_DamageEventType = Damage.index.userType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventArmorPierced = Damage.index.armorPierced
set udg_DamageEventArmorT = Damage.index.armorType
set udg_DamageEventDefenseT = Damage.index.defenseType
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if full then
set udg_DamageEventSource = Damage.index.sourceUnit
set udg_DamageEventTarget = Damage.index.targetUnit
set udg_DamageEventPrevAmt = Damage.index.prevAmt
set udg_IsDamageAttack = Damage.index.isAttack
set udg_IsDamageCode = Damage.index.isCode
set udg_IsDamageSpell = Damage.index.isSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_IsDamageMelee = Damage.index.isMelee
set udg_IsDamageRanged = Damage.index.isRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endmethod
static method setStructFromGUI takes nothing returns nothing
set Damage.index.damage = udg_DamageEventAmount
set Damage.index.attackType = ConvertAttackType(udg_DamageEventAttackT)
set Damage.index.damageType = ConvertDamageType(udg_DamageEventDamageT)
set Damage.index.weaponType = ConvertWeaponType(udg_DamageEventWeaponT)
set Damage.index.userType = udg_DamageEventType
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index.armorPierced = udg_DamageEventArmorPierced
set Damage.index.armorType = udg_DamageEventArmorT
set Damage.index.defenseType = udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method getVerboseStr takes string eventName returns string
if eventName == "Modifier" or eventName == "Mod" then
return "udg_DamageModifierEvent"
endif
return "udg_" + eventName + "DamageEvent"
endmethod
private static method getStrIndex takes string var, real lbs returns thistype
local integer root = R2I(lbs)
if (var == "udg_DamageModifierEvent" and root < 4) or var == "udg_PreDamageEvent" then
set root = MOD
elseif var == "udg_DamageModifierEvent" or var == "udg_ArmorDamageEvent" then
set root = SHIELD
elseif (var == "udg_DamageEvent" and root == 2 or root == 0) or var == "udg_ZeroDamageEvent" then
set root = ZERO
elseif var == "udg_DamageEvent" or var == "udg_OnDamageEvent" then
set root = DAMAGE
elseif var == "udg_AfterDamageEvent" then
set root = AFTER
elseif var == "udg_LethalDamageEvent" then
set root = LETHAL
elseif var == "udg_AOEDamageEvent" or var == "udg_SourceDamageEvent" then
set root = AOE
else
set root = 0
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_REG_PLUGIN_05()
endif
return root
endmethod
private method toggleAllFilters takes boolean flag returns nothing
set filters[this + FILTER_ATTACK] = flag
set filters[this + FILTER_MELEE] = flag
set filters[this + FILTER_OTHER] = flag
set filters[this + FILTER_RANGED] = flag
set filters[this + FILTER_SPELL] = flag
set filters[this + FILTER_CODE] = flag
endmethod
method operator filter= takes integer f returns nothing
set this = this*FILTER_MAX
if f == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if f == FILTER_ATTACK then
set filters[this + FILTER_ATTACK] = true
set filters[this + FILTER_MELEE] = true
set filters[this + FILTER_RANGED] = true
else
set filters[this + f] = true
endif
endif
endmethod
static method registerVerbose takes trigger whichTrig, string var, real lbs, boolean GUI, integer filt returns thistype
local thistype index= getStrIndex(var, lbs)
local thistype i = 0
local thistype id = 0
if index == 0 then
return 0
elseif lastRegistered.rootTrig == whichTrig and lastRegistered.usingGUI then
set filters[lastRegistered*FILTER_MAX + filt] = true //allows GUI to register multiple different types of Damage filters to the same trigger
return 0
endif
if not hasLethal and index == LETHAL then
set hasLethal = true
endif
if trigIndexStack[0] == 0 then
set count = count + 1 //List runs from index 10 and up
set id = count
else
set id = trigIndexStack[0]
set trigIndexStack[0] = trigIndexStack[id]
endif
set lastRegistered = id
set id.filter = filt
set id.rootTrig = whichTrig
set id.usingGUI = GUI
set id.weight = lbs
set id.eventStr = var
//Next 2 lines added to fix a bug when using manual vJass configuration,
//discovered and solved by lolreported
set id.attackType = -1
set id.damageType = -1
//they will probably bug out with class types as well, so I should add them, just in case:
set id.sourceClass = -1
set id.targetClass = -1
loop
set i = index.next
exitwhen i == 0 or lbs < i.weight
set index = i
endloop
set index.next = id
set id.next = i
//call BJDebugMsg("Registered " + I2S(id) + " to " + I2S(index) + " and before " + I2S(i))
return lastRegistered
endmethod
static method registerTrigger takes trigger t, string var, real lbs returns thistype
return registerVerbose(t, DamageTrigger.getVerboseStr(var), lbs, false, FILTER_OTHER)
endmethod
private static thistype prev = 0
static method getIndex takes trigger t, string eventName, real lbs returns thistype
local thistype index = getStrIndex(getVerboseStr(eventName), lbs)
loop
set prev = index
set index = index.next
exitwhen index == 0 or index.rootTrig == t
endloop
return index
endmethod
method unregisterByIndex takes boolean reset returns boolean
if this == 0 then
return false
endif
set prev.next = this.next
set trigIndexStack[this] = trigIndexStack[0]
set trigIndexStack[0] = this
if reset then
call this.configure()
set this.configured = false
call thistype(this*FILTER_MAX).toggleAllFilters(false)
endif
return true
endmethod
static method unregister takes trigger t, string eventName, real lbs, boolean reset returns boolean
return getIndex(t, eventName, lbs).unregisterByIndex(reset)
endmethod
method run takes nothing returns nothing
local integer cat = this
local Damage d = Damage.index
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
local boolean structUnset = false
local boolean guiUnset = false
local boolean mod = cat <= DAMAGE
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if dreaming then
return
endif
set dreaming = true
call DisableTrigger(t1)
call DisableTrigger(t2)
call EnableTrigger(t3)
//call BJDebugMsg("Start of event running")
loop
set this = this.next
exitwhen this == 0
exitwhen cat == MOD and (udg_DamageEventOverride or udg_DamageEventType == TYPE_PURE)
exitwhen cat == SHIELD and udg_DamageEventAmount <= 0.00
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
exitwhen cat == LETHAL and udg_LethalDamageHP > DEATH_VAL
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set eventIndex = this
if (not this.trigFrozen) and filters[this*FILTER_MAX + d.eFilter] and IsTriggerEnabled(this.rootTrig) and ((not this.configured) or (this.checkConfig())) and (cat != AOE or udg_DamageEventAOE > 1 or this.eventStr == "udg_SourceDamageEvent") then
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
if guiUnset then
set guiUnset = false
call setGUIFromStruct(false)
endif
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_PDD()
elseif structUnset then
set structUnset = false
call setStructFromGUI()
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_FILTER_PLUGIN_05()
//JASS users who do not use actions can modify the below block to just evaluate.
//It should not make any perceptable difference in terms of performance.
if TriggerEvaluate(this.rootTrig) then
call TriggerExecute(this.rootTrig)
endif
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_05()
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if mod then
if this.usingGUI then
//! runtextmacro optional DAMAGE_EVENT_MOD_PLUGIN_PDD()
if cat != MOD then
set d.damage = udg_DamageEventAmount
else
set structUnset = true
endif
elseif cat != MOD then
set udg_DamageEventAmount = d.damage
else
set guiUnset = true
endif
endif
if udg_RemoveDamageEvent then
set udg_RemoveDamageEvent = false
call this.unregisterByIndex(true)
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endloop
static if USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if structUnset then
call setStructFromGUI()
endif
if guiUnset then
call setGUIFromStruct(false)
endif
else// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
//call BJDebugMsg("End of event running")
call DisableTrigger(t3)
call EnableTrigger(t1)
call EnableTrigger(t2)
set dreaming = false
endmethod
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code c returns trigger
local integer i = 0
local boolexpr b = Filter(c)
loop
if i == autoN then
set autoTriggers[i] = CreateTrigger()
set autoFuncs[i] = b
call TriggerAddCondition(autoTriggers[i], b)
exitwhen true
endif
set i = i + 1
exitwhen b == autoFuncs[i]
endloop
return autoTriggers[i]
endmethod
endstruct
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_USER_STRUCT_PLUGIN_05()
struct Damage extends array
readonly unit sourceUnit //stores udg_DamageEventSource
readonly unit targetUnit //stores udg_DamageEventTarget
real damage //stores udg_DamageEventAmount
readonly real prevAmt //stores udg_DamageEventPrevAmt
attacktype attackType //stores udg_DamageEventAttackT
damagetype damageType //stores udg_DamageEventDamageT
weapontype weaponType //stores udg_DamageEventWeaponT
integer userType //stores udg_DamageEventType
readonly boolean isAttack //stores udg_IsDamageAttack
readonly boolean isCode //stores udg_IsDamageCode
readonly boolean isSpell //stores udg_IsDamageSpell
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isMelee //stores udg_IsDamageMelee
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly boolean isRanged //stores udg_IsDamageRanged
readonly integer eFilter //stores the previous eventFilter variable
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
real armorPierced //stores udg_DamageEventArmorPierced
integer armorType //stores udg_DamageEventArmorT
integer defenseType //stores udg_DamageEventDefenseT
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
readonly static Damage index = 0
private static Damage damageStack = 0
private static Damage prepped = 0
private static integer count = 0 //The number of currently-running queued or sequential damage instances
private Damage stackRef
private DamageTrigger recursiveTrig
private integer prevArmorT
private integer prevDefenseT
static method operator source takes nothing returns unit
return udg_DamageEventSource
endmethod
static method operator target takes nothing returns unit
return udg_DamageEventTarget
endmethod
static method operator amount takes nothing returns real
return Damage.index.damage
endmethod
static method operator amount= takes real r returns nothing
set Damage.index.damage = r
endmethod
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private method setArmor takes boolean reset returns nothing
local real pierce
local integer at
local integer dt
if reset then
set pierce = udg_DamageEventArmorPierced
set at = Damage.index.prevArmorT
set dt = Damage.index.prevDefenseT
set udg_DamageEventArmorPierced = 0.00
set this.armorPierced = 0.00
else
set pierce = -udg_DamageEventArmorPierced
set at = udg_DamageEventArmorT
set dt = udg_DamageEventDefenseT
endif
if not (pierce == 0.00) then //Changed condition thanks to bug reported by BLOKKADE
call BlzSetUnitArmor(udg_DamageEventTarget, BlzGetUnitArmor(udg_DamageEventTarget) + pierce)
endif
if Damage.index.prevArmorT != udg_DamageEventArmorT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_ARMOR_TYPE, at)
endif
if Damage.index.prevDefenseT != udg_DamageEventDefenseT then
call BlzSetUnitIntegerField(udg_DamageEventTarget, UNIT_IF_DEFENSE_TYPE, dt)
endif
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method onAOEEnd takes nothing returns nothing
call DamageTrigger.AOE.run()
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
set udg_EnhancedDamageTarget = null
set udg_AOEDamageSource = null
call GroupClear(udg_DamageEventAOEGroup)
endmethod
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
private static method afterDamage takes nothing returns nothing
if udg_DamageEventDamageT != 0 and not (udg_DamageEventPrevAmt == 0.00) then
call DamageTrigger.AFTER.run()
set udg_DamageEventDamageT = 0
set udg_DamageEventPrevAmt = 0.00
endif
endmethod
private method doPreEvents takes boolean natural returns boolean
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set this.armorType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_ARMOR_TYPE)
set this.defenseType = BlzGetUnitIntegerField(this.targetUnit, UNIT_IF_DEFENSE_TYPE)
set this.prevArmorT = this.armorType
set this.prevDefenseT = this.defenseType
set this.armorPierced = 0.00
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set Damage.index = this
call DamageTrigger.setGUIFromStruct(true)
call GroupAddUnit(proclusGlobal, udg_DamageEventSource)
call GroupAddUnit(fischerMorrow, udg_DamageEventTarget)
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_PRE_VARS_PLUGIN_05()
if not (udg_DamageEventAmount == 0.00) then
set udg_DamageEventOverride = udg_DamageEventDamageT == 0
call DamageTrigger.MOD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call DamageTrigger.setGUIFromStruct(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if natural then
call BlzSetEventAttackType(this.attackType)
call BlzSetEventDamageType(this.damageType)
call BlzSetEventWeaponType(this.weaponType)
call BlzSetEventDamage(udg_DamageEventAmount)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call this.setArmor(false)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
return false
endif
return true
endmethod
private static method unfreeze takes nothing returns nothing
local Damage i = damageStack
loop
exitwhen i == 0
set i = i - 1
set i.stackRef.recursiveTrig.trigFrozen = false
set i.stackRef.recursiveTrig.levelsDeep = 0
endloop
call EnableTrigger(t1)
call EnableTrigger(t2)
set kicking = false
set damageStack = 0
set prepped = 0
set dreaming = false
set sleepLevel = 0
call GroupClear(proclusGlobal)
call GroupClear(fischerMorrow)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method finish takes nothing returns nothing
local Damage i = 0
local integer exit
if eventsRun then
set eventsRun = false
call afterDamage()
endif
if canKick and not kicking then
if damageStack != 0 then
set kicking = true
loop
set sleepLevel = sleepLevel + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then //Added just in case dead units had issues.
call prepped.doPreEvents(false) //don't evaluate the pre-event
if prepped.damage > 0.00 then
call DisableTrigger(t1) //Force only the after armor event to run.
call EnableTrigger(t2) //in case the user forgot to re-enable this
set totem = true
call UnitDamageTarget(prepped.sourceUnit, prepped.targetUnit, prepped.damage, prepped.isAttack, prepped.isRanged, prepped.attackType, prepped.damageType, prepped.weaponType)
else
//No new events run at all in this case
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
//No need for BlzSetEventDamage here
call SetWidgetLife(prepped.targetUnit, GetWidgetLife(prepped.targetUnit) - prepped.damage)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call prepped.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
call afterDamage()
endif
set i = i + 1
exitwhen i == exit
endloop
exitwhen i == damageStack
endloop
endif
call unfreeze()
endif
endmethod
private static method failsafeClear takes nothing returns nothing
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call Damage.index.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set canKick = true
set kicking = false
set totem = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set eventsRun = true
endif
call finish()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if dreaming then
call EnableTrigger(t3)
else
call EnableTrigger(t1)
call EnableTrigger(t2)
endif
else
if dreaming then
call DisableTrigger(t3)
else
call DisableTrigger(t1)
call DisableTrigger(t2)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(t1)
endmethod
private static boolean arisen = false
private static method getOutOfBed takes nothing returns nothing
if totem then
call failsafeClear() //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
else
set canKick = true
set kicking = false
call finish()
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call onAOEEnd()
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set arisen = true
endmethod
private static method wakeUp takes nothing returns nothing
set dreaming = false
set Damage.enabled = true
call ForForce(bj_FORCE_PLAYER[0], function thistype.getOutOfBed) //Moved to a new thread in case of a thread crash
if not arisen then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set arisen = false
endif
set Damage.count = 0
set Damage.index = 0
set alarmSet = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
if not (this.damage == 0.00) then
set this.recursiveTrig = DamageTrigger.eventIndex
if not this.isCode then
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or DamageTrigger.eventIndex.inceptionTrig
if kicking and IsUnitInGroup(this.sourceUnit, proclusGlobal) and IsUnitInGroup(this.targetUnit, fischerMorrow) then
if not inception then
set DamageTrigger.eventIndex.trigFrozen = true
elseif not DamageTrigger.eventIndex.trigFrozen then
set DamageTrigger.eventIndex.inceptionTrig = true
if DamageTrigger.eventIndex.levelsDeep < sleepLevel then
set DamageTrigger.eventIndex.levelsDeep = DamageTrigger.eventIndex.levelsDeep + 1
if DamageTrigger.eventIndex.levelsDeep >= LIMBO then
set DamageTrigger.eventIndex.trigFrozen = true
endif
endif
endif
endif
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " levelsDeep: " + I2S(DamageTrigger.eventIndex.levelsDeep) + " sleepLevel: " + I2S(sleepLevel))
endif
set inception = false
endmethod
private static method clearNexts takes nothing returns nothing
set udg_NextDamageIsAttack = false
set udg_NextDamageType = 0
set udg_NextDamageWeaponT = 0
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_NextDamageIsMelee = false
set udg_NextDamageIsRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endmethod
static method create takes unit src, unit tgt, real amt, boolean a, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d = Damage.count + 1
set Damage.count = d
set d.sourceUnit = src
set d.targetUnit = tgt
set d.damage = amt
set d.prevAmt = amt
set d.attackType = at
set d.damageType = dt
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or a
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = create(GetEventDamageSource(), GetTriggerUnit(), GetEventDamage(), BlzGetEventIsAttack(), BlzGetEventAttackType(), BlzGetEventDamageType(), BlzGetEventWeaponType())
set d.isCode = udg_NextDamageType != 0 or udg_NextDamageIsAttack or udg_NextDamageIsRanged or udg_NextDamageIsMelee or d.damageType == DAMAGE_TYPE_MIND or udg_NextDamageWeaponT != 0 or (d.damageType == DAMAGE_TYPE_UNKNOWN and not (d.damage == 0.00))
if d.isCode then
if udg_NextDamageType != 0 then
set d.userType = udg_NextDamageType
else
set d.userType = TYPE_CODE
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = udg_NextDamageIsMelee
set d.isRanged = udg_NextDamageIsRanged
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.eFilter = FILTER_CODE
if udg_NextDamageWeaponT != 0 then
set d.weaponType = ConvertWeaponType(udg_NextDamageWeaponT)
set udg_NextDamageWeaponT = 0
endif
else
set d.userType = 0
if d.damageType == DAMAGE_TYPE_NORMAL and d.isAttack then
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = IsUnitType(d.sourceUnit, UNIT_TYPE_MELEE_ATTACKER)
set d.isRanged = IsUnitType(d.sourceUnit, UNIT_TYPE_RANGED_ATTACKER)
if d.isMelee and d.isRanged then
set d.isMelee = d.weaponType != null // Melee units play a sound when damaging
set d.isRanged = not d.isMelee // In the case where a unit is both ranged and melee, the ranged attack plays no sound.
endif
if d.isMelee then
set d.eFilter = FILTER_MELEE
elseif d.isRanged then
set d.eFilter = FILTER_RANGED
else
set d.eFilter = FILTER_ATTACK
endif
else
set d.eFilter = FILTER_ATTACK
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
if d.isSpell then
set d.eFilter = FILTER_SPELL
else
set d.eFilter = FILTER_OTHER
endif
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set d.isMelee = false
set d.isRanged = false
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursion takes nothing returns boolean //New in 5.7
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamaging takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if alarmSet then
if totem then //WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
if d.damageType == DAMAGE_TYPE_SPIRIT_LINK or d.damageType == DAMAGE_TYPE_DEFENSIVE or d.damageType == DAMAGE_TYPE_PLANT then
set totem = false
set lastInstance= Damage.index
set canKick = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call finish() //wrap up any previous damage index
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.sourceUnit != udg_AOEDamageSource then
call onAOEEnd()
set udg_AOEDamageSource = d.sourceUnit
elseif d.targetUnit == udg_EnhancedDamageTarget then
set udg_DamageEventLevel= udg_DamageEventLevel + 1
elseif not IsUnitInGroup(d.targetUnit, udg_DamageEventAOEGroup) then
set udg_DamageEventAOE = udg_DamageEventAOE + 1
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
else
call TimerStart(alarm, 0.00, false, function Damage.wakeUp)
set alarmSet = true
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_AOEDamageSource = d.sourceUnit
set udg_EnhancedDamageTarget= d.targetUnit
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
static if USE_EXTRA then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call GroupAddUnit(udg_DamageEventAOEGroup, d.targetUnit)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if d.doPreEvents(true) then
call DamageTrigger.ZERO.run()
set canKick = true
call finish()
endif
set totem = lastInstance == 0 or attacksImmune[udg_DamageEventAttackT] or damagesImmune[udg_DamageEventDamageT] or not IsUnitType(udg_DamageEventTarget, UNIT_TYPE_MAGIC_IMMUNE)
return false
endmethod
private static method onDamaged takes nothing returns boolean
local real r = GetEventDamage()
local Damage d = Damage.index
//call BJDebugMsg("Second damage event running for " + GetUnitName(GetTriggerUnit()))
if prepped > 0 then
set prepped = 0
elseif dreaming or d.prevAmt == 0.00 then
return false
elseif totem then
set totem = false
else
//This should only happen for stuff like Spirit Link or Thorns Aura/Carapace
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
set canKick = true
call DamageTrigger.setGUIFromStruct(true)
endif
static if USE_ARMOR_MOD then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.setArmor(true)
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not (udg_DamageEventAmount == 0.00) and not (r == 0.00) then
set udg_DamageScalingWC3 = r / udg_DamageEventAmount
elseif udg_DamageEventAmount > 0.00 then
set udg_DamageScalingWC3 = 0.00
else
set udg_DamageScalingWC3 = 1.00
if udg_DamageEventPrevAmt == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = r
set d.damage = r
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_GDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_PDD()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_VARS_PLUGIN_05()
if udg_DamageEventAmount > 0.00 then
call DamageTrigger.SHIELD.run()
static if not USE_GUI then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
set udg_DamageEventAmount = d.damage
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_LETHAL then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if hasLethal or udg_DamageEventType < 0 then
set udg_LethalDamageHP = GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if hasLethal then
call DamageTrigger.LETHAL.run()
set udg_DamageEventAmount = GetWidgetLife(udg_DamageEventTarget) - udg_LethalDamageHP
set d.damage = udg_DamageEventAmount
endif
if udg_DamageEventType < 0 and udg_LethalDamageHP <= DEATH_VAL then
call SetUnitExploded(udg_DamageEventTarget, true)
endif
endif
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
static if USE_SCALING then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if udg_DamageEventPrevAmt == 0.00 or udg_DamageScalingWC3 == 0.00 then
set udg_DamageScalingUser = 0.00
else
set udg_DamageScalingUser = udg_DamageEventAmount/udg_DamageEventPrevAmt/udg_DamageScalingWC3
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
endif
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
endif
call BlzSetEventDamage(udg_DamageEventAmount)
set eventsRun = true
if udg_DamageEventAmount == 0.00 then
call finish()
endif
return false
endmethod
static method apply takes unit src, unit tgt, real amt, boolean a, boolean r, attacktype at, damagetype dt, weapontype wt returns Damage
local Damage d
if udg_NextDamageType == 0 then
set udg_NextDamageType = TYPE_CODE
endif
if dreaming then
set d = create(src, tgt, amt, a, at, dt, wt)
set d.isCode = true
set d.eFilter = FILTER_CODE
set d.userType = udg_NextDamageType
static if USE_MELEE_RANGE then// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
if not d.isSpell then
set d.isRanged = udg_NextDamageIsRanged or r
set d.isMelee = not d.isRanged
endif
endif// \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ /
call d.addRecursive()
else
call UnitDamageTarget(src, tgt, amt, a, r, at, dt, wt)
set d = Damage.index
call finish()
endif
call clearNexts()
return d
endmethod
static method applySpell takes unit src, unit tgt, real amt, damagetype dt returns Damage
return apply(src, tgt, amt, false, false, null, dt, null)
endmethod
static method applyAttack takes unit src, unit tgt, real amt, boolean ranged, attacktype at, weapontype wt returns Damage
return apply(src, tgt, amt, true, ranged, at, DAMAGE_TYPE_NORMAL, wt)
endmethod
//===========================================================================
private static method onInit takes nothing returns nothing
set alarm = CreateTimer()
set proclusGlobal = CreateGroup()
set fischerMorrow = CreateGroup()
set t1 = CreateTrigger()
set t2 = CreateTrigger()
set t3 = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(t1, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t1, Filter(function Damage.onDamaging))
call TriggerRegisterAnyUnitEventBJ(t2, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(t2, Filter(function Damage.onDamaged))
//For recursion
call TriggerRegisterAnyUnitEventBJ(t3, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(t3, Filter(function Damage.onRecursion))
call DisableTrigger(t3)
//For preventing Thorns/Defensive glitch.
//Data gathered from https://www.hiveworkshop.com/threads/repo-in-progress-mapping-damage-types-to-their-abilities.316271/
set attacksImmune[0] = false //ATTACK_TYPE_NORMAL
set attacksImmune[1] = true //ATTACK_TYPE_MELEE
set attacksImmune[2] = true //ATTACK_TYPE_PIERCE
set attacksImmune[3] = true //ATTACK_TYPE_SIEGE
set attacksImmune[4] = false //ATTACK_TYPE_MAGIC
set attacksImmune[5] = true //ATTACK_TYPE_CHAOS
set attacksImmune[6] = true //ATTACK_TYPE_HERO
set damagesImmune[0] = true //DAMAGE_TYPE_UNKNOWN
set damagesImmune[4] = true //DAMAGE_TYPE_NORMAL
set damagesImmune[5] = true //DAMAGE_TYPE_ENHANCED
set damagesImmune[8] = false //DAMAGE_TYPE_FIRE
set damagesImmune[9] = false //DAMAGE_TYPE_COLD
set damagesImmune[10] = false //DAMAGE_TYPE_LIGHTNING
set damagesImmune[11] = true //DAMAGE_TYPE_POISON
set damagesImmune[12] = true //DAMAGE_TYPE_DISEASE
set damagesImmune[13] = false //DAMAGE_TYPE_DIVINE
set damagesImmune[14] = false //DAMAGE_TYPE_MAGIC
set damagesImmune[15] = false //DAMAGE_TYPE_SONIC
set damagesImmune[16] = true //DAMAGE_TYPE_ACID
set damagesImmune[17] = false //DAMAGE_TYPE_FORCE
set damagesImmune[18] = false //DAMAGE_TYPE_DEATH
set damagesImmune[19] = false //DAMAGE_TYPE_MIND
set damagesImmune[20] = false //DAMAGE_TYPE_PLANT
set damagesImmune[21] = false //DAMAGE_TYPE_DEFENSIVE
set damagesImmune[22] = true //DAMAGE_TYPE_DEMOLITION
set damagesImmune[23] = true //DAMAGE_TYPE_SLOW_POISON
set damagesImmune[24] = false //DAMAGE_TYPE_SPIRIT_LINK
set damagesImmune[25] = false //DAMAGE_TYPE_SHADOW_STRIKE
set damagesImmune[26] = true //DAMAGE_TYPE_UNIVERSAL
endmethod
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_DMGPKG()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_01()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_02()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_03()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_04()
//! runtextmacro optional DAMAGE_EVENT_STRUCT_PLUGIN_05()
endstruct
public function DebugStr takes nothing returns nothing
local integer i = 0
loop
set udg_CONVERTED_ATTACK_TYPE[i] = ConvertAttackType(i)
exitwhen i == 6
set i = i + 1
endloop
set i = 0
loop
set udg_CONVERTED_DAMAGE_TYPE[i] = ConvertDamageType(i)
exitwhen i == 26
set i = i + 1
endloop
set udg_AttackTypeDebugStr[0] = "SPELLS" //ATTACK_TYPE_NORMAL in JASS
set udg_AttackTypeDebugStr[1] = "NORMAL" //ATTACK_TYPE_MELEE in JASS
set udg_AttackTypeDebugStr[2] = "PIERCE"
set udg_AttackTypeDebugStr[3] = "SIEGE"
set udg_AttackTypeDebugStr[4] = "MAGIC"
set udg_AttackTypeDebugStr[5] = "CHAOS"
set udg_AttackTypeDebugStr[6] = "HERO"
set udg_DamageTypeDebugStr[0] = "UNKNOWN"
set udg_DamageTypeDebugStr[4] = "NORMAL"
set udg_DamageTypeDebugStr[5] = "ENHANCED"
set udg_DamageTypeDebugStr[8] = "FIRE"
set udg_DamageTypeDebugStr[9] = "COLD"
set udg_DamageTypeDebugStr[10] = "LIGHTNING"
set udg_DamageTypeDebugStr[11] = "POISON"
set udg_DamageTypeDebugStr[12] = "DISEASE"
set udg_DamageTypeDebugStr[13] = "DIVINE"
set udg_DamageTypeDebugStr[14] = "MAGIC"
set udg_DamageTypeDebugStr[15] = "SONIC"
set udg_DamageTypeDebugStr[16] = "ACID"
set udg_DamageTypeDebugStr[17] = "FORCE"
set udg_DamageTypeDebugStr[18] = "DEATH"
set udg_DamageTypeDebugStr[19] = "MIND"
set udg_DamageTypeDebugStr[20] = "PLANT"
set udg_DamageTypeDebugStr[21] = "DEFENSIVE"
set udg_DamageTypeDebugStr[22] = "DEMOLITION"
set udg_DamageTypeDebugStr[23] = "SLOW_POISON"
set udg_DamageTypeDebugStr[24] = "SPIRIT_LINK"
set udg_DamageTypeDebugStr[25] = "SHADOW_STRIKE"
set udg_DamageTypeDebugStr[26] = "UNIVERSAL"
set udg_WeaponTypeDebugStr[0] = "NONE" //WEAPON_TYPE_WHOKNOWS in JASS
set udg_WeaponTypeDebugStr[1] = "METAL_LIGHT_CHOP"
set udg_WeaponTypeDebugStr[2] = "METAL_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[3] = "METAL_HEAVY_CHOP"
set udg_WeaponTypeDebugStr[4] = "METAL_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[5] = "METAL_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[6] = "METAL_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[7] = "METAL_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[8] = "METAL_HEAVY_BASH"
set udg_WeaponTypeDebugStr[9] = "METAL_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[10] = "METAL_HEAVY_STAB"
set udg_WeaponTypeDebugStr[11] = "WOOD_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[12] = "WOOD_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[13] = "WOOD_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[14] = "WOOD_LIGHT_BASH"
set udg_WeaponTypeDebugStr[15] = "WOOD_MEDIUM_BASH"
set udg_WeaponTypeDebugStr[16] = "WOOD_HEAVY_BASH"
set udg_WeaponTypeDebugStr[17] = "WOOD_LIGHT_STAB"
set udg_WeaponTypeDebugStr[18] = "WOOD_MEDIUM_STAB"
set udg_WeaponTypeDebugStr[19] = "CLAW_LIGHT_SLICE"
set udg_WeaponTypeDebugStr[20] = "CLAW_MEDIUM_SLICE"
set udg_WeaponTypeDebugStr[21] = "CLAW_HEAVY_SLICE"
set udg_WeaponTypeDebugStr[22] = "AXE_MEDIUM_CHOP"
set udg_WeaponTypeDebugStr[23] = "ROCK_HEAVY_BASH"
set udg_DefenseTypeDebugStr[0] = "LIGHT"
set udg_DefenseTypeDebugStr[1] = "MEDIUM"
set udg_DefenseTypeDebugStr[2] = "HEAVY"
set udg_DefenseTypeDebugStr[3] = "FORTIFIED"
set udg_DefenseTypeDebugStr[4] = "NORMAL" //Typically deals flat damage to all armor types
set udg_DefenseTypeDebugStr[5] = "HERO"
set udg_DefenseTypeDebugStr[6] = "DIVINE"
set udg_DefenseTypeDebugStr[7] = "UNARMORED"
set udg_ArmorTypeDebugStr[0] = "NONE" //ARMOR_TYPE_WHOKNOWS in JASS, added in 1.31
set udg_ArmorTypeDebugStr[1] = "FLESH"
set udg_ArmorTypeDebugStr[2] = "METAL"
set udg_ArmorTypeDebugStr[3] = "WOOD"
set udg_ArmorTypeDebugStr[4] = "ETHEREAL"
set udg_ArmorTypeDebugStr[5] = "STONE"
// -
// Added 25 July 2017 to allow detection of things like Bash or Pulverize or AOE spread
// -
set udg_DamageEventAOE = 1
set udg_DamageEventLevel = 1
// -
// In-game World Editor doesn't allow Attack Type and Damage Type comparisons. Therefore I need to code them as integers into GUI
// -
set udg_ATTACK_TYPE_SPELLS = 0
set udg_ATTACK_TYPE_NORMAL = 1
set udg_ATTACK_TYPE_PIERCE = 2
set udg_ATTACK_TYPE_SIEGE = 3
set udg_ATTACK_TYPE_MAGIC = 4
set udg_ATTACK_TYPE_CHAOS = 5
set udg_ATTACK_TYPE_HERO = 6
// -
set udg_DAMAGE_TYPE_UNKNOWN = 0
set udg_DAMAGE_TYPE_NORMAL = 4
set udg_DAMAGE_TYPE_ENHANCED = 5
set udg_DAMAGE_TYPE_FIRE = 8
set udg_DAMAGE_TYPE_COLD = 9
set udg_DAMAGE_TYPE_LIGHTNING = 10
set udg_DAMAGE_TYPE_POISON = 11
set udg_DAMAGE_TYPE_DISEASE = 12
set udg_DAMAGE_TYPE_DIVINE = 13
set udg_DAMAGE_TYPE_MAGIC = 14
set udg_DAMAGE_TYPE_SONIC = 15
set udg_DAMAGE_TYPE_ACID = 16
set udg_DAMAGE_TYPE_FORCE = 17
set udg_DAMAGE_TYPE_DEATH = 18
set udg_DAMAGE_TYPE_MIND = 19
set udg_DAMAGE_TYPE_PLANT = 20
set udg_DAMAGE_TYPE_DEFENSIVE = 21
set udg_DAMAGE_TYPE_DEMOLITION = 22
set udg_DAMAGE_TYPE_SLOW_POISON = 23
set udg_DAMAGE_TYPE_SPIRIT_LINK = 24
set udg_DAMAGE_TYPE_SHADOW_STRIKE = 25
set udg_DAMAGE_TYPE_UNIVERSAL = 26
// -
// The below variables don't affect damage amount, but do affect the sound played
// They also give important information about the type of attack used.
// They can differentiate between ranged and melee for units who are both
// -
set udg_WEAPON_TYPE_NONE = 0
// Metal Light/Medium/Heavy
set udg_WEAPON_TYPE_ML_CHOP = 1
set udg_WEAPON_TYPE_MM_CHOP = 2
set udg_WEAPON_TYPE_MH_CHOP = 3
set udg_WEAPON_TYPE_ML_SLICE = 4
set udg_WEAPON_TYPE_MM_SLICE = 5
set udg_WEAPON_TYPE_MH_SLICE = 6
set udg_WEAPON_TYPE_MM_BASH = 7
set udg_WEAPON_TYPE_MH_BASH = 8
set udg_WEAPON_TYPE_MM_STAB = 9
set udg_WEAPON_TYPE_MH_STAB = 10
// Wood Light/Medium/Heavy
set udg_WEAPON_TYPE_WL_SLICE = 11
set udg_WEAPON_TYPE_WM_SLICE = 12
set udg_WEAPON_TYPE_WH_SLICE = 13
set udg_WEAPON_TYPE_WL_BASH = 14
set udg_WEAPON_TYPE_WM_BASH = 15
set udg_WEAPON_TYPE_WH_BASH = 16
set udg_WEAPON_TYPE_WL_STAB = 17
set udg_WEAPON_TYPE_WM_STAB = 18
// Claw Light/Medium/Heavy
set udg_WEAPON_TYPE_CL_SLICE = 19
set udg_WEAPON_TYPE_CM_SLICE = 20
set udg_WEAPON_TYPE_CH_SLICE = 21
// Axe Medium
set udg_WEAPON_TYPE_AM_CHOP = 22
// Rock Heavy
set udg_WEAPON_TYPE_RH_BASH = 23
// -
// Since GUI still doesn't provide Defense Type and Armor Types, I needed to include the below
// -
set udg_ARMOR_TYPE_NONE = 0
set udg_ARMOR_TYPE_FLESH = 1
set udg_ARMOR_TYPE_METAL = 2
set udg_ARMOR_TYPE_WOOD = 3
set udg_ARMOR_TYPE_ETHEREAL = 4
set udg_ARMOR_TYPE_STONE = 5
// -
set udg_DEFENSE_TYPE_LIGHT = 0
set udg_DEFENSE_TYPE_MEDIUM = 1
set udg_DEFENSE_TYPE_HEAVY = 2
set udg_DEFENSE_TYPE_FORTIFIED = 3
set udg_DEFENSE_TYPE_NORMAL = 4
set udg_DEFENSE_TYPE_HERO = 5
set udg_DEFENSE_TYPE_DIVINE = 6
set udg_DEFENSE_TYPE_UNARMORED = 7
// -
set udg_UNIT_CLASS_HERO = 0
set udg_UNIT_CLASS_DEAD = 1
set udg_UNIT_CLASS_STRUCTURE = 2
// -
set udg_UNIT_CLASS_FLYING = 3
set udg_UNIT_CLASS_GROUND = 4
// -
set udg_UNIT_CLASS_ATTACKS_FLYING = 5
set udg_UNIT_CLASS_ATTACKS_GROUND = 6
// -
set udg_UNIT_CLASS_MELEE = 7
set udg_UNIT_CLASS_RANGED = 8
// -
set udg_UNIT_CLASS_GIANT = 9
set udg_UNIT_CLASS_SUMMONED = 10
set udg_UNIT_CLASS_STUNNED = 11
set udg_UNIT_CLASS_PLAGUED = 12
set udg_UNIT_CLASS_SNARED = 13
// -
set udg_UNIT_CLASS_UNDEAD = 14
set udg_UNIT_CLASS_MECHANICAL = 15
set udg_UNIT_CLASS_PEON = 16
set udg_UNIT_CLASS_SAPPER = 17
set udg_UNIT_CLASS_TOWNHALL = 18
set udg_UNIT_CLASS_ANCIENT = 19
// -
set udg_UNIT_CLASS_TAUREN = 20
set udg_UNIT_CLASS_POISONED = 21
set udg_UNIT_CLASS_POLYMORPHED = 22
set udg_UNIT_CLASS_SLEEPING = 23
set udg_UNIT_CLASS_RESISTANT = 24
set udg_UNIT_CLASS_ETHEREAL = 25
set udg_UNIT_CLASS_MAGIC_IMMUNE = 26
// -
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterRunChance = 1.00
endfunction
//===========================================================================
//
// Setup of automatic events from GUI and custom ones from JASS alike
//
//===========================================================================
public function RegisterFromHook takes trigger whichTrig, string var, limitop op, real value returns nothing
call DamageTrigger.registerVerbose(whichTrig, var, value, true, GetHandleId(op))
endfunction
hook TriggerRegisterVariableEvent RegisterFromHook
function TriggerRegisterDamageEngineEx takes trigger whichTrig, string eventName, real value, integer f returns DamageTrigger
return DamageTrigger.registerVerbose(whichTrig, DamageTrigger.getVerboseStr(eventName), value, false, f)
endfunction
function TriggerRegisterDamageEngine takes trigger whichTrig, string eventName, real value returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes code c, string eventName, real value, integer f returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[c], eventName, value, f)
endfunction
//Similar to TriggerRegisterDamageEvent, although takes code instead of trigger as the first argument.
function RegisterDamageEngine takes code c, string eventName, real value returns DamageTrigger
return RegisterDamageEngineEx(c, eventName, value, FILTER_OTHER)
endfunction
//For GUI to tap into more powerful vJass event filtering:
//! textmacro DAMAGE_TRIGGER_CONFIG
if not DamageTrigger.eventIndex.configured then
//! endtextmacro
//! textmacro DAMAGE_TRIGGER_CONFIG_END
call DamageTrigger.eventIndex.configure()
endif
if not DamageTrigger.eventIndex.checkConfig() then
return
endif
//! endtextmacro
endlibrary
native GetUnitGoldCost takes integer unitid returns integer
native GetUnitWoodCost takes integer unitid returns integer
native UnitAlive takes unit u returns boolean
library Core
globals
string MineralsTextColor = "|c00808080"
string HydrogenTextColor = "|c000080FF"
endglobals
private function Debug takes string message returns nothing
call DisplayTextToPlayer(Player(0), 0, 0, message)
endfunction
function FirstPlayer takes nothing returns player
local integer p = 0
loop
exitwhen GetPlayerController(Player(p)) == MAP_CONTROL_USER or p >= bj_MAX_PLAYERS
set p = p + 1
endloop
return Player(p)
endfunction
function B2S takes boolean b returns string
if(b)then
return "true"
endif
return "false"
endfunction
function IsUnitInSight takes unit u, player p returns boolean
return IsVisibleToPlayer(GetUnitX(u), GetUnitY(u), p)
endfunction
function IsArmyUnit takes unit u returns boolean
if(IsUnitType(u, UNIT_TYPE_STRUCTURE))then
return false // ignore structure
endif
if(IsUnitType(u, UNIT_TYPE_PEON))then
return false // ignore builders/harvesters/probes
endif
if(IsUnitType(u, UNIT_TYPE_ATTACKS_GROUND) == false and IsUnitType(u, UNIT_TYPE_ATTACKS_FLYING) == false)then
return false // ignore builders/harvesters/probes
endif
if(GetUnitCurrentOrder(u) == OrderId("holdposition") or GetUnitCurrentOrder(u) == OrderId("attackground") or GetUnitCurrentOrder(u) == OrderId("firebolt"))then
return false // ignore ships on hold position or bombarding
endif
return true
endfunction
function TriggerRegisterAnyPlayerEvent takes trigger t, playerevent eventType returns nothing
local integer i = 0
loop
call TriggerRegisterPlayerEvent(t, Player(i), eventType)
set i = i + 1
exitwhen i == bj_MAX_PLAYERS
endloop
endfunction
function TrimPlayerName takes string name returns string
local integer n = StringLength(name)
loop
exitwhen n < 0
if(SubString(name, n, n + 1) == "#")then
return SubString(name, 0, n)
endif
set n = n - 1
endloop
return name
endfunction
function PlayerColorToText takes playercolor c returns string
if c == PLAYER_COLOR_RED then
return "|cffff0303"
elseif c == PLAYER_COLOR_BLUE then
return "|cff0042ff"
elseif c == PLAYER_COLOR_CYAN then
return "|cff1be7ba"
elseif c == PLAYER_COLOR_PURPLE then
return "|cff550081"
elseif c == PLAYER_COLOR_YELLOW then
return "|cfffefc00"
elseif c == PLAYER_COLOR_ORANGE then
return "|cfffe890d"
elseif c == PLAYER_COLOR_GREEN then
return "|cff21bf00"
elseif c == PLAYER_COLOR_PINK then
return "|cffe45caf"
elseif c == PLAYER_COLOR_LIGHT_GRAY then
return "|cff939596"
elseif c == PLAYER_COLOR_LIGHT_BLUE then
return "|cff7ebff1"
elseif c == PLAYER_COLOR_AQUA then
return "|cff106247"
elseif c == PLAYER_COLOR_BROWN then
return "|cff4f2b05"
elseif c == PLAYER_COLOR_MAROON then
return "|cff9c0000"
elseif c == PLAYER_COLOR_NAVY then
return "|cff0000c3"
elseif c == PLAYER_COLOR_TURQUOISE then
return "|cff00ebff"
elseif c == PLAYER_COLOR_VIOLET then
return "|cffbd00ff"
elseif c == PLAYER_COLOR_WHEAT then
return "|cffecce87"
elseif c == PLAYER_COLOR_PEACH then
return "|cfff7a58b"
elseif c == PLAYER_COLOR_MINT then
return "|cffbfff81"
elseif c == PLAYER_COLOR_LAVENDER then
return "|cffdbb8eb"
elseif c == PLAYER_COLOR_COAL then
return "|cff4f5055"
elseif c == PLAYER_COLOR_SNOW then
return "|cffecf0ff"
elseif c == PLAYER_COLOR_EMERALD then
return "|cff00781e"
elseif c == PLAYER_COLOR_PEANUT then
return "|cffa56f34"
endif
return "|cff2e2d2e"
endfunction
function cs2s takes string name, playercolor c returns string
return PlayerColorToText(c) + TrimPlayerName(name) + "|r"
endfunction
function c2s takes player p returns string
return cs2s(GetPlayerName(p), GetPlayerColor(p)) + ": "
endfunction
function GetColoredPlayerName takes player p returns string
return cs2s(GetPlayerName(p), GetPlayerColor(p))
endfunction
function PlayerChatAll takes player p, string msg returns nothing
call PlaySound("Sound\\Interface\\InGameChatWhat1.wav")
call DisplayTimedTextFromPlayer(p, 0, 0, 5, c2s(p) + msg)
endfunction
function GetResourceString takes integer minerals, integer hydrogen returns string
if(minerals != 0 and hydrogen!= 0)then
return MineralsTextColor + "+" + I2S(minerals) + "\n" + HydrogenTextColor + "+" + I2S(hydrogen)
endif
if(minerals != 0)then
return MineralsTextColor + "+" + I2S(minerals)
endif
if(hydrogen!= 0)then
return HydrogenTextColor + "+" + I2S(hydrogen)
endif
// should not happen
return null
endfunction
function ShowResourceText takes player p, unit u, integer minerals, integer hydrogen returns nothing
local texttag tt = null
if(p != GetLocalPlayer())then
return
endif
set tt = CreateTextTag()
call SetTextTagPos(tt, GetUnitX(u), GetUnitY(u), 100)
call SetTextTagText(tt, GetResourceString(minerals, hydrogen), TextTagSize2Height(10))
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 2)
call SetTextTagFadepoint(tt, 1.7)
call SetTextTagVelocity(tt, 0, TextTagSpeed2Velocity(64))
set tt = null
endfunction
function OrderRally takes unit rallySource, unit rallyUnit returns nothing
local location loc
if(GetUnitRallyUnit(rallySource) != null)then
call IssueTargetOrder(rallyUnit, "smart", GetUnitRallyUnit(rallySource))
elseif(GetUnitRallyDestructable(rallySource) != null)then
call IssueTargetOrder(rallyUnit, "smart", GetUnitRallyDestructable(rallySource))
else
set loc = GetUnitRallyPoint(rallySource)
call IssuePointOrderLoc(rallyUnit, "attack", loc)
call RemoveLocation(loc)
set loc = null
endif
endfunction
endlibrary
library QuickSortLib// initializer TestQuickSortLib
// QuickSort using Hoare partition scheme
type IArray extends integer array [100]
type IUnitArray extends unit array [100]
type ITreeArray extends destructable array [100]
function ArrayToString takes IArray values, integer start, integer end returns string
local string output = I2S(values[start])
local integer i = 1
loop
exitwhen i > end
set output = output + ", " + I2S(values[i])
set i = i + 1
endloop
return output
endfunction
function AssocArrayToString takes IArray keys, IArray values, integer start, integer end returns string
local string output = I2S(keys[start]) + ":" + I2S(values[start])
local integer i = 1
loop
exitwhen i > end
set output = output + ", " + I2S(keys[i]) + ":" + I2S(values[i])
set i = i + 1
endloop
return output
endfunction
function AssocUnitArrayToString takes IUnitArray keys, IArray values, integer start, integer end returns string
local string output = GetUnitName(keys[start]) + ":" + I2S(values[start])
local integer i = 1
loop
exitwhen i > end
set output = output + ", " + GetUnitName(keys[i]) + ":" + I2S(values[i])
set i = i + 1
endloop
return output
endfunction
function AssocTreeArrayToString takes ITreeArray keys, IArray values, integer start, integer end returns string
local string output = GetDestructableName(keys[start]) + ":" + I2S(values[start])
local integer i = 1
loop
exitwhen i > end
set output = output + ", " + GetDestructableName(keys[i]) + ":" + I2S(values[i])
set i = i + 1
endloop
return output
endfunction
function ArraySort takes IArray values, integer start, integer end returns nothing
local integer pivotIndex = (start + end) / 2
local integer pivot = values[pivotIndex]
local integer iS = start
local integer iE = end
local integer tempI
if(start >= end)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion ended")
return // end recursion
endif
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - start with pivot "+ I2S(values[pivotIndex]) + "[" + I2S(pivotIndex) + "]")
loop
exitwhen iS > iE
if((values[iS] > pivot and values[iE] <= pivot) or (values[iE] < pivot and values[iS] >= pivot))then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - switching " + I2S(values[iS]) + "[" + I2S(iS) + "] with " + I2S(values[iE]) + "[" + I2S(iE) + "]")
set tempI = values[iS]
set values[iS] = values[iE]
set values[iE] = tempI
endif
if(values[iS] <= pivot and iS < end)then
set iS = iS + 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer moved to " + I2S(values[iS]) + "[" + I2S(iS) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer stuck at " + I2S(values[iS]) + "[" + I2S(iS) + "] > " + I2S(pivot))
endif
if(values[iE] >= pivot and iE > start)then
set iE = iE - 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer moved to " + I2S(values[iE]) + "[" + I2S(iE) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer stuck at " + I2S(values[iE]) + "[" + I2S(iE) + "] < " + I2S(pivot))
endif
endloop
if(start == iS and end == iE)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion stuck?")
return // end recursion
endif
call ArraySort(values, start, iE)
call ArraySort(values, iS, end)
endfunction
function AssocArraySort takes IArray keys, IArray values, integer start, integer end returns nothing
local integer pivotIndex = (start + end) / 2
local integer pivot = values[pivotIndex]
local integer iS = start
local integer iE = end
local integer tempI
if(start >= end)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion ended")
return // end recursion
endif
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - start with pivot "+ I2S(values[pivotIndex]) + "[" + I2S(pivotIndex) + "]")
loop
exitwhen iS > iE
if((values[iS] > pivot and values[iE] <= pivot) or (values[iE] < pivot and values[iS] >= pivot))then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - switching " + I2S(values[iS]) + "[" + I2S(iS) + "] with " + I2S(values[iE]) + "[" + I2S(iE) + "]")
set tempI = values[iS]
set values[iS] = values[iE]
set values[iE] = tempI
set tempI = keys[iS]
set keys[iS] = keys[iE]
set keys[iE] = tempI
endif
if(values[iS] <= pivot and iS < end)then
set iS = iS + 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer moved to " + I2S(values[iS]) + "[" + I2S(iS) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer stuck at " + I2S(values[iS]) + "[" + I2S(iS) + "] > " + I2S(pivot))
endif
if(values[iE] >= pivot and iE > start)then
set iE = iE - 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer moved to " + I2S(values[iE]) + "[" + I2S(iE) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer stuck at " + I2S(values[iE]) + "[" + I2S(iE) + "] < " + I2S(pivot))
endif
endloop
if(start == iS and end == iE)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion stuck?")
return // end recursion
endif
call AssocArraySort(keys, values, start, iE)
call AssocArraySort(keys, values, iS, end)
endfunction
function AssocUnitArraySort takes IUnitArray keys, IArray values, integer start, integer end returns nothing
local integer pivotIndex = (start + end) / 2
local integer pivot = values[pivotIndex]
local integer iS = start
local integer iE = end
local integer tempI
local unit tempU
if(start >= end)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion ended")
return // end recursion
endif
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - start with pivot "+ I2S(values[pivotIndex]) + "[" + I2S(pivotIndex) + "]")
loop
exitwhen iS > iE
if((values[iS] > pivot and values[iE] <= pivot) or (values[iE] < pivot and values[iS] >= pivot))then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - switching " + I2S(values[iS]) + "[" + I2S(iS) + "] with " + I2S(values[iE]) + "[" + I2S(iE) + "]")
set tempI = values[iS]
set values[iS] = values[iE]
set values[iE] = tempI
set tempU = keys[iS]
set keys[iS] = keys[iE]
set keys[iE] = tempU
set tempU = null
endif
if(values[iS] <= pivot and iS < end)then
set iS = iS + 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer moved to " + I2S(values[iS]) + "[" + I2S(iS) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer stuck at " + I2S(values[iS]) + "[" + I2S(iS) + "] > " + I2S(pivot))
endif
if(values[iE] >= pivot and iE > start)then
set iE = iE - 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer moved to " + I2S(values[iE]) + "[" + I2S(iE) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer stuck at " + I2S(values[iE]) + "[" + I2S(iE) + "] < " + I2S(pivot))
endif
endloop
if(start == iS and end == iE)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion stuck?")
return // end recursion
endif
call AssocUnitArraySort(keys, values, start, iE)
call AssocUnitArraySort(keys, values, iS, end)
endfunction
function AssocTreeArraySort takes ITreeArray keys, IArray values, integer start, integer end returns nothing
local integer pivotIndex = (start + end) / 2
local integer pivot = values[pivotIndex]
local integer iS = start
local integer iE = end
local integer tempI
local destructable tempD
if(start >= end)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion ended")
return // end recursion
endif
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - start with pivot "+ I2S(values[pivotIndex]) + "[" + I2S(pivotIndex) + "]")
loop
exitwhen iS > iE
if((values[iS] > pivot and values[iE] <= pivot) or (values[iE] < pivot and values[iS] >= pivot))then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - switching " + I2S(values[iS]) + "[" + I2S(iS) + "] with " + I2S(values[iE]) + "[" + I2S(iE) + "]")
set tempI = values[iS]
set values[iS] = values[iE]
set values[iE] = tempI
set tempD = keys[iS]
set keys[iS] = keys[iE]
set keys[iE] = tempD
set tempD = null
endif
if(values[iS] <= pivot and iS < end)then
set iS = iS + 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer moved to " + I2S(values[iS]) + "[" + I2S(iS) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - start pointer stuck at " + I2S(values[iS]) + "[" + I2S(iS) + "] > " + I2S(pivot))
endif
if(values[iE] >= pivot and iE > start)then
set iE = iE - 1
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer moved to " + I2S(values[iE]) + "[" + I2S(iE) + "]")
else
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort - end pointer stuck at " + I2S(values[iE]) + "[" + I2S(iE) + "] < " + I2S(pivot))
endif
endloop
if(start == iS and end == iE)then
//call DisplayTextToPlayer(Player(0), 0, 0, "ArraySort [" + I2S(start) + ":" + I2S(end) + "] - recursion stuck?")
return // end recursion
endif
call AssocTreeArraySort(keys, values, start, iE)
call AssocTreeArraySort(keys, values, iS, end)
endfunction
private function RunTestQuickSortLib takes nothing returns nothing
local IArray k = IArray.create()
local IArray v = IArray.create()
set k[0] = 0
set k[1] = 1
set k[2] = 2
set k[3] = 3
set k[4] = 4
set k[5] = 5
set k[6] = 6
set v[0] = 10
set v[1] = 5
set v[2] = 15
set v[3] = 5
set v[4] = 9999
set v[5] = -1
set v[6] = 15
call DisplayTextToPlayer(Player(0), 0, 0, AssocArrayToString(k, v, 0, 6))
call AssocArraySort(k, v, 0, 6)
call DisplayTextToPlayer(Player(0), 0, 0, AssocArrayToString(k, v, 0, 6))
endfunction
private function TestQuickSortLib takes nothing returns nothing
/*local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t, 1, false)
call TriggerAddAction(t, function RunTestQuickSortLib)
set t = null*/
endfunction
endlibrary
library MathLib initializer InitMath
private function Debug takes string s returns nothing
call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
function PolarProjectionX takes real x, real dist, real angle returns real
return x + dist * Cos(angle * bj_DEGTORAD)
endfunction
function PolarProjectionY takes real y, real dist, real angle returns real
return y + dist * Sin(angle * bj_DEGTORAD)
endfunction
function AngleBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
return bj_RADTODEG * Atan2(y2 - y1, x2 - x1)
endfunction
function DistanceBetweenCoordinatesSquared takes real x1, real y1, real x2, real y2 returns real
local real a = x2 - x1
local real b = y2 - y1
return (a*a) + (b*b)
endfunction
function DistanceBetweenCoordinates takes real x1, real y1, real x2, real y2 returns real
local real a = x2 - x1
local real b = y2 - y1
return SquareRoot((a*a) + (b*b))
endfunction
function IsWithinDistance takes real x1, real y1, real x2, real y2, real distance returns boolean
return DistanceBetweenCoordinatesSquared(x1, y1, x2, y2) < distance * distance
endfunction
function AngleSimilarityRadian takes real a0, real a1 returns real
local real x0 = Cos(a0)
local real y0 = Sin(a0)
local real x1 = Cos(a1)
local real y1 = Sin(a1)
return x0*x1 + y0*y1
endfunction
function AngleSimilarity takes real a0, real a1 returns real
return AngleSimilarityRadian(a0 * bj_DEGTORAD - bj_PI, a1 * bj_DEGTORAD - bj_PI)
endfunction
function AngleDifference takes real a, real b returns real
local real d = ModuloReal(b, 360) - ModuloReal(a, 360)
if(d > 180)then
return d - 360
elseif(d < -180)then
return 360 + d
endif
return d
endfunction
function AngleLerpFixed takes real a, real b, real step returns real
local real delta
local real deltaAbs
local real sign
if(b == a)then
return b
endif
set delta = AngleDifference(a, b)
set deltaAbs = RAbsBJ(delta)
if(deltaAbs <= step)then
return b
endif
set sign = RAbsBJ(delta) / delta
return a + step * sign
endfunction
// Ahhh, sweet man-made horrors beyond my comprehension https://gist.github.com/shaunlebron/8832585
globals
private constant real MaxAngle = bj_PI * 2
endglobals
function AngleDelta takes real a0, real a1 returns real
return ModuloReal(a1* bj_DEGTORAD - a0* bj_DEGTORAD, MaxAngle)
endfunction
function AngleLerp takes real a0, real a1, real t returns real
local real da = AngleDelta(a0, a1)
return (a0 * bj_DEGTORAD + (ModuloReal(2 * da, MaxAngle) - da) * t) * bj_RADTODEG
endfunction
private function AssertEqual takes real a, real b returns nothing
if(a == b)then
return
endif
call Debug ("AssertEqual FAILED " + R2S(a) + " != " + R2S(b))
endfunction
private function AssertTrue takes boolean b returns nothing
if(b)then
return
endif
call Debug ("AssertTrue FAILED")
endfunction
private function RunTests takes nothing returns nothing
call Debug("AngleDifference")
call AssertEqual(45, AngleDifference(0, 45))
call AssertEqual(-45, AngleDifference(45, 0))
call AssertEqual(45, AngleDifference(315, 360))
call AssertEqual(-45, AngleDifference(360, 315))
call AssertEqual(45, AngleDifference(315, 0))
call AssertEqual(-45, AngleDifference(0, 315))
call AssertEqual(0, AngleDifference(0, 0))
call AssertEqual(0, AngleDifference(0, 360))
call AssertEqual(0, AngleDifference(360, 360))
call AssertEqual(0, AngleDifference(380, 20))
call AssertEqual(0, AngleDifference(20, 380))
call AssertEqual(20, AngleDifference(350, 10))
call AssertEqual(-20, AngleDifference(10, 350))
call AssertEqual(180, AngleDifference(0, 180))
call AssertEqual(-180, AngleDifference(180, 0))
call Debug("AngleLerpFixed")
call AssertEqual(360, AngleLerpFixed(360, 360, 0))
call AssertEqual(360, AngleLerpFixed(360, 360, 2))
call AssertEqual(360, AngleLerpFixed(360, 360, 180))
call AssertEqual(360, AngleLerpFixed(360, 360, 360))
call AssertEqual(360, AngleLerpFixed(355, 360, 5))
call AssertEqual(360, AngleLerpFixed(365, 360, 5))
call AssertEqual(0, AngleLerpFixed(5, 0, 5))
call AssertEqual(355, AngleLerpFixed(360, 355, 5))
call AssertEqual(365, AngleLerpFixed(360, 365, 5))
call AssertEqual(5, AngleLerpFixed(0, 5, 5))
call AssertEqual(357, AngleLerpFixed(355, 360, 2))
call AssertEqual(363, AngleLerpFixed(365, 360, 2))
call AssertEqual(3, AngleLerpFixed(5, 0, 2))
call AssertEqual(358, AngleLerpFixed(360, 355, 2))
call AssertEqual(362, AngleLerpFixed(360, 365, 2))
call AssertEqual(2, AngleLerpFixed(0, 5, 2))
endfunction
private function InitMath takes nothing returns nothing
//call RunTests()
endfunction
endlibrary
library WeightedRandomLib requires CollectionLib
struct ValueWeight
integer value
integer weight
static method create takes integer value, integer weight returns thistype
local thistype this = thistype.allocate()
set this.value = value
set this.weight = weight
return this
endmethod
static method Destroy takes thistype this returns nothing
call this.destroy()
endmethod
endstruct
struct WeightedRandom
Collection c
integer totalWeight
method Add takes integer value, integer weight returns nothing
call c.Append(ValueWeight.create(value, weight))
endmethod
method Roll takes nothing returns integer
local integer roll = GetRandomInt(0, totalWeight)
local CollectionIterator it = this.c.GetIterator()
local ValueWeight vw
loop
exitwhen it.Next() == false
set vw = it.Value()
if(roll <= vw.weight)then
return vw.value
endif
set roll = roll - vw.weight
endloop
return this.c.GetRandomValue()
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.c = Collection.create(ValueWeight.Destroy)
set this.totalWeight = 0
return this
endmethod
method destroy takes nothing returns nothing
call this.c.destroy()
call this.deallocate()
endmethod
endstruct
endlibrary
library CollectionLib requires QuickSortLib
function interface ISelector takes integer a returns integer
function interface IFilter takes integer a returns boolean
function interface IAction takes integer a returns nothing
function interface IDispose takes integer a returns nothing
struct CollectionIterator
readonly boolean endOfCollection
readonly integer index
readonly integer value
private Collection c
private integer originalCount
method EndOfCollection takes nothing returns boolean
return this.endOfCollection
endmethod
method Index takes nothing returns integer
return this.index
endmethod
method Value takes nothing returns integer
return this.value
endmethod
method Next takes nothing returns boolean
if(this.originalCount != this.c.Count())then
// collection has been tempered with!
set this.endOfCollection = true
endif
if(this.endOfCollection)then
return false
endif
set this.index = this.index + 1
if(this.index == this.c.Count())then
set this.endOfCollection = true
return false
endif
set this.value = this.c[this.index]
return true
endmethod
method Reset takes nothing returns nothing
set this.endOfCollection = c.IsEmpty()
set this.index = -1
set this.value = 0
set this.originalCount = this.c.Count()
endmethod
static method create takes Collection c returns thistype
local thistype this = thistype.allocate()
set this.c = c
call this.Reset()
return this
endmethod
endstruct
struct Collection
private static hashtable ht = InitHashtable()
readonly static integer SORT_ASC = 1
readonly static integer SORT_DESC = -1
private integer count
IDispose onDispose
private CollectionIterator iterator
method Count takes nothing returns integer
return this.count
endmethod
method GetIterator takes nothing returns CollectionIterator
call this.iterator.Reset()
return this.iterator
endmethod
method IndexOf takes integer entry returns integer
local integer i = 0
loop
exitwhen i == this.count
if(this[i] == entry)then
return i
endif
set i = i + 1
endloop
return -1
endmethod
method operator [] takes integer index returns integer
return LoadInteger(thistype.ht, this, index)
endmethod
method FirstOrDefault takes nothing returns integer
if(this.count > 0)then
return this[0]
endif
return 0
endmethod
method LastOrDefault takes nothing returns integer
if(this.count > 0)then
return this[this.count - 1]
endif
return 0
endmethod
method IsEmpty takes nothing returns boolean
return this.count == 0
endmethod
method Shift takes integer index returns nothing
local integer i = this.count
if(index < 0)then
return // nothing to do
endif
loop
exitwhen i == index
call SaveInteger(thistype.ht, this, i, LoadInteger(thistype.ht, this, i - 1)) // move previous value to current index
set i = i + 1
endloop
set this.count = this.count + 1
endmethod
method Unshift takes integer index returns nothing
local integer i = index
if(index >= this.count)then
return // nothing to do
endif
call RemoveSavedInteger(thistype.ht, this, index) // destroy next value
loop
exitwhen i + 1 >= this.count
//call DisplayTextToPlayer(Player(0), 0, 0, "unshift " + I2S(index) + ":" + I2S(i))
call SaveInteger(thistype.ht, this, i, LoadInteger(thistype.ht, this, i + 1)) // move next value to current index
call RemoveSavedInteger(thistype.ht, this, i + 1) // destroy next value
set i = i + 1
endloop
set this.count = this.count - 1
endmethod
method Remove takes integer index returns thistype
if(this.onDispose != 0)then
call this.onDispose.execute(this[index])
endif
call this.Unshift(index) // move everything to the left, freeing the last index and decreasing the collection size
return this
endmethod
method Append takes integer entry returns thistype
call SaveInteger(thistype.ht, this, this.count, entry)
set this.count = this.count + 1
return this
endmethod
method Prepend takes integer entry returns thistype
call this.Shift(0) // move everything to the right, freeing index 0 and increasing the collection size
call SaveInteger(thistype.ht, this, 0, entry)
return this
endmethod
method Clear takes nothing returns nothing
loop
exitwhen this.count == 0
call this.Remove(this.count - 1)
endloop
call FlushChildHashtable(thistype.ht, this)
endmethod
method Copy takes Collection c returns thistype
call this.Clear()
loop
exitwhen this.count == c.count
call this.Append(c[this.count])
endloop
return this
endmethod
method Clone takes nothing returns thistype
local thistype output = thistype.create(0)
call output.Copy(this)
return output
endmethod
method Sum takes ISelector s returns integer
local integer output = 0
local integer i = 0
loop
exitwhen i == this.count
set output = output + s.evaluate(this[i])
set i = i + 1
endloop
return output
endmethod
method Min takes ISelector s returns integer
local integer output = 999999
local integer i = 0
loop
exitwhen i == this.count
set output = IMinBJ(output, s.evaluate(this[i]))
set i = i + 1
endloop
return output
endmethod
method Max takes ISelector s returns integer
local integer output = -999999
local integer i = 0
loop
exitwhen i == this.count
set output = IMaxBJ(output, s.evaluate(this[i]))
set i = i + 1
endloop
return output
endmethod
method Average takes ISelector s returns integer
if(this.count == 0)then
return 0
endif
return this.Sum(s) / this.count
endmethod
method ForEach takes IAction a returns thistype
local integer i = 0
loop
exitwhen i == this.count
call a.execute(this[i])
set i = i + 1
endloop
return this
endmethod
method Any takes IFilter f returns boolean
local integer i = this.count - 1
loop
exitwhen i < 0
if(f.evaluate(this[i]))then
return true
endif
set i = i - 1
endloop
return false
endmethod
method All takes IFilter f returns boolean
local integer i = this.count - 1
loop
exitwhen i < 0
if(f.evaluate(this[i]) == false)then
return false
endif
set i = i - 1
endloop
return true
endmethod
method Filter takes IFilter f returns thistype
local integer i = this.count - 1
loop
exitwhen i < 0
//call DisplayTextToPlayer(Player(0), 0, 0, "Filter " + I2S(i))
if(f.evaluate(this[i]) == false)then
//call DisplayTextToPlayer(Player(0), 0, 0, "REMOVING " + I2S(i))
call this.Remove(i)
endif
set i = i - 1
endloop
return this
endmethod
method Sort takes ISelector s, integer direction returns thistype
local IArray keys = IArray.create()
local IArray values = IArray.create()
local integer i
set i = 0
loop
exitwhen i == this.count
set keys[i] = this[i]
set values[i] = s.evaluate(keys[i])
set i = i + 1
endloop
call AssocArraySort(keys, values, 0, this.count - 1)
set i = 0
loop
exitwhen i == this.count
if(direction == thistype.SORT_ASC)then
call SaveInteger(thistype.ht, this, i, keys[i])
else
call SaveInteger(thistype.ht, this, (this.count - 1) - i, keys[i])
endif
set i = i + 1
endloop
call keys.destroy()
call values.destroy()
return this
endmethod
method SortBy takes ISelector s returns thistype
return this.Sort(s, thistype.SORT_ASC)
endmethod
method SortByDesc takes ISelector s returns thistype
return this.Sort(s, thistype.SORT_DESC)
endmethod
static method ShuffleSelector takes integer a returns integer
return GetRandomInt(1,100)
endmethod
method Shuffle takes nothing returns thistype
return this.Sort(thistype.ShuffleSelector, thistype.SORT_ASC)
endmethod
method GetRandomValue takes nothing returns integer
if(this.count == 0)then
return 0
endif
return this[GetRandomInt(0, this.count - 1)]
endmethod
static method create takes IDispose onDispose returns thistype
local thistype this = thistype.allocate()
set this.count = 0
set this.onDispose = onDispose
set this.iterator = CollectionIterator.create(this)
return this
endmethod
method destroy takes nothing returns nothing
call this.Clear()
call this.iterator.destroy()
call this.deallocate()
endmethod
endstruct
endlibrary
library UnitCollectionLib initializer TestUnitCollectionLib requires QuickSortLib
function interface IUnitSelector takes unit u returns integer
function interface IUnitFilter takes unit u returns boolean
function interface IUnitAction takes unit u returns nothing
struct UnitCollectionIterator
readonly boolean endOfCollection
readonly integer index
readonly unit value
private UnitCollection c
private integer originalCount
method EndOfCollection takes nothing returns boolean
return this.endOfCollection
endmethod
method Index takes nothing returns integer
return this.index
endmethod
method Value takes nothing returns unit
return this.value
endmethod
method Next takes nothing returns boolean
if(this.originalCount != this.c.Count())then
// collection has been tempered with!
set this.endOfCollection = true
endif
if(this.endOfCollection)then
return false
endif
set this.index = this.index + 1
if(this.index == this.c.Count())then
set this.endOfCollection = true
return false
endif
set this.value = this.c[this.index]
return true
endmethod
method Reset takes nothing returns nothing
set this.endOfCollection = c.IsEmpty()
set this.index = -1
set this.value = null
set this.originalCount = this.c.Count()
endmethod
static method create takes UnitCollection c returns thistype
local thistype this = thistype.allocate()
set this.c = c
call this.Reset()
return this
endmethod
method destroy takes nothing returns nothing
set this.value = null
call this.deallocate()
endmethod
endstruct
struct UnitCollection
private static hashtable ht = InitHashtable()
readonly static integer SORT_ASC = 1
readonly static integer SORT_DESC = -1
private integer count
private UnitCollectionIterator iterator
private group g
method GetIterator takes nothing returns UnitCollectionIterator
call this.iterator.Reset()
return this.iterator
endmethod
method Count takes nothing returns integer
return this.count
endmethod
method CountWhere takes IUnitFilter filter returns integer
local integer output = 0
local integer i = 0
loop
exitwhen i == this.count
if(filter.evaluate(this[i]))then
set output = output + 1
endif
set i = i + 1
endloop
return output
endmethod
method IndexOf takes unit entry returns integer
local integer i = 0
loop
exitwhen i == this.count
if(this[i] == entry)then
return i
endif
set i = i + 1
endloop
return -1
endmethod
method operator [] takes integer index returns unit
return LoadUnitHandle(thistype.ht, this, index)
endmethod
method FirstOrDefault takes nothing returns unit
if(this.count > 0)then
return this[0]
endif
return null
endmethod
method LastOrDefault takes nothing returns unit
if(this.count > 0)then
return this[this.count - 1]
endif
return null
endmethod
method IsEmpty takes nothing returns boolean
return this.count == 0
endmethod
method Shift takes integer index returns nothing
local integer i = this.count
if(index < 0)then
return // nothing to do
endif
loop
exitwhen i == index
call SaveUnitHandle(thistype.ht, this, i, LoadUnitHandle(thistype.ht, this, i - 1)) // move previous value to current index
set i = i + 1
endloop
set this.count = count + 1
endmethod
method Unshift takes integer index returns nothing
local integer i = index
if(index >= count)then
return // nothing to do
endif
call GroupRemoveUnit(this.g, LoadUnitHandle(thistype.ht, this, index))
call RemoveSavedHandle(thistype.ht, this, index) // destroy next value
loop
exitwhen i + 1 == this.count
call SaveUnitHandle(thistype.ht, this, i, LoadUnitHandle(thistype.ht, this, i + 1)) // move next value to current index
call RemoveSavedHandle(thistype.ht, this, i + 1) // destroy next value
set i = i + 1
endloop
set this.count = count - 1
endmethod
method Remove takes integer index returns thistype
call this.Unshift(index) // move everything to the left, freeing the last index and decreasing the collection size
return this
endmethod
method Append takes unit entry returns thistype
call SaveUnitHandle(thistype.ht, this, this.count, entry)
set this.count = count + 1
return this
endmethod
method Prepend takes unit entry returns thistype
call this.Shift(0) // move everything to the right, freeing index 0 and increasing the collection size
call SaveUnitHandle(thistype.ht, this, 0, entry)
return this
endmethod
method AddGroup takes group g returns thistype
local group tg
local unit u = null
if(g == null or FirstOfGroup(g) == null)then
return this
endif
set tg = CreateGroup()
call GroupAddGroup(g, tg)
loop
set u = FirstOfGroup(tg)
exitwhen u == null
call this.Append(u)
call GroupRemoveUnit(tg, u)
endloop
call DestroyGroup(tg)
set tg = null
set u = null
return this
endmethod
method Clear takes nothing returns nothing
call FlushChildHashtable(thistype.ht, this)
call GroupClear(this.g)
set this.count = 0
endmethod
method Copy takes UnitCollection c returns thistype
call this.Clear()
loop
exitwhen this.count == c.count
call this.Append(c[this.count])
endloop
return this
endmethod
method Clone takes nothing returns thistype
local thistype output = thistype.create(null)
call output.Copy(this)
return output
endmethod
method Sum takes IUnitSelector s returns integer
local integer output = 0
local integer i = this.count - 1
loop
exitwhen i == 0
set output = output + s.evaluate(this[i])
set i = i - 1
endloop
return output
endmethod
method Average takes IUnitSelector s returns integer
if(this.count == 0)then
return 0
endif
return this.Sum(s) / this.count
endmethod
method ForEach takes IUnitAction a returns thistype
local integer i = 0
loop
exitwhen i == this.count
call a.execute(this[i])
set i = i + 1
endloop
return this
endmethod
method Any takes IUnitFilter f returns boolean
local integer i = this.count - 1
loop
exitwhen i < 0
if(f.evaluate(this[i]) == true)then
return true
endif
set i = i - 1
endloop
return false
endmethod
method Filter takes IUnitFilter f returns thistype
local integer i = this.count - 1
loop
exitwhen i < 0
//call DisplayTextToPlayer(Player(0), 0, 0, "Filter " + I2S(i))
if(f.evaluate(this[i]) == false)then
//call DisplayTextToPlayer(Player(0), 0, 0, "REMOVING " + I2S(i))
call this.Remove(i)
endif
set i = i - 1
endloop
return this
endmethod
method Sort takes IUnitSelector s, integer direction returns thistype
local IUnitArray keys = IUnitArray.create()
local IArray values = IArray.create()
local integer i
set i = 0
loop
exitwhen i == this.count
set keys[i] = this[i]
set values[i] = s.evaluate(keys[i])
set i = i + 1
endloop
call AssocUnitArraySort(keys, values, 0, this.count - 1)
set i = 0
loop
exitwhen i == this.count
if(direction == thistype.SORT_ASC)then
call SaveUnitHandle(thistype.ht, this, i, keys[i])
else
call SaveUnitHandle(thistype.ht, this, (this.count - 1) - i, keys[i])
endif
set i = i + 1
endloop
call keys.destroy()
call values.destroy()
return this
endmethod
method SortBy takes IUnitSelector s returns thistype
return this.Sort(s, thistype.SORT_ASC)
endmethod
method SortByDesc takes IUnitSelector s returns thistype
return this.Sort(s, thistype.SORT_DESC)
endmethod
static method create takes group g returns thistype
local thistype this = thistype.allocate()
set this.count = 0
set this.g = CreateGroup()
set this.iterator = UnitCollectionIterator.create(this)
call this.AddGroup(g)
return this
endmethod
method destroy takes nothing returns nothing
call this.Clear()
call this.iterator.destroy()
call this.deallocate()
endmethod
endstruct
function PercentHealthUnitSelector takes unit u returns integer
return R2I(100 * GetUnitState(u, UNIT_STATE_LIFE) / GetUnitState(u, UNIT_STATE_MAX_LIFE))
endfunction
function PrintNameHealthUnitAction takes unit u returns nothing
call DisplayTextToPlayer(Player(0), 0, 0, "-" + GetUnitName(u) + " " + I2S(PercentHealthUnitSelector(u)) + " %%")
endfunction
function RunTestUnitCollectionLib takes nothing returns nothing
local group g = CreateGroup()
local UnitCollection c
call GroupEnumUnitsOfPlayer(g, Player(0), null)
set c = UnitCollection.create(g)
call DisplayTextToPlayer(Player(0), 0, 0, "Before sort")
call c.ForEach(PrintNameHealthUnitAction)
call c.SortBy(PercentHealthUnitSelector)
call DisplayTextToPlayer(Player(0), 0, 0, "After sort")
call c.ForEach(PrintNameHealthUnitAction)
endfunction
function TestUnitCollectionLib takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t, 1, false)
//call TriggerAddAction(t, function RunTestUnitCollectionLib)
set t = null
endfunction
globals
private real f_GetUnitDistance_x
private real f_GetUnitDistance_y
private real f_IsUnitInRadius_radius
private integer f_IsUnitOrder_orderId
private integer f_IsUnitType_typeId
endglobals
private function GetUnitDistanceCallback takes unit u returns integer
return R2I(DistanceBetweenCoordinates(GetUnitX(u), GetUnitY(u), f_GetUnitDistance_x, f_GetUnitDistance_y))
endfunction
function GetDistanceUnitSelector takes real x, real y returns IUnitSelector
set f_GetUnitDistance_x = x
set f_GetUnitDistance_y = y
return GetUnitDistanceCallback
endfunction
native UnitAlive takes unit u returns boolean
function IsUnitAliveFilter takes unit u returns boolean
return GetUnitState(u, UNIT_STATE_LIFE) >= 1
endfunction
endlibrary
library TreeCollectionLib requires QuickSortLib
function interface ITreeSelector takes destructable d returns integer
function interface ITreeFilter takes destructable d returns boolean
function interface ITreeAction takes destructable d returns nothing
struct TreeCollectionIterator
readonly boolean endOfCollection
readonly integer index
readonly destructable value
private TreeCollection c
private integer originalCount
method EndOfCollection takes nothing returns boolean
return this.endOfCollection
endmethod
method Index takes nothing returns integer
return this.index
endmethod
method Value takes nothing returns destructable
return this.value
endmethod
method Next takes nothing returns boolean
if(this.originalCount != this.c.Count())then
// collection has been tempered with!
set this.endOfCollection = true
endif
if(this.endOfCollection)then
return false
endif
set this.index = this.index + 1
if(this.index == this.c.Count())then
set this.endOfCollection = true
return false
endif
set this.value = this.c[this.index]
return true
endmethod
method Reset takes nothing returns nothing
set this.endOfCollection = c.IsEmpty()
set this.index = -1
set this.value = null
set this.originalCount = this.c.Count()
endmethod
static method create takes TreeCollection c returns thistype
local thistype this = thistype.allocate()
set this.c = c
call this.Reset()
return this
endmethod
method destroy takes nothing returns nothing
set this.value = null
call this.deallocate()
endmethod
endstruct
struct TreeCollection
private static hashtable ht = InitHashtable()
readonly static integer SORT_ASC = 1
readonly static integer SORT_DESC = -1
private integer count
private TreeCollectionIterator iterator
method Count takes nothing returns integer
return this.count
endmethod
method GetIterator takes nothing returns TreeCollectionIterator
call this.iterator.Reset()
return this.iterator
endmethod
method IndexOf takes destructable entry returns integer
local integer i = 0
loop
exitwhen i == this.count
if(this[i] == entry)then
return i
endif
set i = i + 1
endloop
return -1
endmethod
method operator [] takes integer index returns destructable
return LoadDestructableHandle(thistype.ht, this, index)
endmethod
method FirstOrDefault takes nothing returns destructable
if(this.count > 0)then
return this[0]
endif
return null
endmethod
method LastOrDefault takes nothing returns destructable
if(this.count > 0)then
return this[this.count - 1]
endif
return null
endmethod
method IsEmpty takes nothing returns boolean
return this.count == 0
endmethod
method Shift takes integer index returns nothing
local integer i = this.count
if(index < 0)then
return // nothing to do
endif
loop
exitwhen i == index
call SaveDestructableHandle(thistype.ht, this, i, LoadDestructableHandle(thistype.ht, this, i - 1)) // move previous value to current index
set i = i + 1
endloop
set this.count = count + 1
endmethod
method Unshift takes integer index returns nothing
local integer i = index
if(index >= count)then
return // nothing to do
endif
call RemoveSavedHandle(thistype.ht, this, index) // destroy next value
loop
exitwhen i + 1 == this.count
call SaveDestructableHandle(thistype.ht, this, i, LoadDestructableHandle(thistype.ht, this, i + 1)) // move next value to current index
call RemoveSavedHandle(thistype.ht, this, i + 1) // destroy next value
set i = i + 1
endloop
set this.count = count - 1
endmethod
method Remove takes integer index returns thistype
call this.Unshift(index) // move everything to the left, freeing the last index and decreasing the collection size
return this
endmethod
method Append takes destructable entry returns thistype
call SaveDestructableHandle(thistype.ht, this, this.count, entry)
set this.count = count + 1
return this
endmethod
method Prepend takes destructable entry returns thistype
call this.Shift(0) // move everything to the right, freeing index 0 and increasing the collection size
call SaveDestructableHandle(thistype.ht, this, 0, entry)
return this
endmethod
method Clear takes nothing returns nothing
call FlushChildHashtable(thistype.ht, this)
set this.count = 0
endmethod
method Copy takes TreeCollection c returns thistype
//call DisplayTextToPlayer(Player(0), 0, 0, "TreeCollection.Copy")
call this.Clear()
loop
//call DisplayTextToPlayer(Player(0), 0, 0, I2S(this.count) + "/" + I2S(c.count))
exitwhen this.count == c.count
call this.Append(c[this.count])
endloop
return this
endmethod
method Clone takes nothing returns thistype
local thistype output
call DisplayTextToPlayer(Player(0), 0, 0, "TreeCollection.Clone")
set output = thistype.create()
call output.Copy(this)
return output
endmethod
method Sum takes ITreeSelector s returns integer
local integer output = 0
local integer i = this.count - 1
loop
exitwhen i == 0
set output = output + s.evaluate(this[i])
set i = i - 1
endloop
return output
endmethod
method Average takes ITreeSelector s returns integer
if(this.count == 0)then
return 0
endif
return this.Sum(s) / this.count
endmethod
method ForEach takes ITreeAction a returns thistype
local integer i = 0
loop
exitwhen i == this.count
call a.execute(this[i])
set i = i + 1
endloop
return this
endmethod
method Any takes ITreeFilter f returns boolean
local integer i = this.count - 1
loop
exitwhen i < 0
if(f.evaluate(this[i]) == false)then
return true
endif
set i = i - 1
endloop
return false
endmethod
method Filter takes ITreeFilter f returns thistype
local integer i = this.count - 1
loop
exitwhen i < 0
//call DisplayTextToPlayer(Player(0), 0, 0, "Filter " + I2S(i))
if(f.evaluate(this[i]) == false)then
//call DisplayTextToPlayer(Player(0), 0, 0, "REMOVING " + I2S(i))
call this.Remove(i)
endif
set i = i - 1
endloop
return this
endmethod
method Sort takes ITreeSelector s, integer direction returns thistype
local ITreeArray keys = ITreeArray.create()
local IArray values = IArray.create()
local integer i
set i = 0
loop
exitwhen i == this.count
set keys[i] = this[i]
set values[i] = s.evaluate(keys[i])
set i = i + 1
endloop
call AssocTreeArraySort(keys, values, 0, this.count - 1)
set i = 0
loop
exitwhen i == this.count
if(direction == thistype.SORT_ASC)then
call SaveDestructableHandle(thistype.ht, this, i, keys[i])
else
call SaveDestructableHandle(thistype.ht, this, (this.count - 1) - i, keys[i])
endif
set i = i + 1
endloop
call keys.destroy()
call values.destroy()
return this
endmethod
method SortBy takes ITreeSelector s returns thistype
return this.Sort(s, thistype.SORT_ASC)
endmethod
method SortByDesc takes ITreeSelector s returns thistype
return this.Sort(s, thistype.SORT_DESC)
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.count = 0
set this.iterator = TreeCollectionIterator.create(this)
return this
endmethod
method destroy takes nothing returns nothing
call this.Clear()
call this.iterator.destroy()
call this.deallocate()
endmethod
endstruct
globals
private real f_GetTreeDistance_x
private real f_GetTreeDistance_y
endglobals
private function GetTreeDistanceCallback takes destructable d returns integer
return R2I(DistanceBetweenCoordinates(GetDestructableX(d), GetDestructableY(d), f_GetTreeDistance_x, f_GetTreeDistance_y))
endfunction
function GetTreeDistanceSelector takes real x, real y returns ITreeSelector
set f_GetTreeDistance_x = x
set f_GetTreeDistance_y = y
return GetTreeDistanceCallback
endfunction
endlibrary
globals
trigger FinalTierTechStart
trigger FinalTierTechCancel
trigger FinalTierTechEnd
trigger AiUprisingBuildBoost
trigger EnvironmentalistFederationTerraformRefund
trigger PirateLordShipPlunder
constant integer AiUprisingTech = 'R00J'
constant integer AiUprisingAbility = 'A01R'
constant integer EnvironmentalistFederationTech = 'R00G'
constant integer EnvironmentalistFederationAbility = 'A024'
constant integer GalacticDominionTech = 'R00H'
constant integer GalacticDominionAbility = 'S000'
constant integer GalacticDominionAbility2 = 'A025'
constant integer IndustrialComplexTech = 'R00K'
constant integer IndustrialComplexAbility = 'A026'
constant integer PirateLordTech = 'R00F'
constant integer PirateLordAbility = 'S001'
constant integer ScientificConglomerateTech = 'R00I'
constant integer ScientificConglomerateAbility = 'A027'
endglobals
function FinalTierTechCondition takes nothing returns boolean
if(GetResearched() == PirateLordTech)then
return true
endif
if(GetResearched() == EnvironmentalistFederationTech)then
return true
endif
if(GetResearched() == GalacticDominionTech)then
return true
endif
if(GetResearched() == ScientificConglomerateTech)then
return true
endif
if(GetResearched() == AiUprisingTech)then
return true
endif
if(GetResearched() == IndustrialComplexTech)then
return true
endif
return false
endfunction
function FinalTierTechStartAction takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
call SetPlayerTechMaxAllowedSwap(PirateLordTech, 0, p)
call SetPlayerTechMaxAllowedSwap(EnvironmentalistFederationTech, 0, p)
call SetPlayerTechMaxAllowedSwap(GalacticDominionTech, 0, p)
call SetPlayerTechMaxAllowedSwap(ScientificConglomerateTech, 0, p)
call SetPlayerTechMaxAllowedSwap(AiUprisingTech, 0, p)
call SetPlayerTechMaxAllowedSwap(IndustrialComplexTech, 0, p)
set p = null
endfunction
function FinalTierTechCancelAction takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
call SetPlayerTechMaxAllowedSwap(PirateLordTech, 1, p)
call SetPlayerTechMaxAllowedSwap(EnvironmentalistFederationTech, 1, p)
call SetPlayerTechMaxAllowedSwap(GalacticDominionTech, 1, p)
call SetPlayerTechMaxAllowedSwap(ScientificConglomerateTech, 1, p)
call SetPlayerTechMaxAllowedSwap(AiUprisingTech, 1, p)
call SetPlayerTechMaxAllowedSwap(IndustrialComplexTech, 1, p)
set p = null
endfunction
function AiUprisingBuildBoostAction takes nothing returns nothing
local unit u = GetConstructingStructure()
call TriggerSleepAction(0)
call UnitSetConstructionProgress(u, 50)
endfunction
function EnvironmentalistFederationTerraformRefundFilter takes nothing returns boolean
return IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT)
endfunction
function EnvironmentalistFederationTerraformRefundAction takes nothing returns nothing
local integer refund = GetUnitWoodCost(GetUnitTypeId(GetTriggerUnit())) / 2
//call DisplayTextToPlayer(Player(0), 0, 0, "EnvironmentalistFederationTerraformRefundAction")
call ShowResourceText(GetOwningPlayer(GetTriggerUnit()), GetTriggerUnit(), 0, refund)
call SetPlayerState(GetOwningPlayer(GetTriggerUnit()), PLAYER_STATE_RESOURCE_LUMBER, refund + GetPlayerState(GetOwningPlayer(GetTriggerUnit()), PLAYER_STATE_RESOURCE_LUMBER))
endfunction
function PirateLordShipPlunderCondition takes nothing returns boolean
return GetPlayerTechCount(GetOwningPlayer(GetKillingUnit()), PirateLordTech, true) > 0 and IsUnitType(GetDyingUnit(), UNIT_TYPE_ANCIENT) == false and IsUnitType(GetDyingUnit(), UNIT_TYPE_HERO) == false
endfunction
function PirateLordShipPlunderAction takes nothing returns nothing
local integer minerals = GetUnitGoldCost(GetUnitTypeId(GetDyingUnit())) / 10
local integer hydrogen = GetUnitWoodCost(GetUnitTypeId(GetDyingUnit())) / 10
call ShowResourceText(GetOwningPlayer(GetKillingUnit()), GetDyingUnit(), minerals, hydrogen)
call SetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_RESOURCE_GOLD, minerals + GetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_RESOURCE_GOLD))
call SetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_GOLD_GATHERED, minerals + GetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_GOLD_GATHERED))
call SetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_RESOURCE_LUMBER, hydrogen + GetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_RESOURCE_LUMBER))
call SetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_LUMBER_GATHERED, minerals + GetPlayerState(GetOwningPlayer(GetKillingUnit()), PLAYER_STATE_LUMBER_GATHERED))
endfunction
function TrySetupAiUprising takes player p returns nothing
if(GetResearched() != AiUprisingTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, AiUprisingAbility, true)
// activate personal bonus
call AdjustPlayerStateBJ(200, p, PLAYER_STATE_RESOURCE_FOOD_CAP)
call TriggerRegisterPlayerUnitEvent(AiUprisingBuildBoost, p, EVENT_PLAYER_UNIT_CONSTRUCT_START, null)
endfunction
function TrySetupEnvironmentalistFederation takes player p returns nothing
if(GetResearched() != EnvironmentalistFederationTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, EnvironmentalistFederationAbility, true)
// activate personal bonus
call TriggerRegisterPlayerUnitEvent(EnvironmentalistFederationTerraformRefund, p, EVENT_PLAYER_UNIT_UPGRADE_FINISH, Condition(function EnvironmentalistFederationTerraformRefundFilter))
endfunction
function TrySetupGalacticDominion takes player p returns nothing
if(GetResearched() != GalacticDominionTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, GalacticDominionAbility, true)
// activate personal bonus
call SetPlayerAbilityAvailable(p, GalacticDominionAbility2, true)
endfunction
function TrySetupIndustrialComplex takes player p returns nothing
if(GetResearched() != IndustrialComplexTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, IndustrialComplexAbility, true)
// activate personal bonus
// in ResourceDelivery/PeriodicIncome
endfunction
function TrySetupPirateLord takes player p returns nothing
if(GetResearched() != PirateLordTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, PirateLordAbility, true)
// activate personal bonus
// resource delivery contains plunder code as well
endfunction
function TrySetupScientificConglomerate takes player p returns nothing
if(GetResearched() != ScientificConglomerateTech)then
return
endif
// activate team aura
call SetPlayerAbilityAvailable(p, ScientificConglomerateAbility, true)
// activate personal bonus
// in ResourceDelivery/PeriodicIncome
endfunction
function FinalTierTechEndAction takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
call TrySetupAiUprising(p)
call TrySetupEnvironmentalistFederation(p)
call TrySetupGalacticDominion(p)
call TrySetupIndustrialComplex(p)
call TrySetupPirateLord(p)
call TrySetupScientificConglomerate(p)
set p = null
endfunction
function Trig_InitFinalTierTechs_Actions takes nothing returns nothing
set FinalTierTechStart = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(FinalTierTechStart, EVENT_PLAYER_UNIT_RESEARCH_START)
call TriggerAddCondition(FinalTierTechStart, Condition(function FinalTierTechCondition))
call TriggerAddAction(FinalTierTechStart, function FinalTierTechStartAction)
set FinalTierTechCancel = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(FinalTierTechCancel, EVENT_PLAYER_UNIT_RESEARCH_CANCEL)
call TriggerAddCondition(FinalTierTechCancel, Condition(function FinalTierTechCondition))
call TriggerAddAction(FinalTierTechCancel, function FinalTierTechCancelAction)
set FinalTierTechEnd = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(FinalTierTechEnd, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddCondition(FinalTierTechEnd, Condition(function FinalTierTechCondition))
call TriggerAddAction(FinalTierTechEnd, function FinalTierTechEndAction)
// tech-specific events
set AiUprisingBuildBoost = CreateTrigger()
call TriggerAddAction(AiUprisingBuildBoost, function AiUprisingBuildBoostAction)
set EnvironmentalistFederationTerraformRefund = CreateTrigger()
call TriggerAddAction(EnvironmentalistFederationTerraformRefund, function EnvironmentalistFederationTerraformRefundAction)
set PirateLordShipPlunder = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(PirateLordShipPlunder, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(PirateLordShipPlunder, Condition( function PirateLordShipPlunderCondition))
call TriggerAddAction(PirateLordShipPlunder, function PirateLordShipPlunderAction)
endfunction
//===========================================================================
function InitTrig_InitFinalTierTechs takes nothing returns nothing
set gg_trg_InitFinalTierTechs = CreateTrigger()
call TriggerAddAction(gg_trg_InitFinalTierTechs, function Trig_InitFinalTierTechs_Actions)
endfunction
library CampGeneratorLib initializer InitCampGenerator requires WeightedRandomLib, CollectionLib
globals
private Collection CampUnitTypes
private constant integer Raider = 'h005'
private constant integer Defender = 'h006'
private constant integer Hunter = 'h00G'
private constant integer Ravager = 'h00I'
private constant integer Destroyer = 'h007'
private constant integer AncientFrigate = 'h00K'
private integer f_RollCampFilter_limit
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
private function RollCampFilter takes integer value returns boolean
return GetFoodUsed(value) <= f_RollCampFilter_limit
endfunction
private function GetFoodUsed2 takes integer i returns integer
return GetFoodUsed(i)
endfunction
private function RollCamp takes Collection camp, integer limit returns integer
local Collection validTypes
local integer selectedType
local integer selectedCount
if(CampUnitTypes.Min(GetFoodUsed2) > limit)then
return 0
endif
set validTypes = CampUnitTypes.Clone()
set f_RollCampFilter_limit = limit
call validTypes.Filter(RollCampFilter)
set selectedType = validTypes.GetRandomValue()
set selectedCount = GetRandomInt(1, limit / GetFoodUsed(selectedType))
set limit = limit - selectedCount * GetFoodUsed(selectedType)
call Debug("Adding x" + I2S(selectedCount) + " " + GetObjectName(selectedType))
loop
exitwhen selectedCount == 0
call camp.Append(selectedType)
set selectedCount = selectedCount - 1
endloop
call validTypes.destroy()
return limit
endfunction
private function SpawnCamp takes Collection camp, real x, real y returns nothing
local CollectionIterator it = camp.GetIterator()
local integer campSize = camp.Count()
local real a
local real d = SquareRoot((campSize - 1) * 1000)
local unit u
call Debug("SpawnCamp of size " + I2S(campSize))
loop
exitwhen it.Next() == false
call Debug("Creating " + GetObjectName(it.Value()))
set a = (360.0 / campSize) * it.Index()
set u = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), it.Value(), PolarProjectionX(x, d, a), PolarProjectionY(y, d, a), 360 - a)
call SetUnitCreepGuard(u, true)
//call SetUnitAcquireRange(u, 200)
endloop
set u = null
endfunction
function GenerateCamp takes real x, real y, integer fleetLimit returns nothing
local Collection camp = Collection.create(0)
call Debug("GenerateCamp")
loop
call Debug("FleetLimit left: " + I2S(fleetLimit))
exitwhen fleetLimit == 0
set fleetLimit = RollCamp(camp, fleetLimit)
endloop
call SpawnCamp(camp, x, y)
call camp.destroy()
endfunction
private function InitCampGenerator takes nothing returns nothing
set CampUnitTypes = Collection.create(0)
call CampUnitTypes.Append(Raider)
call CampUnitTypes.Append(Defender)
call CampUnitTypes.Append(Hunter)
call CampUnitTypes.Append(Ravager)
call CampUnitTypes.Append(Destroyer)
call CampUnitTypes.Append(AncientFrigate)
endfunction
endlibrary
library MapGeneratorLib requires Core, MathLib, CollectionLib, WeightedRandomLib, AiUtilsLib, CampGeneratorLib, TeamManagerLib
globals
unit array PlayerHomePlanets
unit array PlayerControlPanel
minimapicon array PlayerHomePlanetIcons
private real AngleVariation = GetRandomReal(-360, 360)
private constant integer ClusterPerSystem = 3
private constant integer PlanetPerCluster = 2
private constant integer SystemToSystemDistance = 4500
private real CloseSystemToCenterDistance
private real FarSystemToCenterDistance
private real AsteroidFieldToCenterDistance
private constant integer MainClusterDistance = 800
private constant integer ExtraClusterDistance = 600
private constant integer PlanetDistance = 250
private constant integer ResourceNodeDistance = 500
private constant integer MapBoundsOffset = 800
private constant integer CameraBoundsOffset = 300
private rect GeneratedBounds
private rect MapBounds
private rect CameraBounds
private constant integer HomePlanet = 'h001'
private constant integer ControlPanel = 'H013'
private constant integer SpaceBuilder = 'h002'
private constant integer Probe = 'h004'
private constant integer FrozenPlanet = 'n000'
private constant integer MagmaPlanet = 'n001'
private constant integer HospitablePlanet = 'n002'
private constant integer SmallAsteroid = 'n004'
private constant integer MediumAsteroid = 'n005'
private constant integer LargeAsteroid = 'n006'
private constant integer GasCloud = 'n008'
private constant integer Star = 'B000'
private constant string SystemType = "MHFMHMF"
private constant string SystemType1 = "HFFHHMM"
private constant string SystemType2 = "MHFMHMF"
private constant string SystemType3 = "FHMFHFM"
private unit f_GeneratePlanet_output
private unit f_GenerateResource_output
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
private function GetNumberOfSystems takes integer playerCount returns integer
return playerCount
endfunction
private function GetNumberOfAsteroidFields takes integer playerCount returns integer
return playerCount / 2
endfunction
private function GetNumberOfNeutralClusters takes nothing returns integer
return 0
endfunction
private function PlanetAngle takes integer planetCount, integer planetNumber returns real
return 90 + (planetNumber * 360.0) / planetCount
endfunction
private function ClusterAngle takes integer clusterCount, integer clusterNumber returns real
return 90 + (clusterNumber * 360.0) / clusterCount
endfunction
private function SystemAngle takes integer systemCount, integer systemNumber returns real
return AngleVariation + (systemNumber * 360.0) / systemCount
endfunction
private function AsteroidFieldAngle takes integer systemCount, integer asteroidFieldCount, integer asteroidFieldNumber returns real
return AngleVariation + (360.0 / systemCount) / 2 + (asteroidFieldNumber * 360.0) / asteroidFieldCount
endfunction
private function ClusterPlanetCount takes integer clusterNumber returns integer
if(clusterNumber == ClusterPerSystem - 1)then
return PlanetPerCluster + 1 // extra planet in last cluster
endif
return PlanetPerCluster
endfunction
private function SystemDistance takes integer systemCount, integer systemNumber returns real
return FarSystemToCenterDistance
if(ModuloInteger(systemNumber, 2) == 0)then
return FarSystemToCenterDistance
endif
return CloseSystemToCenterDistance
endfunction
private function UpdateBounds takes real x, real y returns nothing
local real minX = RMinBJ(GetRectMinX(GeneratedBounds), x)
local real maxX = RMaxBJ(GetRectMaxX(GeneratedBounds), x)
local real minY = RMinBJ(GetRectMinY(GeneratedBounds), y)
local real maxY = RMaxBJ(GetRectMaxY(GeneratedBounds), y)
call SetRect(GeneratedBounds, minX, minY, maxX, maxY)
endfunction
// lifted here: https://www.hiveworkshop.com/threads/how-do-you-make-a-terrain-unwalkable.214006/#post-2174343
function SetPathing takes real minX, real minY, real maxX, real maxY, pathingtype P, boolean T returns nothing
local integer cellSize = 128
local integer mX = R2I(minX / cellSize)
local integer mY = R2I(minY / cellSize)
local integer MX = R2I(maxX / cellSize)
local integer MY = R2I(maxY / cellSize)
local integer x
local integer y
set x = mX
loop
exitwhen x > MX
set y = mY
loop
exitwhen y > MY
call SetTerrainType(x*cellSize, y*cellSize, 'NOTH', -1, 1, 1)
//call CreateUnit(Player(5), 'hpea', x*cellSize, y*cellSize, 0)
//call SetTerrainPathable(x*cellSize, y*cellSize, P, T)
set y = y + 1
endloop
set x = x + 1
endloop
endfunction
function SetPathings takes real minX, real maxX, real minY, real maxY returns nothing
//call SetPathing(minX, minY, maxX, maxY, PATHING_TYPE_BUILDABILITY, false)
//call SetPathing(minX, minY, maxX, maxY, PATHING_TYPE_WALKABILITY, false)
call SetPathing(minX, minY, maxX, maxY, PATHING_TYPE_FLYABILITY, false)
endfunction
private function ApplyMapBounds takes nothing returns nothing
local real minX = GetRectMinX(GeneratedBounds) - MapBoundsOffset
local real maxX = GetRectMaxX(GeneratedBounds) + MapBoundsOffset
local real minY = GetRectMinY(GeneratedBounds) - MapBoundsOffset
local real maxY = GetRectMaxY(GeneratedBounds) + MapBoundsOffset
call SetRect(MapBounds, minX, minY, maxX, maxY)
// wide top/bottom
call SetPathings(minX - MapBoundsOffset*2, maxX + MapBoundsOffset*2, maxY, maxY + MapBoundsOffset*2)
call SetPathings(minX - MapBoundsOffset*2, maxX + MapBoundsOffset, minY - MapBoundsOffset*2, minY)
// short left/right
call SetPathings(minX - MapBoundsOffset*2, minX, minY, maxY)
call SetPathings(maxX, maxX + MapBoundsOffset*2, minY, maxY)
endfunction
private function ApplyCameraBounds takes nothing returns nothing
local real minX = GetRectMinX(GeneratedBounds) - CameraBoundsOffset
local real maxX = GetRectMaxX(GeneratedBounds) + CameraBoundsOffset
local real minY = GetRectMinY(GeneratedBounds) - CameraBoundsOffset
local real maxY = GetRectMaxY(GeneratedBounds) + CameraBoundsOffset
call SetRect(CameraBounds, minX, minY, maxX, maxY)
call SetCameraBoundsToRect(CameraBounds)
endfunction
private function GetRandomPlanetType takes nothing returns string
local integer i = GetRandomInt(1, 3)
if(i == 1)then
return "F"
elseif(i == 2)then
return "M"
else
return "H"
endif
return "H"
endfunction
private function GetRandomPlanets takes integer count returns string
local string s = ""
local integer i = 0
loop
exitwhen i == count
set s = s + GetRandomPlanetType()
set i = i + 1
endloop
return s
endfunction
private function ToPlanetUnitType takes string p returns integer
if(p == "F")then
return FrozenPlanet
elseif(p == "M")then
return MagmaPlanet
elseif(p == "H")then
return HospitablePlanet
endif
return 0
endfunction
private function GetRandomSystemType takes nothing returns string
/*local integer i = GetRandomInt(1, 3)
if(i == 1)then
return SystemType1
elseif(i == 2)then
return SystemType2
else
return SystemType2
endif*/
return SystemType
endfunction
private function GeneratePlanet takes real x, real y, string planetType returns unit
set f_GeneratePlanet_output = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), ToPlanetUnitType(planetType), x, y, 0)
call UpdateBounds(x, y)
return f_GeneratePlanet_output
endfunction
private function GenerateResourceNode takes real x, real y, integer resourceType returns unit
set f_GenerateResource_output = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), resourceType, x, y, 0)
call UpdateBounds(x, y)
return f_GenerateResource_output
endfunction
struct Cluster
real x
real y
real angle
group planets
group asteroids
method ProjectX takes integer planetCount, integer planetNumber returns real
return PolarProjectionX(this.x, PlanetDistance, this.angle + PlanetAngle(planetCount, planetNumber))
endmethod
method ProjectY takes integer planetCount, integer planetNumber returns real
return PolarProjectionY(this.y, PlanetDistance, this.angle + PlanetAngle(planetCount, planetNumber))
endmethod
method GeneratePlanets takes string planetTypes returns nothing
local integer planetCount = StringLength(planetTypes)
local integer n = 0
set this.planets = CreateGroup()
loop
exitwhen n == planetCount
call GroupAddUnit(this.planets, GeneratePlanet(this.ProjectX(planetCount, n), this.ProjectY(planetCount, n), SubString(planetTypes, n, n + 1)))
set n = n + 1
endloop
endmethod
method GeneratePlayerResource takes integer resourceType returns nothing
set this.asteroids = CreateGroup()
call GroupAddUnit(this.asteroids, GenerateResourceNode(this.x, this.y, resourceType))
endmethod
method GenerateNeutralResource takes integer resourceType returns nothing
set this.asteroids = CreateGroup()
call GroupAddUnit(this.asteroids, GenerateResourceNode(this.x, this.y, resourceType))
call GenerateCamp(this.x, this.y, 10)
endmethod
method GenerateNeutralPlanets takes string planetTypes returns nothing
local integer planetCount = StringLength(planetTypes)
local integer n = 0
set this.planets = CreateGroup()
loop
exitwhen n == planetCount
call GroupAddUnit(this.planets, GeneratePlanet(this.ProjectX(planetCount, n), this.ProjectY(planetCount, n), SubString(planetTypes, n, n + 1)))
set n = n + 1
endloop
call GenerateCamp(this.x, this.y, 15)
endmethod
static method create takes real x, real y, real angle returns thistype
local thistype this = thistype.allocate()
set this.x = x
set this.y = y
set this.angle = angle
return this
endmethod
method destroy takes nothing returns nothing
local integer n = 0
call this.deallocate()
endmethod
endstruct
struct System
real x
real y
real angle
real closeSystem
real farSystem
string systemType
Collection clusters
method SpawnPlayer takes player p returns nothing
local integer id = GetPlayerId(p)
set PlayerHomePlanets[id] = CreateUnit(p, HomePlanet, this.x, this.y, 270)
set PlayerControlPanel[id] = CreateUnit(p, ControlPanel, this.x, this.y, 270)
set PlayerHomePlanetIcons[id] = CreateMinimapIconOnUnit(PlayerHomePlanets[id], 255, 255, 255, "UI\\Minimap\\minimap-neutralbuilding.blp", FOG_OF_WAR_FOGGED)
call BlzSetHeroProperName(PlayerControlPanel[id], "Control Panel")
call SuspendHeroXP(PlayerControlPanel[id], true)
// hide lifebar?
call UnitAddAbility(PlayerControlPanel[id],'Aloc')
call ShowUnit(PlayerControlPanel[id],false)
call ShowUnit(PlayerControlPanel[id],true)
if(CompetitiveMode)then
call CreateUnit(p, SpaceBuilder, this.x, this.y - 150, 270)
call SetPlayerState(p, PLAYER_STATE_FOOD_CAP_CEILING, CompetitiveFleetCap)
else
call CreateUnit(p, SpaceBuilder, this.x + 150, this.y - 200, 270)
call CreateUnit(p, SpaceBuilder, this.x - 150, this.y - 200, 270)
call CreateUnit(p, Probe, this.x, this.y - 300, 270)
call SetPlayerState(p, PLAYER_STATE_FOOD_CAP_CEILING, NormalFleetCap)
endif
//call UnitAddItem(PlayerHomePlanets[id], CreateItem('I009', this.x, this.y))
//call CreateUnit(p, 'h00L', this.x, this.y - 500, 270)
if(TeamGame == false)then
call SetPlayerTechResearched(p, 'R00L', 1)
endif
call DefineStartLocation(id, this.x, this.y)
call SetPlayerStartLocation(p, id)
call ForcePlayerStartLocation(p, id)
if(p == GetLocalPlayer())then
call SetCameraPosition(this.x, this.y)
endif
if(GetPlayerController(p) == MAP_CONTROL_COMPUTER)then
call StartMeleeAI(p, "SolarEmpire.ai")
call SetFogStateRect(p, FOG_OF_WAR_VISIBLE, GetEntireMapRect(), false) // pre-scout planets and resources
call AiCompetitive(p, CompetitiveMode)
call AiSetGatherPoint(p, GetUnitX(PlayerHomePlanets[id]), GetUnitY(PlayerHomePlanets[id]))
call SetPlayerName(p, GetColoredPlayerName(p) + " (" + I2S(id + 1) + ")")
endif
endmethod
method Angle takes integer clusterNumber returns real
return this.angle + ClusterAngle(ClusterPerSystem, clusterNumber)
endmethod
method ProjectX takes integer clusterNumber returns real
return PolarProjectionX(this.x, MainClusterDistance + clusterNumber * ExtraClusterDistance, this.Angle(clusterNumber))
endmethod
method ProjectY takes integer clusterNumber returns real
return PolarProjectionY(this.y, MainClusterDistance + clusterNumber * ExtraClusterDistance, this.Angle(clusterNumber))
endmethod
method AsteroidProjectX takes integer asteroidCount, integer asteroidNumber returns real
return PolarProjectionX(this.x, asteroidNumber * ResourceNodeDistance, this.angle + PlanetAngle(asteroidCount, asteroidNumber))
endmethod
method AsteroidProjectY takes integer asteroidCount, integer asteroidNumber returns real
return PolarProjectionY(this.y, asteroidNumber * ResourceNodeDistance, this.angle + PlanetAngle(asteroidCount, asteroidNumber))
endmethod
private method GenerateSun takes nothing returns nothing
local unit u
if(GetRandomInt(0, 1) == 0)then
// red star
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'h017', this.ProjectX(GetRandomInt(0, 2)), this.ProjectY(GetRandomInt(0, 2)), 0)
call SetUnitFlyHeight(u, GetRandomReal(-500, 0), 0)
else
// blue star
set u = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'h018', this.ProjectX(GetRandomInt(0, 2)), this.ProjectY(GetRandomInt(0, 2)), 0)
call SetUnitFlyHeight(u, GetRandomReal(-1000, -500), 0)
endif
set u = null
endmethod
method GeneratePlanetSystem takes integer systemCount, integer systemNumber returns nothing
local integer n = 0
local integer clusterPlanetCount = 0
local Cluster c
//call Debug("Generating system " + I2S(systemNumber+1) + "/" + I2S(systemCount))
set this.systemType = GetRandomSystemType()
set this.angle = SystemAngle(systemCount, systemNumber)
set this.x = PolarProjectionX(0, SystemDistance(systemCount, systemNumber), angle)
set this.y = PolarProjectionY(0, SystemDistance(systemCount, systemNumber), angle)
loop
exitwhen n == ClusterPerSystem
set c = Cluster.create(this.ProjectX(n), this.ProjectY(n), this.Angle(n))
call this.clusters.Append(c)
call c.GeneratePlanets(SubString(this.systemType, clusterPlanetCount, clusterPlanetCount + ClusterPlanetCount(n)))
set clusterPlanetCount = clusterPlanetCount + ClusterPlanetCount(n)
set n = n + 1
endloop
set c = Cluster.create(this.ProjectX(n), this.ProjectY(n), this.Angle(n))
call c.GeneratePlayerResource(GasCloud)
call this.clusters.Append(c)
set n = n + 1
set c = Cluster.create(this.ProjectX(n), this.ProjectY(n), this.Angle(n))
call c.GeneratePlayerResource(SmallAsteroid)
call this.clusters.Append(c)
set n = n + 1
set c = Cluster.create(this.ProjectX(n), this.ProjectY(n), this.Angle(n))
call c.GeneratePlayerResource(SmallAsteroid)
call this.clusters.Append(c)
set n = n + 1
set c = Cluster.create(this.ProjectX(n), this.ProjectY(n), this.Angle(n))
call c.GeneratePlayerResource(SmallAsteroid)
call this.clusters.Append(c)
call GenerateSun()
endmethod
method GenerateResourceSystem takes integer systemCount, integer systemNumber returns nothing
local integer target = GetNumberOfAsteroidFields(systemCount)
local Cluster c
set this.angle = AsteroidFieldAngle(systemCount, target, 1 + systemNumber * 2)
set this.x = PolarProjectionX(0, AsteroidFieldToCenterDistance, angle)
set this.y = PolarProjectionY(0, AsteroidFieldToCenterDistance, angle)
set c = Cluster.create(this.AsteroidProjectX(5, 0), this.AsteroidProjectY(5, 0), this.angle)
call c.GenerateNeutralResource(MediumAsteroid)
call this.clusters.Append(c)
set c = Cluster.create(this.AsteroidProjectX(5, 2), this.AsteroidProjectY(5, 2), this.angle)
call c.GenerateNeutralResource(LargeAsteroid)
call this.clusters.Append(c)
set c = Cluster.create(this.AsteroidProjectX(5, 4), this.AsteroidProjectY(5, 4), this.angle)
call c.GenerateNeutralResource(GasCloud)
call this.clusters.Append(c)
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.clusters = Collection.create(0)
return this
endmethod
method destroy takes nothing returns nothing
call this.clusters.destroy()
call this.deallocate()
endmethod
endstruct
globals
private real f_GetDistanceToSystem_x
private real f_GetDistanceToSystem_y
endglobals
private function GetDistanceToSystemCallback takes System s returns integer
return R2I(DistanceBetweenCoordinates(s.x, s.y, f_GetDistanceToSystem_x, f_GetDistanceToSystem_y))
endfunction
private function GetDistanceToSystemSelector takes System s returns ISelector
set f_GetDistanceToSystem_x = s.x
set f_GetDistanceToSystem_y = s.y
return GetDistanceToSystemCallback
endfunction
private function SystemSortingSelector takes System s returns integer
return R2I(s.farSystem)
endfunction
private function System2SortingSelector takes System s returns integer
return R2I(s.closeSystem)
endfunction
private function GetAllPlayersFilter takes nothing returns boolean
return GetPlayerSlotState(GetFilterPlayer()) == PLAYER_SLOT_STATE_PLAYING and IsPlayerObserver(GetFilterPlayer()) == false
endfunction
private function GenerateExtraResources takes Collection systems returns Collection
local integer systemCount = systems.Count()
local integer target = GetNumberOfAsteroidFields(systemCount)
local integer n = 0
local real r = 0
local Collection resources = Collection.create(0)
local System s
loop
exitwhen n == target
set s = System.create()
call s.GenerateResourceSystem(systemCount, n)
call resources.Append(s)
set n = n + 1
endloop
return resources
endfunction
globals
private real GenerateExtraPlanetsCheck_x
private real GenerateExtraPlanetsCheck_y
endglobals
private function GenerateExtraPlanetsCheckCluster takes Cluster c returns boolean
return IsWithinDistance(GenerateExtraPlanetsCheck_x, GenerateExtraPlanetsCheck_y, c.x, c.y, SystemToSystemDistance/2) == false
endfunction
private function GenerateExtraPlanetsCheckSystem takes System s returns boolean
return s.clusters.All(GenerateExtraPlanetsCheckCluster)
endfunction
private function GenerateExtraPlanets takes Collection systems, Collection resources returns Collection
local Collection clusters = Collection.create(0)
local Cluster cluster
local integer target = 3 + R2I(SquareRoot(systems.Count() * systems.Count() * 2))
local integer n = 0
local integer limit = target * 150
local integer i = 0
loop
exitwhen n == target or i == limit
loop
exitwhen n == target or i == limit
set GenerateExtraPlanetsCheck_x = GetRandomReal(GetRectMinX(GeneratedBounds), GetRectMaxX(GeneratedBounds))
set GenerateExtraPlanetsCheck_y = GetRandomReal(GetRectMinY(GeneratedBounds), GetRectMaxY(GeneratedBounds))
if(systems.All(GenerateExtraPlanetsCheckSystem) and resources.All(GenerateExtraPlanetsCheckSystem) and clusters.All(GenerateExtraPlanetsCheckCluster))then
set cluster = Cluster.create(GenerateExtraPlanetsCheck_x, GenerateExtraPlanetsCheck_y, GetRandomReal(0, 360))
call cluster.GenerateNeutralPlanets(GetRandomPlanets(2))
call clusters.Append(cluster)
set n = n + 1
endif
set i = i + 1
endloop
endloop
//call DisplayTextToPlayer(Player(0), 0, 0, "Generated " + I2S(n) + "/" + I2S(target) + " clusters, " + I2S(i) + "/" + I2S(limit) + " attempts used.")
return clusters
endfunction
private function SpawnPlayersFfa takes force players, Collection systems returns nothing
local System system
local CollectionIterator systemIt
local Collection systems2 = Collection.create(0)
local player p = null
call Debug("Process system distances")
set systemIt = systems.GetIterator()
loop
exitwhen systemIt.Next() == false
set system = systemIt.Value()
//set system.closeSystem = systems.Min(GetDistanceToSystemSelector(system))
set system.farSystem = systems.Max(GetDistanceToSystemSelector(system))
//call Debug(I2S(R2I(system.closeSystem)) + "/" + I2S(R2I(system.farSystem)))
endloop
call systems.SortByDesc(SystemSortingSelector)
loop
set p = ForcePickRandomPlayer(players)
exitwhen p == null
set system = systems.FirstOrDefault()
call system.SpawnPlayer(p)
call systems.Remove(0)
call systems2.Append(system)
call ForceRemovePlayer(players, p)
exitwhen systems.Count() == 0
set systemIt = systems.GetIterator()
loop
exitwhen systemIt.Next() == false
set system = systemIt.Value()
set system.closeSystem = systems2.Average(GetDistanceToSystemSelector(system))
set system.farSystem = systems2.Max(GetDistanceToSystemSelector(system))
call Debug(I2S(R2I(system.closeSystem)) + "/" + I2S(R2I(system.farSystem)))
endloop
call systems.SortByDesc(System2SortingSelector)
endloop
call systems2.destroy()
endfunction
private function SpawnPlayersTeam takes force players, Collection systems returns nothing
local CollectionIterator it = systems.GetIterator()
local System system
local player p = null
local force allies = CreateForce()
loop
set p = ForcePickRandomPlayer(players)
exitwhen p == null
call ForceEnumAllies(allies, p, null)
loop
set p = ForcePickRandomPlayer(allies)
exitwhen p == null
call it.Next()
set system = it.Value()
call system.SpawnPlayer(p)
call ForceRemovePlayer(players, p)
call ForceRemovePlayer(allies, p)
endloop
endloop
endfunction
private function RunGenerateMap takes nothing returns nothing
local force players = CreateForce()
local player p = null
local integer playerCount
local integer systemCount
local integer neutralResourceClusterCount
local integer neutralPlanetClusterCount
local integer neutralClusterCount
local integer n
local real r
local Collection systems = Collection.create(0)
local CollectionIterator systemIt
local Collection neutralResourceClusters// = Collection.create(0)
local Collection neutralPlanetClusters// = Collection.create(0)
local System system
call ForceEnumPlayers(players, Condition(function GetAllPlayersFilter))
set playerCount = CountPlayersInForceBJ(players)
set systemCount = GetNumberOfSystems(playerCount)
set neutralResourceClusterCount = GetNumberOfAsteroidFields(playerCount)
set neutralPlanetClusterCount = playerCount - neutralResourceClusterCount
set neutralClusterCount = neutralResourceClusterCount + neutralPlanetClusterCount
set GeneratedBounds = Rect(0, 0, 0, 0)
set MapBounds = Rect(0, 0, 0, 0)
set CameraBounds = Rect(0, 0, 0, 0)
set CloseSystemToCenterDistance = ((SystemToSystemDistance+500) * systemCount / 2) / bj_PI
if(systemCount <= 4)then
set CloseSystemToCenterDistance = CloseSystemToCenterDistance + 1000 / systemCount
endif
set FarSystemToCenterDistance = (CloseSystemToCenterDistance + 1000) * bj_PI / 2
set AsteroidFieldToCenterDistance = CloseSystemToCenterDistance // (CloseSystemToCenterDistance + FarSystemToCenterDistance) / 2 - 500
//call SetPathings(-128, 128, -128, 128)
call Debug("Number of systems: " + I2S(systemCount))
call Debug("Cluster per system: " + I2S(ClusterPerSystem))
call Debug("Planet per cluster: " + I2S(PlanetPerCluster))
call Debug("Number of neutral resource clusters: " + I2S(neutralResourceClusterCount))
call Debug("Number of neutral planet cluseters: " + I2S(neutralPlanetClusterCount))
// create player systems
set n = 0
loop
exitwhen n == systemCount
set system = System.create()
call system.GeneratePlanetSystem(systemCount, n)
call systems.Append(system)
set n = n + 1
endloop
if(NeutralResources)then
set neutralResourceClusters = GenerateExtraResources(systems)
endif
if(NeutralPlanets)then
set neutralPlanetClusters = GenerateExtraPlanets(systems, neutralResourceClusters)
endif
//call SetTerrainType(0, 0, 'NOTH', -1, 1000, 1)
//call SetTerrainType(0, 0, 'Agrs', -1, 30, 1)
//call TriggerSleepAction(0)
//call Debug("ApplyMapBounds")
//call ApplyMapBounds()
call TriggerSleepAction(0)
call Debug("ApplyCameraBounds")
call ApplyCameraBounds()
call Debug("Spawn players")
if(TeamGame)then
call SpawnPlayersTeam(players, systems)
else
call SpawnPlayersFfa(players, systems)
endif
call systems.destroy()
set players = null
set p = null
call Debug("DONE!!")
endfunction
function GenerateMap takes nothing returns nothing
call RunGenerateMap()
endfunction
endlibrary
library MapSettingsLib initializer InitMapSettings requires MapGeneratorLib, optional DiplomacyLib
globals
// generation parameters
private player Host = null
private dialog MapDialog = null
private button StartButton = null
private button CompetitiveModeButton = null
private button TeamGameButton = null
private button NeutralPlanetsButton = null
private button NeutralResourcesButton = null
private trigger MapDialogTrigger
private boolean ForceTeam
private boolean ForceFfa
private boolean RecommendTeam
private boolean RecommendCompetitive
private boolean ManyPlayers
boolean CompetitiveMode = true
boolean TeamGame = true
boolean NeutralPlanets = true
boolean NeutralResources = true
constant integer CompetitiveFleetCap = 120
constant integer NormalFleetCap = 180
private constant string TickSoundPath = "Sound\\Interface\\BattleNetTick.flac"
private sound TickSound
private constant string GameStartSoundPath = "Sound\\Interface\\Hint.flac"
private sound GameStartSound
endglobals
private function GetLabelGameMode takes nothing returns string
if(CompetitiveMode)then
if(RecommendCompetitive)then
return "|cffffcc00Competitive |r (Recommended)"
endif
return "|cffffcc00Competitive |r"
else
if(RecommendCompetitive == false)then
return "|cffffcc00Normal Mode|r (Recommended)"
endif
return "|cffffcc00Normal Mode|r"
endif
endfunction
private function GetLabelTeamType takes nothing returns string
if(ForceTeam)then
return "|cffffcc00Team Game|r (FORCED)"
endif
if(TeamGame)then
if(RecommendTeam)then
return "|cffffcc00Team Game|r (Recommended)"
endif
return "|cffffcc00Team Game|r"
else
if(RecommendTeam == false)then
return "|cffffcc00Free-For-All|r (Recommended)"
endif
return "|cffffcc00Free-For-All|r"
endif
endfunction
private function GetLabelPlanets takes nothing returns string
if(NeutralPlanets)then
return "|cffffcc00Neutral planets:|r |cff55ff55On|r"
else
return "|cffffcc00Neutral planets:|r |cffff5555Off|r"
endif
endfunction
private function GetLabelResources takes nothing returns string
if(NeutralResources)then
return "|cffffcc00Neutral resources:|r |cff55ff55On|r"
else
return "|cffffcc00Neutral resources:|r |cffff5555Off|r"
endif
endfunction
private function GetDescriptionGameMode takes nothing returns string
if(CompetitiveMode)then
return "|cffffffff- Fleet Limit: "+I2S(CompetitiveFleetCap)+" MAX|r\n|cffffffff- Players start with 1 Pioneer|r"
else
return "|cffffffff- Fleet Limit: "+I2S(NormalFleetCap)+" MAX|r\n|cffffffff- Players start with 2 Pioneers|r\n|cffffffff- Players start with 1 Probe|r"
endif
endfunction
private function GetDescriptionTeamType takes nothing returns string
if(TeamGame)then
return "|cffffffff- Use lobby teams|r\n|cffffffff- Diplomacy options disabled|r"
else
return "|cffffffff- All players start as enemies|r\n|cffffffff- Diplomacy options enabled|r"
endif
endfunction
private function GetDescriptionPlanets takes nothing returns string
if(NeutralPlanets)then
return "|cffffffff- Extra Planet clusters|r"
else
return "|cffffffff- No extra Planet clusters|r"
endif
endfunction
private function GetDescriptionResources takes nothing returns string
if(NeutralResources)then
return "|cffffffff- Extra Resources nodes|r"
else
return "|cffffffff- No extra Resources nodes|r"
endif
endfunction
private function GetMapDialogDescription takes nothing returns string
local string s = ""
set s = s + GetLabelGameMode() + "\n" + GetDescriptionGameMode() + "\n"
set s = s + GetLabelTeamType() + "\n" + GetDescriptionTeamType() + "\n"
set s = s + GetLabelPlanets() + "\n" + GetDescriptionPlanets() + "\n"
set s = s + GetLabelResources() + "\n" + GetDescriptionResources() + "\n"
return s
endfunction
private function RefreshMapDialog takes nothing returns nothing
call DialogClear(MapDialog)
call DialogSetMessage(MapDialog, "|cff55FFFFMAP SETTINGS|r\n\n" + GetMapDialogDescription())
set StartButton = DialogAddButton(MapDialog, "|cff55FFFFSTART GAME|r", 0)
set CompetitiveModeButton = DialogAddButton(MapDialog, GetLabelGameMode(), 0)
if(ForceTeam == false)then
set TeamGameButton = DialogAddButton(MapDialog, GetLabelTeamType(), 0)
endif
set NeutralPlanetsButton = DialogAddButton(MapDialog, GetLabelPlanets(), 0)
set NeutralResourcesButton = DialogAddButton(MapDialog, GetLabelResources(), 0)
call DialogDisplay(Host, MapDialog, true)
endfunction
private function StartGame takes nothing returns nothing
local string mapSettings = GetMapDialogDescription()
local quest q = CreateQuest()
local questitem qi
call QuestSetTitle(q, "|cff55FFFFMAP SETTINGS|r")
call QuestSetDescription(q, mapSettings)
call QuestSetDiscovered(q, true)
call QuestSetRequired(q, false)
call QuestSetIconPath(q, "BTNHomePlanet.blp")
set qi = QuestCreateItem(q)
call QuestItemSetDescription(qi, GetLabelGameMode())
if(ForceTeam == false)then
set qi = QuestCreateItem(q)
call QuestItemSetDescription(qi, GetLabelTeamType())
endif
set qi = QuestCreateItem(q)
call QuestItemSetDescription(qi, GetLabelPlanets())
set qi = QuestCreateItem(q)
call QuestItemSetDescription(qi, GetLabelResources())
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "Starting the map with options:\n" + mapSettings)
call TriggerSleepAction(1)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "3")
call StartSound(TickSound)
//static if(DiplomacyLib)then
call InitDiplomacy(TeamGame)
//endif
call TriggerSleepAction(1)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "2")
call StartSound(TickSound)
call TriggerSleepAction(1)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "1")
call StartSound(TickSound)
call TriggerSleepAction(1)
call GenerateMap()
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "|cffffcc00GO!|r")
call StartSound(GameStartSound)
endfunction
private function OnMapDialog takes nothing returns nothing
if(GetClickedButton() == StartButton)then
call DialogDestroy(MapDialog)
call StartGame()
return
endif
if(GetClickedButton() == CompetitiveModeButton)then
set CompetitiveMode = not CompetitiveMode
endif
if(GetClickedButton() == TeamGameButton)then
set TeamGame = not TeamGame
endif
if(GetClickedButton() == NeutralPlanetsButton)then
set NeutralPlanets = not NeutralPlanets
endif
if(GetClickedButton() == NeutralResourcesButton)then
set NeutralResources = not NeutralResources
endif
call RefreshMapDialog()
endfunction
private function CreateMapDialog takes nothing returns nothing
local integer n = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerController(Player(n)) == MAP_CONTROL_USER)then
call SetPlayerName(Player(n), GetColoredPlayerName(Player(n)) + " (" + I2S(n + 1) + ")")
endif
set n = n + 1
endloop
set MapDialog = DialogCreate()
set MapDialogTrigger = CreateTrigger()
call TriggerRegisterDialogEvent(MapDialogTrigger, MapDialog)
call TriggerAddAction(MapDialogTrigger, function OnMapDialog)
call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, GetPlayerName(Player(0)) + " |cffffcc00is choosing the map settings...|r")
call RefreshMapDialog()
endfunction
private function InitMapSettings takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t, 0.1, false)
call TriggerAddAction(t, function CreateMapDialog)
set t = null
set ManyPlayers = PlayerCount > 4
set ForceTeam = PlayerCount <= 4
set RecommendTeam = PlayerCount != TeamCount and (PlayerCount / TeamCount) * TeamCount == PlayerCount // lobby teams are not Ffa and are balanced
set RecommendCompetitive = ManyPlayers == false
set CompetitiveMode = RecommendCompetitive
if(ForceTeam or RecommendTeam)then
set TeamGame = true
else
set TeamGame = RecommendTeam
endif
set Host = FirstPlayer()
set TickSound = CreateSound(TickSoundPath, false, false, false, 10, 10, "")
set GameStartSound = CreateSound(GameStartSoundPath, false, false, false, 10, 10, "")
endfunction
endlibrary
library DamageDefinitionLib
globals
constant integer MissileDamageType = 66
constant integer PlanetKillerMissileDamageType = 67
constant integer BulwarkDamageType = 33
constant integer ExtractorDamageType = 99
endglobals
/*function SetNextDamageType takes integer damageType returns nothing
endfunction
function IsSpellDamageEvent takes nothing returns boolean
endfunction
function GetAmountDamageEvent takes nothing returns real
endfunction
function SetAmountDamageEvent takes nothing returns real
endfunction*/
endlibrary
library DamageHandlerLib initializer InitDamageHandler requires DamageDefinitionLib, MissileSystem, Evasion, ForceOfWill, EnergyShieldLib, Reaver, SearingChargeLib, HyperdenseAlloyLib, BulwarkLib, ShotCallerLib, RepulsiveCoatingLib, ShredderVolleyLib
globals
private constant real ArmorReductionMinDamage = 1
private constant real EMPEnergyDamage = 3
private constant real EMPEnergyDamageAlt = 2
private trigger DamageModifier
private trigger AfterDamage
endglobals
function ApplyFlatArmor takes nothing returns nothing
if(udg_DamageEventAmount <= 0)then
return // skip armor if damage is already fully negated
endif
set udg_DamageEventAmount = RMaxBJ(ArmorReductionMinDamage, udg_DamageEventAmount - GetShotCallerFactor(udg_DamageEventSource, BlzGetUnitArmor(udg_DamageEventTarget)))
endfunction
function DamageModifierAction takes nothing returns nothing
// ignore Extractor damage
if(udg_DamageEventType == ExtractorDamageType)then
return
endif
// ignore Planet Killer damage, except for shields
if(udg_DamageEventType == PlanetKillerMissileDamageType or udg_DamageEventAttackT == udg_ATTACK_TYPE_CHAOS)then
call ApplyEnergyShield() // Singularity
//call ApplyPlanetaryScaleShield() // Planet
return
endif
// try to replace with a Missile
if(TryDamageSpawnMissile())then
return
endif
// try to evade a non-missile attack
if(TryApplyEvasion())then
return
endif
// apply damage boosts
call ApplyForceOfWill() // Singularity bonus
call ApplyReaver() // Havoc bonus
call ApplySearingCharge() // Sapper bonus
// apply % damage reductions
call ApplyHyperdenseAlloy() // Aegis bonus
call ApplyRepulsiveCoating() // Defender bonus
// apply flat damage reduction
call ApplyEnergyShield() // Singularity
//call ApplyPlanetaryScaleShield() // Planet
// apply regular armor
call ApplyFlatArmor() // all ships/structures/planets
// try redirecting damage with Bulwark
call TryApplyBulwark() // Aegis ability
endfunction
function ApplyEMPRounds takes nothing returns nothing
if(udg_DamageEventType == BulwarkDamageType)then
return // redirected Bulwark damage type cannot trigger energy drain
endif
if(GetUnitAbilityLevel(udg_DamageEventSource, 'A029') == 0)then
return // no ability
endif
if(GetPlayerTechCount(GetOwningPlayer(udg_DamageEventSource), 'R00M', true) == 0)then
return // not researched
endif
if(GetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA) <= 0)then
return // no mana
endif
if(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_HERO) or IsUnitType(udg_DamageEventTarget, UNIT_TYPE_ANCIENT))then
call SetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA, GetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA) - EMPEnergyDamageAlt)
else
call SetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA, GetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA) - EMPEnergyDamage)
endif
endfunction
function ApplyResources takes nothing returns nothing
if(GetResourceAmount(udg_DamageEventTarget) == 0)then
return // no resource
endif
call SetResourceAmount(udg_DamageEventTarget, R2I(GetUnitState(udg_DamageEventTarget, UNIT_STATE_LIFE)))
endfunction
function AfterDamageAction takes nothing returns nothing
call ApplyResources()
// ignore Planet Killer damage
if(udg_DamageEventType == PlanetKillerMissileDamageType or udg_DamageEventAttackT == udg_ATTACK_TYPE_CHAOS)then
return
endif
call ApplyEMPRounds()
if(udg_DamageEventType != MissileDamageType)then
return // shredder volley for non-missile damage
endif
call ApplyShredderVolley()
endfunction
function InitDamageHandler takes nothing returns nothing
set DamageModifier = CreateTrigger()
call TriggerRegisterVariableEvent(DamageModifier, "udg_DamageModifierEvent", EQUAL, 1.00)
call TriggerAddAction(DamageModifier, function DamageModifierAction)
set AfterDamage = CreateTrigger()
call TriggerRegisterVariableEvent(AfterDamage, "udg_AfterDamageEvent", EQUAL, 1.00)
call TriggerAddAction(AfterDamage, function AfterDamageAction)
endfunction
endlibrary
//===========================================================================
library BarrierLib initializer InitBarrier
globals
private constant integer BarrierAbilityId = 'A02J'
private constant integer BarrierHealthPerLevel = 50
private constant real BarrierDuration = 10
private trigger BarrierCastTrigger
endglobals
struct Barrier
private static hashtable ht = InitHashtable()
unit target
integer amount
timer expirationTimer
static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
static method create takes unit target, integer amount returns thistype
local thistype this = thistype.allocate()
set this.target = target
set this.amount = amount
set this.expirationTimer = CreateTimer()
call SaveInteger(thistype.ht, 0, GetHandleId(this.expirationTimer), this)
call SaveInteger(thistype.ht, 1, GetHandleId(this.target), this)
call TimerStart(this.expirationTimer, BarrierDuration, false, function thistype.OnExpire)
// apply bonus
call BlzSetUnitMaxHP(this.target, R2I(GetUnitState(this.target, UNIT_STATE_MAX_LIFE)) + this.amount)
call SetUnitState(this.target, UNIT_STATE_LIFE, GetUnitState(this.target, UNIT_STATE_LIFE) + this.amount)
return this
endmethod
method destroy takes nothing returns nothing
// unapply bonus
local real healthPercent = GetUnitState(this.target, UNIT_STATE_LIFE) / GetUnitState(this.target, UNIT_STATE_MAX_LIFE)
call BlzSetUnitMaxHP(this.target, R2I(GetUnitState(this.target, UNIT_STATE_MAX_LIFE)) - this.amount)
//call SetUnitState(this.target, UNIT_STATE_LIFE, healthPercent * GetUnitState(this.target, UNIT_STATE_MAX_LIFE))
// cleanup
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.expirationTimer))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.target))
call DestroyTimer(this.expirationTimer)
set this.expirationTimer = null
set this.target = null
call this.deallocate()
endmethod
static method Remove takes unit target returns nothing
local thistype this
if(HaveSavedInteger(thistype.ht, 1, GetHandleId(target)))then
set this = LoadInteger(thistype.ht, 1, GetHandleId(target))
call this.destroy()
endif
endmethod
static method SetBarrier takes unit target, integer level returns nothing
call thistype.Remove(target)
call thistype.create(target, level * BarrierHealthPerLevel)
endmethod
endstruct
private function BarrierCondition takes nothing returns boolean
return GetSpellAbilityId() == BarrierAbilityId
endfunction
private function BarrierAction takes nothing returns nothing
call Barrier.SetBarrier(GetSpellTargetUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), BarrierAbilityId))
endfunction
private function InitBarrier takes nothing returns nothing
set BarrierCastTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(BarrierCastTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(BarrierCastTrigger, Condition(function BarrierCondition))
call TriggerAddAction(BarrierCastTrigger, function BarrierAction)
endfunction
endlibrary
library BulwarkLib initializer InitBulwark requires LightningBounceAbilityLib, LinkedLightningEffectLib, MathLib
globals
private constant integer BulwarkAbilityId = 'A02K'
private constant integer BulwarkAbilitySfxId = 'A033'
private constant integer BulwarkBuffId = 'A00O'
// abilty effect
private constant integer BounceBase = 2
private constant integer BouncePerLevel = 2
private constant real Duration = 20
private constant real RedirectDamageFactor = 0.5
private constant real LeashRange = 1200
private constant real LeashCheckInterval = 0.2
// leash effect
private constant string LeashEffectCode = "BLBM"
private constant real LeashEffectDuration = Duration
private constant real LeashEffectFadeOutPoint = Duration + 0.3
// deviation effect
private constant string DeviationEffectCode = "BLNL"
private constant real DeviationEffectDuration = 0.4
private constant real DeviationEffectFadeOutPoint = 0.1
//private constant string DeviationImpactEffectPath = "Abilities\\Spells\\Orc\\LightningShield\\LightningShieldBuff.mdl"
// bounce effect
private constant real BounceDelay = 0.1
private constant real BounceRadius = 500
private constant string LightningEffectCode = "HLFX"
private constant real LightningEffectDuration = 0.8
private constant real LightningEffectFadeOutPoint = 0.5
private LightningBounceAbility BounceAbilityLevel1
private LightningBounceAbility BounceAbilityLevel2
private LightningBounceAbility BounceAbilityLevel3
private trigger BulwarkCastTrigger
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct Bulwark
private static hashtable ht = InitHashtable()
unit source
unit target
timer leashCheckTimer
timer expirationTimer
trigger deathTrigger
LinkedLightningEffect leashEffect
private static method OnLeashCheck takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
if(IsWithinDistance(GetUnitX(this.source), GetUnitY(this.source), GetUnitX(this.target), GetUnitY(this.target), LeashRange))then
return // still in range, nothing to do
endif
call this.destroy()
endmethod
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 2, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
static method create takes unit source, unit target returns thistype
local thistype this = thistype.allocate()
set this.source = source
set this.target = target
set this.leashCheckTimer = CreateTimer()
call TimerStart(this.leashCheckTimer, LeashCheckInterval, true, function thistype.OnLeashCheck)
call SaveInteger(thistype.ht, 0, GetHandleId(this.leashCheckTimer), this)
set this.expirationTimer = CreateTimer()
call TimerStart(this.expirationTimer, Duration, true, function thistype.OnExpire)
call SaveInteger(thistype.ht, 1, GetHandleId(this.expirationTimer), this)
set this.deathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.deathTrigger, this.source, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.deathTrigger, this.target, EVENT_UNIT_DEATH)
call TriggerAddAction(this.deathTrigger, function thistype.OnDeath)
call SaveInteger(thistype.ht, 2, GetHandleId(this.deathTrigger), this)
set this.leashEffect = LinkedLightningEffect.create(this.source, this.target, LeashEffectCode, LeashEffectDuration, LeashEffectFadeOutPoint)
call UnitAddAbility(this.target, BulwarkAbilitySfxId)
call BlzUnitDisableAbility(this.target, BulwarkAbilitySfxId, false, true)
call SaveInteger(thistype.ht, 3, GetHandleId(this.target), this)
return this
endmethod
method destroy takes nothing returns nothing
call UnitRemoveAbility(this.target, BulwarkAbilitySfxId)
call UnitRemoveAbility(this.target, BulwarkBuffId)
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.leashCheckTimer))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.expirationTimer))
call RemoveSavedInteger(thistype.ht, 2, GetHandleId(this.deathTrigger))
call RemoveSavedInteger(thistype.ht, 3, GetHandleId(this.target))
call DestroyTimer(this.leashCheckTimer)
call DestroyTimer(this.expirationTimer)
call DestroyTrigger(this.deathTrigger)
call this.leashEffect.ResetExpirationTimer(0.3, 0)
set this.source = null
set this.target = null
set this.leashCheckTimer = null
set this.expirationTimer = null
set this.deathTrigger = null
call this.deallocate()
endmethod
static method GetBulwarkSource takes unit target returns unit
local thistype this
if(HaveSavedInteger(thistype.ht, 3, GetHandleId(target)))then
set this = LoadInteger(thistype.ht, 3, GetHandleId(target))
return this.source
endif
return null
endmethod
static method Remove takes unit target returns nothing
local thistype this
if(HaveSavedInteger(thistype.ht, 3, GetHandleId(target)))then
set this = LoadInteger(thistype.ht, 3, GetHandleId(target))
call this.destroy()
endif
endmethod
static method SetBulwark takes unit source, unit target returns nothing
call thistype.Remove(target)
call thistype.create(source, target)
endmethod
endstruct
private function ApplyBulwarkCondition takes nothing returns boolean
if(udg_DamageEventType == BulwarkDamageType)then
return false // can't trigger Bulwark effect off of redirect Bulwark damage
endif
return true
endfunction
private function ApplyBulwarkAction takes nothing returns nothing
local unit source = Bulwark.GetBulwarkSource(udg_DamageEventTarget)
if(source == null)then
return // no bulwark active, nothing to do
endif
// reduce incoming damage for target
set udg_DamageEventAmount = udg_DamageEventAmount / 2
// deal same amount of damage to source
set udg_NextDamageType = BulwarkDamageType
call UnitDamageTarget(udg_DamageEventSource, source, udg_DamageEventAmount, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//call TriggerEvaluate(udg_ClearDamageEvent)
//call DestroyEffect(AddSpecialEffectTarget(DeviationImpactEffectPath, source, "origin"))
call LinkedLightningEffect.create(udg_DamageEventTarget, source, DeviationEffectCode, DeviationEffectDuration, DeviationEffectFadeOutPoint)
endfunction
function TryApplyBulwark takes nothing returns nothing
if(ApplyBulwarkCondition())then
call ApplyBulwarkAction()
endif
endfunction
private function BulwarkTargetFilter takes unit source, unit target returns boolean
if(source == target)then
return false // can't hit the caster
endif
if(UnitAlive(target) == false)then
return false
endif
if(IsUnitType(target, UNIT_TYPE_ANCIENT) or IsUnitType(target, UNIT_TYPE_STRUCTURE))then
return false
endif
if(GetUnitAbilityLevel(target, BulwarkBuffId) > 0)then
return false // already affected
endif
return IsUnitAlly(target, GetOwningPlayer(source)) or GetOwningPlayer(source) == GetOwningPlayer(target)
endfunction
private function BulwarkEffectCallback takes unit source, unit target returns nothing
call Debug("BulwarkEffectCallback")
call Bulwark.SetBulwark(source, target)
endfunction
private function BulwarkCondition takes nothing returns boolean
return GetSpellAbilityId() == BulwarkAbilityId
endfunction
private function BulwarkAction takes nothing returns nothing
if(GetUnitAbilityLevel(GetSpellAbilityUnit(), BulwarkAbilityId) == 1)then
call Debug("BulwarkAction 1")
call BounceAbilityLevel1.StartBounce(GetSpellAbilityUnit(), GetSpellTargetUnit())
elseif(GetUnitAbilityLevel(GetSpellAbilityUnit(), BulwarkAbilityId) == 2)then
call Debug("BulwarkAction 2")
call BounceAbilityLevel2.StartBounce(GetSpellAbilityUnit(), GetSpellTargetUnit())
else
call Debug("BulwarkAction 3")
call BounceAbilityLevel3.StartBounce(GetSpellAbilityUnit(), GetSpellTargetUnit())
endif
endfunction
private function InitBulwark takes nothing returns nothing
set BulwarkCastTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(BulwarkCastTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(BulwarkCastTrigger, Condition(function BulwarkCondition))
call TriggerAddAction(BulwarkCastTrigger, function BulwarkAction)
set BounceAbilityLevel1 = LightningBounceAbility.create(BounceDelay, BounceRadius, BounceBase + BouncePerLevel * 1, LightningEffectCode, LightningEffectDuration, LightningEffectFadeOutPoint, BulwarkTargetFilter, BulwarkEffectCallback)
set BounceAbilityLevel2 = LightningBounceAbility.create(BounceDelay, BounceRadius, BounceBase + BouncePerLevel * 2, LightningEffectCode, LightningEffectDuration, LightningEffectFadeOutPoint, BulwarkTargetFilter, BulwarkEffectCallback)
set BounceAbilityLevel3 = LightningBounceAbility.create(BounceDelay, BounceRadius, BounceBase + BouncePerLevel * 3, LightningEffectCode, LightningEffectDuration, LightningEffectFadeOutPoint, BulwarkTargetFilter, BulwarkEffectCallback)
endfunction
endlibrary
library ParagonLib initializer InitParagon
globals
private constant integer ParagonAbilityId = 'A02M'
private constant integer BulwarkAbilityId = 'A02K'
private constant integer BarrierAbilityId = 'A02J'
private constant integer IonStormAbilityId = 'A01H'
private constant real EnergyPullUpValue = 200
private trigger ParagonTrigger
endglobals
private function ParagonCondition takes nothing returns boolean
return GetSpellAbilityId() == ParagonAbilityId
endfunction
private function ParagonAction takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local real mana = GetUnitState(caster, UNIT_STATE_MANA)
call BlzEndUnitAbilityCooldown(caster, BulwarkAbilityId)
call BlzEndUnitAbilityCooldown(caster, BarrierAbilityId)
call BlzEndUnitAbilityCooldown(caster, IonStormAbilityId)
if(mana < EnergyPullUpValue)then
call SetUnitState(caster, UNIT_STATE_MANA, EnergyPullUpValue)
endif
set caster = null
endfunction
private function InitParagon takes nothing returns nothing
set ParagonTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(ParagonTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(ParagonTrigger, Condition(function ParagonCondition))
call TriggerAddAction(ParagonTrigger, function ParagonAction)
endfunction
endlibrary
library Reaver
function ReaverCondition takes nothing returns boolean
if(GetUnitAbilityLevel(udg_DamageEventSource, 'A01G') == 0)then
return false // no ability
endif
if(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_ANCIENT))then
return false // doesn't affect planets
endif
// structure or flagship
return IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE) or IsUnitType(udg_DamageEventTarget, UNIT_TYPE_HERO)
endfunction
function ReaverAction takes nothing returns nothing
set udg_DamageEventAmount = udg_DamageEventAmount * 1.25
endfunction
function ApplyReaver takes nothing returns nothing
if(ReaverCondition())then
call ReaverAction()
endif
endfunction
endlibrary
//===========================================================================
function InitTrig_Reaver takes nothing returns nothing
endfunction
library ShotCallerLib
globals
private constant integer ShotCaller10 = 'B001'
private constant integer ShotCaller20 = 'B009'
private constant integer ShotCaller30 = 'B00A'
endglobals
function GetShotCallerFactor takes unit attacker, real value returns real
if(GetUnitAbilityLevel(attacker, ShotCaller10) > 0)then
return value * 0.9
endif
if(GetUnitAbilityLevel(attacker, ShotCaller20) > 0)then
return value * 0.8
endif
if(GetUnitAbilityLevel(attacker, ShotCaller30) > 0)then
return value * 0.7
endif
return value
endfunction
endlibrary
function AnnihilateCondition takes nothing returns boolean
return GetSpellAbilityId() == 'A01M'
endfunction
function AnnihilateAction takes nothing returns nothing
local unit caster = GetSpellAbilityUnit()
local unit target = GetSpellTargetUnit()
local integer level = GetUnitAbilityLevel(caster, 'A01M')
local integer rocket = 5 + 2 * level
local real damage = 10 + 10 * level
local integer i = 0
local Missile m
loop
exitwhen i == rocket or UnitAlive(caster) == false or UnitAlive(target) == false
set m = Missile.create(caster, 'A01M', level - 1)
call m.SetTargetUnit(target)
call TriggerSleepAction(0.3)
set i = i + 1
endloop
set caster = null
set target = null
endfunction
//===========================================================================
function InitTrig_Annihilate takes nothing returns nothing
set gg_trg_Annihilate = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Annihilate, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Annihilate, Condition(function AnnihilateCondition))
call TriggerAddAction(gg_trg_Annihilate, function AnnihilateAction)
call RegisterMissileSource('A01M', 0, 0, 0, "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl", 1.5, 600, 1200, HomingHigh, 30, 20, ExplosiveDamage, 100, 0)
call RegisterMissileSource('A01M', 0, 0, 0, "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl", 1.5, 600, 1200, HomingHigh, 30, 30, ExplosiveDamage, 100, 0)
call RegisterMissileSource('A01M', 0, 0, 0, "Abilities\\Weapons\\BoatMissile\\BoatMissile.mdl", 1.5, 600, 1200, HomingHigh, 30, 40, ExplosiveDamage, 100, 0)
endfunction
library JugernautMinesLib initializer InitJugernautMines requires MissileSystem
globals
private constant integer JugernautMineAbilityId = 'A01S'
private constant integer MineType1 = 'n009'
private constant integer MineType2 = 'n00A'
private constant integer MineType3 = 'n00B'
private constant real MineDuration = 120
private constant real MineActivationDelay = 5
private constant real MineDamagePerLevel = 40
private constant real MineRadiusPerLevel = 100
private trigger OnCastTrigger
private trigger OnEnterTrigger
endglobals
struct JugernautMine
private static hashtable ht = InitHashtable()
unit mine
real damage
real radius
boolean isActive
trigger activate
trigger detonate
trigger death
private static method OnActivate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
call TriggerRegisterUnitInRange(this.detonate, this.mine, this.radius / 2, null)
set this.isActive = true
endmethod
private method DetonateCondition takes unit u returns boolean
return u != this.mine and IsUnitEnemy(u, GetOwningPlayer(this.mine)) and GetUnitAbilityLevel(u, 'Aloc') == 0
endmethod
private method Detonate takes nothing returns nothing
local unit mine = this.mine
local real damage = this.damage
local real radius = this.radius
call this.destroy()
call KillUnit(mine)
//call SetUnitAnimation(this.mine, "death")
call TriggerSleepAction(0.3)
call DamageArea(mine, GetUnitX(mine), GetUnitY(mine), radius, damage, AttackTypes[EnergyDamage], mine)
call TriggerSleepAction(0.6)
call RemoveUnit(mine)
endmethod
private static method OnDetonate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
if(GetEnteringUnit() != null and this.DetonateCondition(GetEnteringUnit()) == false)then
return
endif
if(this.isActive and GetUnitAbilityLevel(this.mine, 'B00Q') == 0)then
call this.Detonate()
else
call this.destroy()
endif
endmethod
static method create takes unit mine returns thistype
local thistype this = thistype.allocate()
set this.mine = mine
set this.damage = GetUnitLevel(this.mine) * MineDamagePerLevel
set this.radius = MineRadiusPerLevel + GetUnitLevel(this.mine) * MineRadiusPerLevel
set this.activate = CreateTrigger()
call SaveInteger(thistype.ht, 0, GetHandleId(this.activate), this)
call TriggerRegisterTimerEvent(this.activate, MineActivationDelay, false)
call TriggerAddAction(this.activate, function thistype.OnActivate)
set this.detonate = CreateTrigger()
call SaveInteger(thistype.ht, 1, GetHandleId(this.detonate), this)
call TriggerRegisterUnitEvent(this.detonate, this.mine, EVENT_UNIT_DEATH)
call TriggerAddAction(this.detonate, function thistype.OnDetonate)
set this.isActive = false
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.activate))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.detonate))
call DestroyTrigger(this.activate)
call DestroyTrigger(this.detonate)
set this.mine = null
set this.activate = null
set this.detonate = null
call this.deallocate()
endmethod
endstruct
private function OnCastCondition takes nothing returns boolean
return GetSpellAbilityId() == JugernautMineAbilityId
endfunction
private function OnCastAction takes nothing returns nothing
local integer level = GetUnitAbilityLevel(GetSpellAbilityUnit(), JugernautMineAbilityId)
if(level == 1)then
call CreateUnit(GetOwningPlayer(GetSpellAbilityUnit()), MineType1, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
elseif(level == 2)then
call CreateUnit(GetOwningPlayer(GetSpellAbilityUnit()), MineType2, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
else
call CreateUnit(GetOwningPlayer(GetSpellAbilityUnit()), MineType3, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
endif
endfunction
private function OnEnterCondition takes nothing returns boolean
local integer typeId = GetUnitTypeId(GetEnteringUnit())
return typeId == MineType1 or typeId == MineType2 or typeId == MineType3
endfunction
private function OnEnterAction takes nothing returns nothing
call JugernautMine.create(GetEnteringUnit())
endfunction
private function InitJugernautMines takes nothing returns nothing
set OnCastTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(OnCastTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(OnCastTrigger, Condition(function OnCastCondition))
call TriggerAddAction(OnCastTrigger, function OnCastAction)
set OnEnterTrigger = CreateTrigger()
call TriggerRegisterEnterRectSimple(OnEnterTrigger, bj_mapInitialPlayableArea)
call TriggerAddCondition(OnEnterTrigger, Condition(function OnEnterCondition))
call TriggerAddAction(OnEnterTrigger, function OnEnterAction)
endfunction
endlibrary
library DisintegrateLib initializer InitDisintegrate requires MissileSystem, MissilesRepository
globals
private constant integer DisintegrateAbilityId = 'A01A'
private constant real DisintegrateDamageTotal = 400
private constant real DisintegrateDuration = 6
private constant real DisintegrateDamageInterval = 0.05
private constant real DisintegrateDamagePerInterval = DisintegrateDamageTotal * DisintegrateDamageInterval / DisintegrateDuration
//private constant string DisintegrateMissilePath = "war3mapImported\\BeamMissile.mdx"
private constant string DisintegrateMissilePath = "Abilities\\Spells\\Undead\\OrbOfDeath\\OrbOfDeathMissile.mdl"
private trigger DisintegrateTrigger
endglobals
struct Disintegrate
private static hashtable ht = InitHashtable()
unit caster
timer updateTimer
trigger expirationTrigger
private static method OnUpdate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
call Missile.create(this.caster, DisintegrateAbilityId, 0)
endmethod
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
static method create takes unit caster returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.updateTimer = CreateTimer()
call SaveInteger(thistype.ht, 0, GetHandleId(this.updateTimer), this)
call TimerStart(this.updateTimer, DisintegrateDamageInterval, true, function thistype.OnUpdate)
set this.expirationTrigger = CreateTrigger()
call SaveInteger(thistype.ht, 1, GetHandleId(this.expirationTrigger), this)
call TriggerRegisterTimerEvent(this.expirationTrigger, DisintegrateDuration, false)
call TriggerRegisterUnitEvent(this.expirationTrigger, this.caster, EVENT_UNIT_DEATH)
call TriggerAddAction(this.expirationTrigger, function thistype.OnExpire)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.updateTimer))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.expirationTrigger))
call DestroyTimer(this.updateTimer)
call DestroyTrigger(this.expirationTrigger)
set this.caster = null
set this.updateTimer = null
set this.expirationTrigger = null
call this.deallocate()
endmethod
endstruct
private function DisintegrateCondition takes nothing returns boolean
return GetSpellAbilityId() == DisintegrateAbilityId
endfunction
private function DisintegrateAction takes nothing returns nothing
call Disintegrate.create(GetSpellAbilityUnit())
endfunction
private function InitDisintegrate takes nothing returns nothing
set DisintegrateTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(DisintegrateTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(DisintegrateTrigger, Condition(function DisintegrateCondition))
call TriggerAddAction(DisintegrateTrigger, function DisintegrateAction)
call RegisterMissileSource(DisintegrateAbilityId, 0, 0, 0, DisintegrateMissilePath, 2, 600, 2400, 0, 250, DisintegrateDamagePerInterval, PlanetKillerDamage, 0, 1)
endfunction
endlibrary
library DrainEnergyLib initializer InitDrainEnergy requires BarrierLib, BulwarkLib, EnergyShieldLib
globals
private constant integer DrainEnergyAbilityId = 'A00Y'
private constant real EnergyPerLevel = 75
private trigger DrainEnergyTrigger
endglobals
private function DrainEnergyCondition takes nothing returns boolean
return GetSpellAbilityId() == DrainEnergyAbilityId
endfunction
private function DrainEnergyAction takes nothing returns nothing
local real drainValue = EnergyPerLevel * GetUnitAbilityLevel(GetSpellAbilityUnit(), DrainEnergyAbilityId)
local real energyDamageFactor = GetHardenedShieldFactor(GetSpellTargetUnit())
local real energy = RMinBJ(drainValue, GetUnitState(GetSpellTargetUnit(), UNIT_STATE_MANA)) * energyDamageFactor
call Barrier.Remove(GetSpellTargetUnit())
call Bulwark.Remove(GetSpellTargetUnit())
if(energy > 0)then
call SetUnitState(GetSpellAbilityUnit(), UNIT_STATE_MANA, GetUnitState(GetSpellAbilityUnit(), UNIT_STATE_MANA) + energy)
call SetUnitState(GetSpellTargetUnit(), UNIT_STATE_MANA, GetUnitState(GetSpellTargetUnit(), UNIT_STATE_MANA) - energy)
endif
endfunction
private function InitDrainEnergy takes nothing returns nothing
set DrainEnergyTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(DrainEnergyTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(DrainEnergyTrigger, Condition(function DrainEnergyCondition))
call TriggerAddAction(DrainEnergyTrigger, function DrainEnergyAction)
endfunction
endlibrary
library EnergyShieldLib
globals
private constant integer EnergyShieldAbilityId = 'A00F'
private constant integer HardenedShieldAbilityId = 'A019'
private constant integer EMPRoundsAbilityId = 'A029'
private constant real HardenedShieldReductionPerLevel = 0.15
private constant real EMPRoundsDamageIncrease = 1
endglobals
function GetHardenedShieldFactor takes unit u returns real
return 1 - GetUnitAbilityLevel(u, HardenedShieldAbilityId) * HardenedShieldReductionPerLevel
endfunction
function GetEMPRoundsFactor takes unit u returns real
return 1 + GetUnitAbilityLevel(u, EMPRoundsAbilityId) * EMPRoundsDamageIncrease
endfunction
private function GetPlanetKillerFactor takes nothing returns real
if(udg_DamageEventType == PlanetKillerMissileDamageType)then
return 2.0
else
return 1.0
endif
endfunction
private function EnergyShieldCondition takes nothing returns boolean
return GetUnitAbilityLevel(udg_DamageEventTarget, EnergyShieldAbilityId) > 0 and GetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA) >= 1
endfunction
private function EnergyShieldAction takes nothing returns nothing
local real hardenedShieldFactor = GetHardenedShieldFactor(udg_DamageEventTarget)
local real empRoundFactor = GetEMPRoundsFactor(udg_DamageEventSource)
local real planetKillerFactor = GetPlanetKillerFactor()
local real manaDamageFactor = hardenedShieldFactor * empRoundFactor * planetKillerFactor
local real mana = GetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA)
local real manaDamage = RMinBJ(udg_DamageEventAmount * manaDamageFactor, mana)
local real passthroughDamage = RMaxBJ(udg_DamageEventAmount - manaDamage / manaDamageFactor, 0)
set udg_DamageEventAmount = passthroughDamage
call SetUnitState(udg_DamageEventTarget, UNIT_STATE_MANA, mana - manaDamage)
endfunction
function ApplyEnergyShield takes nothing returns nothing
if(EnergyShieldCondition())then
call EnergyShieldAction()
endif
endfunction
endlibrary
library ForceOfWill
function ForceOfWillCondition takes nothing returns boolean
return GetUnitAbilityLevel(udg_DamageEventSource, 'A01C') > 0
endfunction
function ForceOfWillAction takes nothing returns nothing
local unit source = udg_DamageEventSource
local unit target = udg_DamageEventTarget
local real manaPercent = GetUnitStatePercent(source, UNIT_STATE_MANA, UNIT_STATE_MAX_MANA) / 100 // divide by 100 because GetUnitStatePercent gives a value between 0 and 100
if(manaPercent > 0.5)then
set udg_DamageEventAmount = udg_DamageEventAmount * 1.66
call DestroyEffect(AddSpellEffectById('A01C', EFFECT_TYPE_TARGET, GetUnitX(target), GetUnitY(target)))
endif
set source = null
set target = null
endfunction
function ApplyForceOfWill takes nothing returns nothing
if(ForceOfWillCondition())then
call ForceOfWillAction()
endif
endfunction
endlibrary
//===========================================================================
function InitTrig_ForceOfWill takes nothing returns nothing
endfunction
library GravityWell initializer InitGravityWell requires MissileSystem
globals
private integer GravityWellAbilityId = 'A00T'
private boolean GravityWellKillCaster = false
private real GravityWellPullDurationPerLevel = 5
private real GravityWellPullRange = 325
private real GravityWellPullStrength = 125
private real GravityWellPullPeriod = 0.02
private real GravityWellPullMinDistance = 10
private real GravityWellDamagePerSecond = 6
private string GravityWellEffect = "war3mapImported\\BlackHole.mdx"
private integer GravityWellPoolTimer = 0
private integer GravityWellExpireTimer = 1
private trigger GravityWellStartTrigger
endglobals
struct GravityWellPull
private static hashtable ht = InitHashtable()
private static location loc = null
private static group untracking = CreateGroup()
private static unit enumCaster
private unit caster
private location l
private timer updateTimer
private timer expirationTimer
private effect e
private group affectedUnits
static method PullUnit takes nothing returns nothing
local unit u = GetEnumUnit()
local location uLoc = GetUnitLoc(u)
local real distance = DistanceBetweenPoints(thistype.loc, uLoc)
local real angle = AngleBetweenPoints(thistype.loc, uLoc)
local real pullDistanceFactor = 1 - (distance * distance) / (GravityWellPullRange * GravityWellPullRange * GravityWellPullRange)
local real newDistance = RMaxBJ(GravityWellPullMinDistance, distance - GravityWellPullStrength * pullDistanceFactor * GravityWellPullPeriod)
local real newAngle = angle + 90 * GravityWellPullPeriod * pullDistanceFactor
call RemoveLocation(uLoc)
set uLoc = PolarProjectionBJ(thistype.loc, newDistance, newAngle)
call SetUnitX(u, GetLocationX(uLoc))
call SetUnitY(u, GetLocationY(uLoc))
//call SetUnitScale(u, 1-pullDistanceFactor, 1-pullDistanceFactor, 1-pullDistanceFactor)
//call UnitAddAbility(u, 'Aloc')
call DamageM(thistype.enumCaster, u, GravityWellDamagePerSecond * GravityWellPullPeriod, AttackTypes[PlanetKillerDamage])
call RemoveLocation(uLoc)
set uLoc = null
endmethod
static method FilterAffectedUnit takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean notBuilding = IsUnitType(u, UNIT_TYPE_STRUCTURE) == false
local boolean notLocust = GetUnitAbilityLevel(u, 'aloc') == 0
set u = null
return notBuilding and notLocust
endmethod
static method UntrackUnit takes nothing returns nothing
//call SetUnitScale(GetEnumUnit(), 1, 1, 1)
//call UnitRemoveAbility(GetEnumUnit(), 'Aloc')
endmethod
static method FindUnitsToUntrack takes nothing returns nothing
local location l = GetUnitLoc(GetEnumUnit())
if(DistanceBetweenPoints(l, thistype.loc) > GravityWellPullRange)then
call GroupAddUnit(thistype.untracking, GetEnumUnit())
endif
call RemoveLocation(l)
set l = null
endmethod
private method UpdateAffectedUnits takes nothing returns nothing
// find units that are no longer affected
call ForGroup(this.affectedUnits, function thistype.FindUnitsToUntrack)
call ForGroup(thistype.untracking, function thistype.UntrackUnit)
call GroupClear(thistype.untracking)
// find units that are supposed to be affected
call GroupClear(this.affectedUnits)
call GroupEnumUnitsInRangeOfLoc(this.affectedUnits, this.l, GravityWellPullRange, function thistype.FilterAffectedUnit)
endmethod
private method ApplyPull takes nothing returns nothing
set thistype.enumCaster = this.caster
call ForGroup(this.affectedUnits, function thistype.PullUnit)
endmethod
private method UpdateEffect takes nothing returns nothing
set thistype.loc = this.l
call UpdateAffectedUnits()
call this.ApplyPull()
set thistype.loc = null
endmethod
private static method OnUpdate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, GravityWellPoolTimer, GetHandleId(GetExpiredTimer()))
call this.UpdateEffect()
endmethod
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, GravityWellExpireTimer, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
static method create takes unit caster, location l, integer level returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.l = l
set this.e = AddSpecialEffect(GravityWellEffect, GetLocationX(l), GetLocationY(l))
set this.affectedUnits = CreateGroup()
set this.updateTimer = CreateTimer()
call TimerStart(this.updateTimer, GravityWellPullPeriod, true, function thistype.OnUpdate)
call SaveInteger(thistype.ht, GravityWellPoolTimer, GetHandleId(this.updateTimer), this)
set this.expirationTimer = CreateTimer()
call TimerStart(this.expirationTimer, level * GravityWellPullDurationPerLevel, false, function thistype.OnExpire)
call SaveInteger(thistype.ht, GravityWellExpireTimer, GetHandleId(this.expirationTimer), this)
return this
endmethod
method destroy takes nothing returns nothing
call ForGroup(this.affectedUnits, function thistype.UntrackUnit)
call RemoveSavedInteger(thistype.ht, GravityWellPoolTimer, GetHandleId(this.updateTimer))
call RemoveSavedInteger(thistype.ht, GravityWellExpireTimer, GetHandleId(this.expirationTimer))
call RemoveLocation(this.l)
call DestroyTimer(this.updateTimer)
call DestroyTimer(this.expirationTimer)
call DestroyEffect(this.e)
call DestroyGroup(this.affectedUnits)
set this.caster = null
set this.l = null
set this.updateTimer = null
set this.expirationTimer = null
set this.affectedUnits = null
call this.deallocate()
endmethod
endstruct
private function GravityWellStartCondition takes nothing returns boolean
return GetSpellAbilityId() == GravityWellAbilityId
endfunction
private function GravityWellStartAction takes nothing returns nothing
call GravityWellPull.create(GetSpellAbilityUnit(), GetSpellTargetLoc(), GetUnitAbilityLevel(GetSpellAbilityUnit(), GravityWellAbilityId))
endfunction
private function InitGravityWell takes nothing returns nothing
set GravityWellStartTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(GravityWellStartTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(GravityWellStartTrigger, Condition(function GravityWellStartCondition))
call TriggerAddAction(GravityWellStartTrigger, function GravityWellStartAction)
endfunction
endlibrary
//===========================================================================
function InitTrig_GravityWell takes nothing returns nothing
endfunction
library WarpDive initializer InitWarpDive
globals
private integer WarpDiveAbility = 'A01B'
private integer WarpDiveEffectAbility = 'A01E'
private real WarpDivePullArrivalDistance = 200
private real WarpDivePullRange = 500
private real WarpDivePullSpeed = 1500
private real WarpDivePullPeriod = 0.01
private real WarpDivePullWarmupDelay = 5.5
private string WarpDiveEffect = "war3mapImported\\BlackHole.mdx"
private string WarpDiveWarmupSound = "Sound\\Ambient\\DoodadEffects\\ShimmeringPortalBirth.wav"
private string WarpDiveStartSound = "Sound\\Ambient\\DoodadEffects\\LichKingDream.wav"
private integer WarpDivePullLocationMap = 0
private trigger WarpDiveStartTrigger
endglobals
struct WarpDivePull
private static hashtable ht = InitHashtable()
private static location loc = null
private static real angle
private static group untracking = CreateGroup()
private unit caster
private location destinationLoc
private location casterLoc
private timer warmupTimer
private timer updateTimer
private effect e
private group affectedUnits
static method PullUnit takes nothing returns nothing
local unit u = GetEnumUnit()
local location uLoc = GetUnitLoc(u)
local location newULoc = PolarProjectionBJ(uLoc, WarpDivePullSpeed * WarpDivePullPeriod, thistype.angle)
call SetUnitX(u, GetLocationX(newULoc))
call SetUnitY(u, GetLocationY(newULoc))
if(GetUnitAbilityLevel(u, WarpDiveEffectAbility) == 0)then
call UnitAddAbility(u, WarpDiveEffectAbility)
call IssueImmediateOrder(u, "holdposition")
endif
call SetUnitFacing(u, thistype.angle)
call RemoveLocation(uLoc)
call RemoveLocation(newULoc)
set uLoc = null
set newULoc = null
endmethod
static method FilterAffectedUnit takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean notBuilding = IsUnitType(u, UNIT_TYPE_STRUCTURE) == false
local boolean notLocust = GetUnitAbilityLevel(u, 'aloc') == 0
set u = null
return notBuilding and notLocust
endmethod
static method UntrackUnit takes nothing returns nothing
call UnitRemoveAbility(GetEnumUnit(), WarpDiveEffectAbility)
endmethod
static method FindUnitsToUntrack takes nothing returns nothing
local location l = GetUnitLoc(GetEnumUnit())
if(DistanceBetweenPoints(l, thistype.loc) > WarpDivePullRange)then
call GroupAddUnit(thistype.untracking, GetEnumUnit())
endif
call RemoveLocation(l)
set l = null
endmethod
private method UpdateAffectedUnits takes nothing returns nothing
// find units that are no longer affected
call ForGroup(this.affectedUnits, function thistype.FindUnitsToUntrack)
call ForGroup(thistype.untracking, function thistype.UntrackUnit)
call GroupClear(thistype.untracking)
// find units that are supposed to be affected
call GroupClear(this.affectedUnits)
call GroupEnumUnitsInRangeOfLoc(this.affectedUnits, this.casterLoc, WarpDivePullRange, function thistype.FilterAffectedUnit)
endmethod
private method ApplyPull takes nothing returns nothing
call ForGroup(this.affectedUnits, function thistype.PullUnit)
endmethod
private method UpdateEffect takes nothing returns nothing
set thistype.loc = this.casterLoc
set thistype.angle = AngleBetweenPoints(this.casterLoc, this.destinationLoc)
call UpdateAffectedUnits()
call this.ApplyPull()
call RemoveLocation(this.casterLoc)
set this.casterLoc = GetUnitLoc(this.caster)
set thistype.loc = null
endmethod
private method IsFinished takes nothing returns boolean
return DistanceBetweenPoints(this.casterLoc, this.destinationLoc) <= WarpDivePullArrivalDistance
endmethod
static method Update takes nothing returns nothing
local timer t = GetExpiredTimer()
local thistype this = LoadInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(t))
set t = null
if(this.IsFinished())then
call this.destroy()
return
endif
call this.UpdateEffect()
endmethod
static method WarmupDone takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(GetExpiredTimer()))
call TimerStart(this.updateTimer, WarpDivePullPeriod, true, function thistype.Update)
call DisplayTextToForce(GetPlayersAll(), "Warp Dive started!")
call PlaySound(WarpDiveStartSound)
endmethod
static method create takes unit caster, location destination returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.destinationLoc = destination
set this.casterLoc = GetUnitLoc(this.caster)
set this.warmupTimer = CreateTimer()
set this.updateTimer = CreateTimer()
set this.e = AddSpecialEffectTarget(WarpDiveEffect, this.caster, "origin")
set this.affectedUnits = CreateGroup()
call TimerStart(this.warmupTimer, WarpDivePullWarmupDelay, false, function thistype.WarmupDone)
call SaveInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(this.warmupTimer), this)
call SaveInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(this.updateTimer), this)
call IssueImmediateOrder(this.caster, "stop")
call PauseUnit(this.caster, true) // pause the caster so he can't interrupt the spell or deviate trajectory
// show the Warp Dive warmup alert
call DisplayTextToForce(GetPlayersAll(), "|cffff0000" + GetPlayerName(GetOwningPlayer(this.caster)) + " is initiating a Warp Dive!|r")
call PingMinimapEx(GetLocationX(this.destinationLoc), GetLocationY(this.destinationLoc), WarpDivePullWarmupDelay, 255, 0, 0, true)
call PlaySound(WarpDiveWarmupSound)
return this
endmethod
method destroy takes nothing returns nothing
call PauseUnit(this.caster, false) // unpause the caster
call ForGroup(this.affectedUnits, function thistype.UntrackUnit)
call RemoveSavedInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(this.warmupTimer))
call RemoveSavedInteger(thistype.ht, WarpDivePullLocationMap, GetHandleId(this.updateTimer))
call RemoveLocation(this.destinationLoc)
call RemoveLocation(this.casterLoc)
call DestroyTimer(this.warmupTimer)
call DestroyTimer(this.updateTimer)
call DestroyEffect(this.e)
call DestroyGroup(this.affectedUnits)
set this.caster = null
set this.destinationLoc = null
set this.casterLoc = null
set this.warmupTimer = null
set this.updateTimer = null
set this.affectedUnits = null
call this.deallocate()
endmethod
endstruct
private function WarpDiveStartCondition takes nothing returns boolean
return GetSpellAbilityId() == WarpDiveAbility
endfunction
private function WarpDiveStartAction takes nothing returns nothing
call WarpDivePull.create(GetSpellAbilityUnit(), GetSpellTargetLoc())
endfunction
private function InitWarpDive takes nothing returns nothing
set WarpDiveStartTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(WarpDiveStartTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition(WarpDiveStartTrigger, Condition(function WarpDiveStartCondition))
call TriggerAddAction(WarpDiveStartTrigger, function WarpDiveStartAction )
endfunction
endlibrary
//===========================================================================
function InitTrig_WarpDive takes nothing returns nothing
endfunction
library DeployRepairDronesLib initializer InitDeployRepairDrones requires SwarmSystemLib
globals
private constant integer DeployRepairDronesAbilityId = 'A02L'
private constant integer DeployRepairDronesunitTyeId = 'h00M'
private trigger RepairDronesTrigger
endglobals
private function DeployRepairDronesCondition takes nothing returns boolean
return GetSpellAbilityId() == DeployRepairDronesAbilityId
endfunction
private function DeployRepairDronesAction takes nothing returns nothing
call Swarm.create(GetSpellAbilityUnit(), GetSpellTargetUnit(), DeployRepairDronesAbilityId)
endfunction
private function InitDeployRepairDrones takes nothing returns nothing
set RepairDronesTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(RepairDronesTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(RepairDronesTrigger, Condition(function DeployRepairDronesCondition))
call TriggerAddAction(RepairDronesTrigger, function DeployRepairDronesAction)
call Swarm.DeclareSwarmAbilitySettings(DeployRepairDronesAbilityId, DeployRepairDronesunitTyeId, 5, 0.2, 0.8, true, 30, 250)
endfunction
endlibrary
library InterceptorDroneLib initializer InitInterceptorDrone
globals
private constant integer InterceptorDroneAbilityId = 'A02Q'
private constant integer InterceptAbilityId = 'A02G'
private constant integer InterceptorDroneTypeId1 = 'n00C'
private constant integer InterceptorDroneTypeId2 = 'n00D'
private constant integer InterceptorDroneTypeId3 = 'n00E'
private constant string InterceptLightningEffect = "RESB"
private constant real InterceptLightningDuration = 0.2
private constant real InterceptorDroneDuration = 30
private trigger OnCastTrigger
endglobals
struct Interception
private static hashtable ht = InitHashtable()
timer t
lightning e
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
static method create takes unit collider, real x, real y, real z returns thistype
local thistype this = thistype.allocate()
set this.t = CreateTimer()
call SaveInteger(thistype.ht, 0, GetHandleId(this.t), this)
call TimerStart(this.t, InterceptLightningDuration, false, function thistype.OnExpire)
set this.e = AddLightningEx(InterceptLightningEffect, true, GetUnitX(collider), GetUnitY(collider), GetUnitFlyHeight(collider), x, y, z)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.t))
call DestroyTimer(this.t)
call DestroyLightning(this.e)
set this.t = null
set this.e = null
call this.deallocate()
endmethod
endstruct
function TryInterceptMissile takes unit collider, attacktype missileDamageType,real x, real y, real z returns boolean
if(missileDamageType == ATTACK_TYPE_CHAOS)then
return false // can't intercept planet killer damage
endif
if(GetUnitAbilityLevel(collider, InterceptAbilityId) == 0)then
return false // not an interceptor
endif
call Interception.create(collider, x, y, z)
return true
endfunction
private function CreateDrone takes player p, integer typeId, real x, real y, real facing returns nothing
local unit u = CreateUnit(p, typeId, x, y, facing)
call SetUnitAnimation(u, "birth")
set u = null
endfunction
private function OnCastCondition takes nothing returns boolean
return GetSpellAbilityId() == InterceptorDroneAbilityId
endfunction
private function OnCastAction takes nothing returns nothing
local integer level = GetUnitAbilityLevel(GetSpellAbilityUnit(), InterceptorDroneAbilityId)
if(level == 1)then
call CreateDrone(GetOwningPlayer(GetSpellAbilityUnit()), InterceptorDroneTypeId1, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
elseif(level == 2)then
call CreateDrone(GetOwningPlayer(GetSpellAbilityUnit()), InterceptorDroneTypeId2, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
else
call CreateDrone(GetOwningPlayer(GetSpellAbilityUnit()), InterceptorDroneTypeId3, GetSpellTargetX(), GetSpellTargetY(), GetUnitFacing(GetSpellAbilityUnit()))
endif
endfunction
private function InitInterceptorDrone takes nothing returns nothing
set OnCastTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(OnCastTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(OnCastTrigger, Condition(function OnCastCondition))
call TriggerAddAction(OnCastTrigger, function OnCastAction)
endfunction
endlibrary
function Trig_DemolishPlanetaryModule_Conditions takes nothing returns boolean
if(not (GetSpellAbilityId() == 'A01T'))then
return false
endif
return true
endfunction
function Trig_DemolishPlanetaryModule_Actions takes nothing returns nothing
call RemoveItem(GetSpellTargetItem())
endfunction
//===========================================================================
function InitTrig_DemolishPlanetaryModule takes nothing returns nothing
set gg_trg_DemolishPlanetaryModule = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_DemolishPlanetaryModule, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_DemolishPlanetaryModule, Condition(function Trig_DemolishPlanetaryModule_Conditions))
call TriggerAddAction(gg_trg_DemolishPlanetaryModule, function Trig_DemolishPlanetaryModule_Actions)
endfunction
library GSAutocannonArrayLib initializer InitGSAutocannonArray requires AutocannonLib
globals
private constant integer ItemType = 'I004'
private constant integer ItemType2 = 'I00F'
private constant real MissileRange = 900
private constant real MissileCooldown = 2
private constant real ManaCost = 30
private constant real MissileDamage = 60
private constant real MissileSpeed = 1200
private trigger OnAcquire = CreateTrigger()
private trigger OnDrop = CreateTrigger()
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
private function SourceCondition takes unit source returns boolean
call Debug("SourceCondition")
return GetUnitState(source, UNIT_STATE_MANA) >= ManaCost and GetUnitAbilityLevel(source, 'B005') == 0
endfunction
private function FireAction takes unit source, unit target returns nothing
call Debug("FireAction")
call SetUnitState(source, UNIT_STATE_MANA, GetUnitState(source, UNIT_STATE_MANA) - ManaCost)
endfunction
private function OnAcquireCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnAcquireAction takes nothing returns nothing
local integer itemType = GetItemTypeId(GetManipulatedItem())
local Autocannon instance = Autocannon.create(GetManipulatingUnit(), itemType, MissileRange, MissileCooldown)
call Debug("OnAcquireAction " + GetObjectName(itemType))
set instance.sourceCondition = SourceCondition
set instance.onFireAction = FireAction
call TriggerRegisterDeathEvent(instance.destroyed, GetManipulatedItem())
endfunction
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
call RemoveItem(GetManipulatedItem())
endfunction
private function InitGSAutocannonArray takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnAcquire, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddCondition(OnAcquire, Condition(function OnAcquireCondition))
call TriggerAddAction(OnAcquire, function OnAcquireAction)
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
call RegisterMissileSource(ItemType, 0, 0, 0, "war3mapImported\\ShotGunBullet.mdx", 1.25, MissileRange, MissileSpeed, HomingLow, 75, MissileDamage, KineticDamage, 0, 0)
call RegisterMissileSource(ItemType2, 0, 0, 0, "war3mapImported\\ShotGunBullet.mdx", 1.25, MissileRange, MissileSpeed, HomingMedium, 75, MissileDamage, KineticDamage, 0, 1)
endfunction
endlibrary
library ColonialDraftingCenterLib initializer InitColonialDraftingCenter
globals
private constant integer ItemType = 'I009'
private constant integer ItemType2 = 'I00B'
private constant integer FoodBonus = 5
private constant integer FoodBonus2 = 10
private trigger OnAcquire = CreateTrigger()
private trigger OnDrop = CreateTrigger()
endglobals
private function OnAcquireCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnAcquireAction takes nothing returns nothing
local player p = GetOwningPlayer(GetManipulatingUnit())
local integer itemType = GetItemTypeId(GetManipulatedItem())
if(itemType == ItemType)then
call SetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP, GetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP) + FoodBonus)
else
call SetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP, GetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP) + FoodBonus2)
endif
set p = null
endfunction
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
local integer itemType = GetItemTypeId(GetManipulatedItem())
local player p = GetOwningPlayer(GetManipulatingUnit())
if(itemType == ItemType)then
call SetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP, GetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP) - FoodBonus)
else
call SetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP, GetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP) - FoodBonus2)
endif
set p = null
call RemoveItem(GetManipulatedItem())
endfunction
private function InitColonialDraftingCenter takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnAcquire, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddCondition(OnAcquire, Condition(function OnAcquireCondition))
call TriggerAddAction(OnAcquire, function OnAcquireAction)
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
endfunction
endlibrary
library ExportVentureLib initializer InitExportVenture
globals
private constant integer ItemType = 'I008'
private constant integer ItemType2 = 'I00D'
private trigger OnDrop = CreateTrigger()
endglobals
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
call RemoveItem(GetManipulatedItem())
endfunction
private function InitExportVenture takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
endfunction
endlibrary
library FusionCoreLib initializer InitFusionCore
globals
private constant integer ItemType = 'I002'
private constant integer ItemType2 = 'I00E'
private trigger OnDrop = CreateTrigger()
endglobals
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
call RemoveItem(GetManipulatedItem())
endfunction
private function InitFusionCore takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
endfunction
endlibrary
library CovertOpsLib initializer InitCovertOps
globals
private constant integer ItemType = 'I000'
private constant integer ItemType2 = 'I00C'
private trigger OnDrop = CreateTrigger()
endglobals
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
call RemoveItem(GetManipulatedItem())
endfunction
private function InitCovertOps takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
endfunction
endlibrary
library PlanetaryScaleShield
private function PlanetaryScaleShieldCondition takes nothing returns boolean
return UnitHasItemOfTypeBJ(udg_DamageEventTarget, 'I001')
endfunction
private function PlanetaryScaleShieldAction takes nothing returns nothing
local unit target = udg_DamageEventTarget
local real mana = GetUnitState(target, UNIT_STATE_MANA)
local real damageFactor = 1
local real passthroughDamage = RMaxBJ(udg_DamageEventAmount - mana / damageFactor, 0)
local real manaCost = (udg_DamageEventAmount - passthroughDamage) * damageFactor
set udg_DamageEventAmount = passthroughDamage
call SetUnitState(target, UNIT_STATE_MANA, mana - manaCost)
if(udg_DamageEventAmount > 0)then
call RemoveItem(GetItemOfTypeFromUnitBJ(target, 'I001'))
call DisplayTextToPlayer(GetOwningPlayer(target), 0, 0, "A |cffffcc00"+GetObjectName('I001')+"|r was destroyed!")
call PingMinimapForPlayer(GetOwningPlayer(target), GetUnitX(target), GetUnitY(target), 3)
endif
set target = null
endfunction
function ApplyPlanetaryScaleShield takes nothing returns nothing
if(PlanetaryScaleShieldCondition())then
call PlanetaryScaleShieldAction()
endif
endfunction
endlibrary
library PlanetaryFactoryLib initializer InitPlanetaryFactory requires PlanetaryModuleLib
globals
private constant real SpawmManaThreshold = 400
private constant real SpawnManaCost = 200
private constant real SpawnManaCost2 = 150
private constant real SpawnManaCheckInterval = 1
private constant integer SpawnUnitTypeId = 'h005'
private constant integer ItemType = 'I00A'
private constant integer ItemType2 = 'I00G'
private trigger OnAcquire = CreateTrigger()
private trigger OnDrop = CreateTrigger()
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct PlanetaryFactory
private static hashtable ht = InitHashtable()
PlanetaryModuleInstance planetaryModule
trigger spawnTrigger
real manaCost
private static method OnDestroy takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
private static method OnSpawn takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
if(GetUnitAbilityLevel(this.planetaryModule.planetUnit, 'B005') > 0)then
call Debug("sabotaged")
return
endif
if(GetUnitState(this.planetaryModule.planetUnit, UNIT_STATE_MANA) < SpawmManaThreshold)then
call Debug("not enough mana")
return
endif
if(GetPlayerState(GetOwningPlayer(this.planetaryModule.planetUnit), PLAYER_STATE_RESOURCE_FOOD_USED) + GetFoodUsed(SpawnUnitTypeId) > GetPlayerState(GetOwningPlayer(this.planetaryModule.planetUnit), PLAYER_STATE_RESOURCE_FOOD_CAP))then
call Debug("not enough food")
return
endif
call Debug("OnSpawn")
call SetUnitState(this.planetaryModule.planetUnit, UNIT_STATE_MANA, GetUnitState(this.planetaryModule.planetUnit, UNIT_STATE_MANA) - this.manaCost)
call OrderRally(this.planetaryModule.planetUnit, CreateUnit(GetOwningPlayer(this.planetaryModule.planetUnit), SpawnUnitTypeId, GetUnitX(this.planetaryModule.planetUnit), GetUnitY(this.planetaryModule.planetUnit), 0))
endmethod
static method create takes unit planet, item i returns thistype
local thistype this = thistype.allocate()
set this.planetaryModule = PlanetaryModuleInstance.create(planet, i)
if(GetItemTypeId(i) == ItemType)then
set this.manaCost = SpawnManaCost
else
set this.manaCost = SpawnManaCost2
endif
call SaveInteger(thistype.ht, 0, GetHandleId(this.planetaryModule.onRemoveTrigger), this)
call TriggerAddAction(this.planetaryModule.onRemoveTrigger, function thistype.OnDestroy)
set this.spawnTrigger = CreateTrigger()
call SaveInteger(thistype.ht, 1, GetHandleId(this.spawnTrigger), this)
call TriggerRegisterUnitStateEvent(this.spawnTrigger, this.planetaryModule.planetUnit, UNIT_STATE_MANA, GREATER_THAN_OR_EQUAL, SpawmManaThreshold)
call TriggerRegisterTimerEvent(this.spawnTrigger, SpawnManaCheckInterval, true)
call TriggerAddAction(this.spawnTrigger, function thistype.OnSpawn)
call TriggerEvaluate(this.spawnTrigger)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.planetaryModule.onRemoveTrigger))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.spawnTrigger))
call DestroyTrigger(this.spawnTrigger)
set this.spawnTrigger = null
call this.deallocate()
endmethod
endstruct
private function OnAcquireCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnAcquireAction takes nothing returns nothing
call PlanetaryFactory.create(GetManipulatingUnit(), GetManipulatedItem())
endfunction
private function OnDropCondition takes nothing returns boolean
local integer itemType = GetItemTypeId(GetManipulatedItem())
return itemType == ItemType or itemType == ItemType2
endfunction
private function OnDropAction takes nothing returns nothing
call RemoveItem(GetManipulatedItem())
endfunction
private function InitPlanetaryFactory takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(OnAcquire, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddCondition(OnAcquire, Condition(function OnAcquireCondition))
call TriggerAddAction(OnAcquire, function OnAcquireAction)
call TriggerRegisterAnyUnitEventBJ(OnDrop, EVENT_PLAYER_UNIT_DROP_ITEM)
call TriggerAddCondition(OnDrop, Condition(function OnDropCondition))
call TriggerAddAction(OnDrop, function OnDropAction)
endfunction
endlibrary
library ColonizeLib initializer InitColonize
globals
private constant integer SpellId = 'A02Z'
private constant real Duration = 10
private constant string OnCompleteEffect = "Abilities\\Spells\\Other\\Charm\\CharmTarget.mdl"
private trigger OnCast
private constant real ColonizeMinHealthFactor = 0.8
private constant string ColonizeSoundPath = "Advisor\\PlanetColonized1.wav"
private sound ColonizeSound
endglobals
struct Colonize
private static hashtable ht = InitHashtable()
unit caster
unit target
trigger complete
trigger interrupt
private static method OnComplete takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
local effect e = AddSpecialEffect(OnCompleteEffect, GetUnitX(this.target), GetUnitY(this.target))
call BlzSetSpecialEffectScale(e, 1)
call DestroyEffect(e)
set e = null
if(IsUnitSelected(this.caster, GetOwningPlayer(this.caster)))then
call SelectUnitForPlayerSingle(this.target, GetOwningPlayer(this.caster))
endif
if(GetUnitState(this.target, UNIT_STATE_LIFE) < ColonizeMinHealthFactor * GetUnitState(this.target, UNIT_STATE_MAX_LIFE))then
call SetUnitState(this.target, UNIT_STATE_LIFE, ColonizeMinHealthFactor * BlzGetUnitMaxHP(this.target))
endif
call SetUnitOwner(this.target, GetOwningPlayer(this.caster), true)
if(GetLocalPlayer() == GetOwningPlayer(this.caster))then
call StartSound(ColonizeSound)
endif
call RemoveUnit(this.caster)
call this.destroy()
endmethod
private static method OnInterrupt takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call BlzEndUnitAbilityCooldown(this.caster, SpellId)
call this.destroy()
endmethod
static method create takes unit caster, unit target returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.target = target
set this.complete = CreateTrigger()
call TriggerRegisterTimerEvent(this.complete, Duration, false)
call TriggerAddAction(complete, function thistype.OnComplete)
call SaveInteger(thistype.ht, 0, GetHandleId(this.complete), this)
set this.interrupt = CreateTrigger()
call TriggerRegisterUnitEvent(this.interrupt, this.target, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.interrupt, this.caster, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.interrupt, this.caster, EVENT_UNIT_SPELL_ENDCAST)
call TriggerRegisterUnitEvent(this.interrupt, this.caster, EVENT_UNIT_SPELL_FINISH)
call TriggerAddAction(interrupt, function thistype.OnInterrupt)
call SaveInteger(thistype.ht, 1, GetHandleId(this.interrupt), this)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.complete))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.interrupt))
call DestroyTrigger(this.complete)
call DestroyTrigger(this.interrupt)
set this.caster = null
set this.target = null
set this.complete = null
set this.interrupt = null
call this.deallocate()
endmethod
endstruct
private function CastCondition takes nothing returns boolean
return GetSpellAbilityId() == SpellId
endfunction
private function CastAction takes nothing returns nothing
call Colonize.create(GetSpellAbilityUnit(), GetSpellTargetUnit())
endfunction
private function InitColonize takes nothing returns nothing
set ColonizeSound = CreateSound(ColonizeSoundPath, false, false, false, 10, 10, "")
set OnCast = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(OnCast, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(OnCast, Condition(function CastCondition))
call TriggerAddAction(OnCast, function CastAction)
endfunction
endlibrary
function Trig_BonusResourcesOn_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00C'
endfunction
function Trig_BonusResourcesOn_Actions takes nothing returns nothing
call UnitAddAbility(GetSpellAbilityUnit(), 'A010')
endfunction
//===========================================================================
function InitTrig_BonusResourcesOn takes nothing returns nothing
set gg_trg_BonusResourcesOn = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_BonusResourcesOn, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddCondition(gg_trg_BonusResourcesOn, Condition(function Trig_BonusResourcesOn_Conditions))
call TriggerAddAction(gg_trg_BonusResourcesOn, function Trig_BonusResourcesOn_Actions)
endfunction
function Trig_BonusResourcesOff_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00C'
endfunction
function Trig_BonusResourcesOff_Actions takes nothing returns nothing
call UnitRemoveAbility(GetSpellAbilityUnit(), 'A010')
endfunction
//===========================================================================
function InitTrig_BonusResourcesOff takes nothing returns nothing
set gg_trg_BonusResourcesOff = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_BonusResourcesOff, EVENT_PLAYER_UNIT_SPELL_ENDCAST)
call TriggerAddCondition(gg_trg_BonusResourcesOff, Condition(function Trig_BonusResourcesOff_Conditions))
call TriggerAddAction(gg_trg_BonusResourcesOff, function Trig_BonusResourcesOff_Actions)
endfunction
library RefineryLib initializer InitRefinery requires ResourceDeliveryLib, DamageDefinitionLib
globals
private constant real MineralsProduction = 450
private constant real HydrogenProduction = 180
private constant real HarvestInterval = 0.5
private constant real MineralsIntervalProduction = MineralsProduction * (HarvestInterval / 60)
private constant real HydrogenIntervalProduction = HydrogenProduction * (HarvestInterval / 60)
private constant real MineralsDeliveryThreshold = 225
private constant real HydrogenDeliveryThreshold = 90
private constant integer ToggleAutoDeliveryTrigger = 0
private constant integer SendDeliveryTrigger = 1
private constant integer HarvestStartTrigger = 2
private constant integer HarvestTickTimer = 3
private constant integer HarvestEndTrigger = 4
private constant integer DeathTrigger = 5
private constant integer ToggleAutoDeliveryOrderId = 852561
private constant integer ToggleAutoDeliveryOnOrderId = 852562
private constant integer ToggleAutoDeliveryOffOrderId = 852563
private constant integer SendDeliveryAbilityId = 'A02E'
private constant integer HarvestAbilityId = 'A02D'
private trigger OnRefineryCreate
private constant string ResourceDepletedSoundPath = "Advisor\\ResourceDepleted.wav"
private sound ResourceDepletedSound
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct Refinery
private static hashtable ht = InitHashtable()
unit u
unit target
boolean autoDelivery
real minerals
real hydrogen
item mineralsDisplay
item hydrogenDisplay
trigger toggleAutoDeliveryTrigger
trigger sendDeliveryTrigger
trigger harvestStartTrigger
timer harvestTimer
trigger harvestEndTrigger
trigger deathTrigger
private method SendDelivery takes nothing returns nothing
local integer m = R2I(this.minerals)
local integer h = R2I(this.hydrogen)
if(m == 0 and h == 0)then
call Debug("SendDelivery failed")
return // nothing to send
endif
call Debug("SendDelivery")
call SendCargoShipCore(this.u, PlayerHomePlanets[GetPlayerId(GetOwningPlayer(this.u))], m, h)
set this.minerals = this.minerals - m
set this.hydrogen = this.hydrogen - h
call SetItemCharges(this.mineralsDisplay, R2I(this.minerals))
call SetItemCharges(this.hydrogenDisplay, R2I(this.hydrogen))
endmethod
private static method OnToggleAutoDelivery takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, ToggleAutoDeliveryTrigger, GetHandleId(GetTriggeringTrigger()))
call Debug("SendDelivery")
if(GetIssuedOrderId() == ToggleAutoDeliveryOrderId)then
set this.autoDelivery = not this.autoDelivery
if(this.autoDelivery)then
call Debug("OnToggleAutoDelivery toggle true")
call IssueImmediateOrderById(this.u, ToggleAutoDeliveryOnOrderId)
else
call Debug("OnToggleAutoDelivery toggle false")
call IssueImmediateOrderById(this.u, ToggleAutoDeliveryOffOrderId)
endif
elseif(GetIssuedOrderId() == ToggleAutoDeliveryOnOrderId)then
call Debug("OnToggleAutoDelivery true")
set this.autoDelivery = true
elseif(GetIssuedOrderId() == ToggleAutoDeliveryOffOrderId)then
call Debug("OnToggleAutoDelivery false")
set this.autoDelivery = false
endif
endmethod
private static method OnSendDelivery takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, SendDeliveryTrigger, GetHandleId(GetTriggeringTrigger()))
if(GetSpellAbilityId() == SendDeliveryAbilityId)then
call Debug("OnSendDelivery")
call this.SendDelivery()
endif
endmethod
private static method OnHarvestStart takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, HarvestStartTrigger, GetHandleId(GetTriggeringTrigger()))
if(GetSpellAbilityId() == HarvestAbilityId)then
call Debug("OnHarvestStart")
set this.target = GetSpellTargetUnit()
call TimerStart(this.harvestTimer, HarvestInterval, true, function thistype.OnHarvestTick)
endif
endmethod
private static method OnHarvestTick takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, HarvestTickTimer, GetHandleId(GetExpiredTimer()))
if(this.target == null or UnitAlive(this.target) == false)then
call Debug("OnHarvestTick interrupt")
call PauseTimer(this.harvestTimer)
return
endif
call Debug("OnHarvestTick")
if(GetUnitName(this.target) == "Asteroid")then
if(GetPlayerTechCount(GetOwningPlayer(this.u), IndustrialComplexTech, true) > 0)then
set this.minerals = this.minerals + RMinBJ(MineralsIntervalProduction, GetUnitState(this.target, UNIT_STATE_LIFE)) * 1.25
else
set this.minerals = this.minerals + RMinBJ(MineralsIntervalProduction, GetUnitState(this.target, UNIT_STATE_LIFE))
endif
call SetItemCharges(this.mineralsDisplay, R2I(this.minerals))
set udg_NextDamageType = ExtractorDamageType
call UnitDamageTarget(this.u, this.target, MineralsIntervalProduction, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//call TriggerEvaluate(udg_ClearDamageEvent)
//call SetUnitState(this.target, UNIT_STATE_LIFE, GetUnitState(this.target, UNIT_STATE_LIFE) - MineralsIntervalProduction)
//call SetResourceAmount(this.target, R2I(GetUnitState(this.target, UNIT_STATE_LIFE)))
endif
if(GetUnitName(this.target) == "Gas Cloud")then
if(GetPlayerTechCount(GetOwningPlayer(this.u), ScientificConglomerateTech, true) > 0)then
set this.hydrogen = this.hydrogen + RMinBJ(HydrogenIntervalProduction, GetUnitState(this.target, UNIT_STATE_LIFE)) * 1.25
else
set this.hydrogen = this.hydrogen + RMinBJ(HydrogenIntervalProduction, GetUnitState(this.target, UNIT_STATE_LIFE))
endif
call SetItemCharges(this.hydrogenDisplay, R2I(this.hydrogen))
set udg_NextDamageType = ExtractorDamageType
call UnitDamageTarget(this.u, this.target, HydrogenIntervalProduction, false, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
//call TriggerEvaluate(udg_ClearDamageEvent)
//call SetUnitState(this.target, UNIT_STATE_LIFE, GetUnitState(this.target, UNIT_STATE_LIFE) - HydrogenIntervalProduction)
//call SetResourceAmount(this.target, R2I(GetUnitState(this.target, UNIT_STATE_LIFE)))
endif
if(autoDelivery and (this.minerals >= MineralsDeliveryThreshold or this.hydrogen >= HydrogenDeliveryThreshold))then
call this.SendDelivery()
endif
endmethod
private static method OnHarvestEnd takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, HarvestEndTrigger, GetHandleId(GetTriggeringTrigger()))
call Debug("OnHarvestEnd")
if(GetSpellAbilityId() == HarvestAbilityId)then
call Debug("OnHarvestEnd yes")
if(UnitAlive(this.target) == false and GetLocalPlayer() == GetOwningPlayer(this.u))then
call DisplayTextToPlayer(GetOwningPlayer(this.u), 0, 0, "|cffffcc00" + GetUnitName(this.target) + " depleted.|r")
call StartSound(ResourceDepletedSound)
call PingMinimap(GetUnitX(this.target), GetUnitY(this.target), 2)
call SetCameraQuickPosition(GetUnitX(this.target), GetUnitY(this.target))
else
call Debug("OnHarvestEnd target alive")
endif
set this.target = null
call PauseTimer(this.harvestTimer)
endif
endmethod
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, DeathTrigger, GetHandleId(GetTriggeringTrigger()))
call Debug("OnDeath")
call this.destroy()
endmethod
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
call Debug("create")
set this.u = u
call IssueImmediateOrderById(this.u, OrderId("frenzyon"))
set this.target = null
set this.autoDelivery = true
set this.minerals = 0
set this.hydrogen = 0
set this.mineralsDisplay = CreateItem('I005', GetUnitX(this.u), GetUnitY(this.u))
call SetItemCharges(this.mineralsDisplay, 0)
call UnitAddItem(this.u, this.mineralsDisplay)
set this.hydrogenDisplay = CreateItem('I006', GetUnitX(this.u), GetUnitY(this.u))
call SetItemCharges(this.hydrogenDisplay, 0)
call UnitAddItem(this.u, this.hydrogenDisplay)
set this.toggleAutoDeliveryTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.toggleAutoDeliveryTrigger, this.u, EVENT_UNIT_ISSUED_ORDER)
call TriggerAddAction(this.toggleAutoDeliveryTrigger, function thistype.OnToggleAutoDelivery)
call SaveInteger(thistype.ht, ToggleAutoDeliveryTrigger, GetHandleId(this.toggleAutoDeliveryTrigger), this)
set this.sendDeliveryTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.sendDeliveryTrigger, this.u, EVENT_UNIT_SPELL_EFFECT)
call TriggerAddAction(this.sendDeliveryTrigger, function thistype.OnSendDelivery)
call SaveInteger(thistype.ht, SendDeliveryTrigger, GetHandleId(this.sendDeliveryTrigger), this)
set this.harvestStartTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.harvestStartTrigger, this.u, EVENT_UNIT_SPELL_EFFECT)
call TriggerAddAction(this.harvestStartTrigger, function thistype.OnHarvestStart)
call SaveInteger(thistype.ht, HarvestStartTrigger, GetHandleId(this.harvestStartTrigger), this)
set this.harvestTimer = CreateTimer()
// nothing to do here, timer starts/end in other triggers
call SaveInteger(thistype.ht, HarvestTickTimer, GetHandleId(this.harvestTimer), this)
set this.harvestEndTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.harvestEndTrigger, this.u, EVENT_UNIT_SPELL_ENDCAST)
call TriggerAddAction(this.harvestEndTrigger, function thistype.OnHarvestEnd)
call SaveInteger(thistype.ht, HarvestEndTrigger, GetHandleId(this.harvestEndTrigger), this)
set this.deathTrigger = CreateTrigger()
call TriggerRegisterUnitEvent(this.deathTrigger, this.u, EVENT_UNIT_DEATH)
call TriggerAddAction(this.deathTrigger, function thistype.OnDeath)
call SaveInteger(thistype.ht, DeathTrigger, GetHandleId(this.deathTrigger), this)
return this
endmethod
method destroy takes nothing returns nothing
call Debug("destroy")
call RemoveItem(this.mineralsDisplay)
call RemoveItem(this.hydrogenDisplay)
call RemoveSavedInteger(thistype.ht, ToggleAutoDeliveryTrigger, GetHandleId(this.toggleAutoDeliveryTrigger))
call RemoveSavedInteger(thistype.ht, SendDeliveryTrigger, GetHandleId(this.sendDeliveryTrigger))
call RemoveSavedInteger(thistype.ht, HarvestStartTrigger, GetHandleId(this.harvestStartTrigger))
call RemoveSavedInteger(thistype.ht, HarvestTickTimer, GetHandleId(this.harvestTimer))
call RemoveSavedInteger(thistype.ht, HarvestEndTrigger, GetHandleId(this.harvestEndTrigger))
call RemoveSavedInteger(thistype.ht, DeathTrigger, GetHandleId(this.deathTrigger))
call DestroyTrigger(this.toggleAutoDeliveryTrigger)
call DestroyTrigger(this.sendDeliveryTrigger)
call DestroyTrigger(this.harvestStartTrigger)
call DestroyTimer(this.harvestTimer)
call DestroyTrigger(this.harvestEndTrigger)
call DestroyTrigger(this.deathTrigger)
set this.u = null
set this.target = null
set this.mineralsDisplay = null
set this.hydrogenDisplay = null
set this.toggleAutoDeliveryTrigger = null
set this.sendDeliveryTrigger = null
set this.harvestStartTrigger = null
set this.harvestTimer = null
set this.harvestEndTrigger = null
set this.deathTrigger = null
endmethod
endstruct
function OnRefineryCreateCondition takes nothing returns boolean
return GetUnitTypeId(GetEnteringUnit()) == 'h00L'
endfunction
function OnRefineryCreateAction takes nothing returns nothing
call Refinery.create(GetEnteringUnit())
endfunction
function InitRefinery takes nothing returns nothing
local region r = CreateRegion()
call RegionAddRect(r, bj_mapInitialPlayableArea)
set OnRefineryCreate = CreateTrigger()
call TriggerRegisterEnterRegion(OnRefineryCreate, r, null)
call TriggerAddCondition(OnRefineryCreate, Condition(function OnRefineryCreateCondition))
call TriggerAddAction(OnRefineryCreate, function OnRefineryCreateAction)
set r = null
set ResourceDepletedSound = CreateSound(ResourceDepletedSoundPath, false, false, false, 10, 10, "")
endfunction
endlibrary
library MaintenanceBeamLib initializer InitMaintenanceBeam requires LinkedLightningEffectLib
globals
integer MaintenanceBeamAbility = 'A00S'
real MaintenanceBeamDuration = 0.4
real MaintenanceBeamFadeOutPoint = 0.3
string MaintenanceBeamCode = "GRSB"
trigger MaintenanceBeamStartTrigger
endglobals
private function MaintenanceBeamStartCondition takes nothing returns boolean
return GetSpellAbilityId() == MaintenanceBeamAbility
endfunction
private function MaintenanceBeamStartAction takes nothing returns nothing
call LinkedLightningEffect.create(GetSpellAbilityUnit(), GetSpellTargetUnit(), MaintenanceBeamCode, MaintenanceBeamDuration, MaintenanceBeamFadeOutPoint)
endfunction
private function InitMaintenanceBeam takes nothing returns nothing
set MaintenanceBeamStartTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(MaintenanceBeamStartTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(MaintenanceBeamStartTrigger, Condition(function MaintenanceBeamStartCondition))
call TriggerAddAction(MaintenanceBeamStartTrigger, function MaintenanceBeamStartAction)
endfunction
endlibrary
library SearingChargeLib
globals
private constant real DamageFactor = 1.35
endglobals
function SearingChargeCondition takes nothing returns boolean
if(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_ANCIENT))then
return false // doesn't affect planets
endif
if(GetUnitAbilityLevel(udg_DamageEventSource, 'A01Q') == 0)then
return false // deosn't have ability
endif
if(GetPlayerTechCount(GetOwningPlayer(udg_DamageEventSource), 'R00O', true) < 1)then
return false // tech not researched
endif
return IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE)
endfunction
function SearingChargeAction takes nothing returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, "SearingChargeAction")
set udg_DamageEventAmount = udg_DamageEventAmount * DamageFactor
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Items\\AIfb\\AIfbSpecialArt.mdl", udg_DamageEventTarget, "origin"))
endfunction
function ApplySearingCharge takes nothing returns nothing
if(SearingChargeCondition())then
call SearingChargeAction()
endif
endfunction
endlibrary
library ShredderVolleyLib requires MissileSystem
globals
private constant real MaxHealthDamageRatio = 0.01
endglobals
function ShredderVolleyCondition takes nothing returns boolean
if(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_ANCIENT))then
return false // doesn't affect planets
endif
if(IsUnitType(udg_DamageEventTarget, UNIT_TYPE_STRUCTURE))then
return false // doesn't affect structures
endif
if(GetUnitAbilityLevel(udg_DamageEventSource, 'A031') == 0)then
return false // deosn't have ability
endif
if(GetPlayerTechCount(GetOwningPlayer(udg_DamageEventSource), 'R00M', true) < 1)then
return false // tech not researched
endif
return true
endfunction
function ShredderVolleyAction takes nothing returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, "ShredderVolleyAction")
call DamageM(udg_DamageEventSource, udg_DamageEventTarget, GetUnitState(udg_DamageEventTarget, UNIT_STATE_MAX_LIFE) * MaxHealthDamageRatio, AttackTypes[PlanetKillerDamage])
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Undead\\FrostArmor\\FrostArmorDamage.mdl", udg_DamageEventTarget, "origin"))
endfunction
function ApplyShredderVolley takes nothing returns nothing
if(ShredderVolleyCondition())then
call ShredderVolleyAction()
endif
endfunction
endlibrary
library HyperdenseAlloyLib
function HyperdenseAlloyCondition takes nothing returns boolean
return GetUnitAbilityLevel(udg_DamageEventTarget, 'A028') > 0
endfunction
function HyperdenseAlloyAction takes nothing returns nothing
set udg_DamageEventAmount = udg_DamageEventAmount * 0.85
endfunction
function ApplyHyperdenseAlloy takes nothing returns nothing
if(HyperdenseAlloyCondition())then
call HyperdenseAlloyAction()
endif
endfunction
endlibrary
library RepulsiveCoatingLib
globals
private constant real DamageFactor = 0.80
endglobals
function RepulsiveCoatingCondition takes nothing returns boolean
if(udg_DamageEventAttackT != udg_ATTACK_TYPE_MAGIC and udg_DamageEventAttackT != udg_ATTACK_TYPE_SPELLS)then
//call DisplayTextToPlayer(Player(0), 0, 0, "not kinetic")
return false
endif
if(GetUnitAbilityLevel(udg_DamageEventTarget, 'A007') == 0)then
//call DisplayTextToPlayer(Player(0), 0, 0, "not ability")
return false
endif
return true // and GetPlayerTechCount(GetOwningPlayer(udg_DamageEventSource), 'R00M', true) > 0
endfunction
function RepulsiveCoatingAction takes nothing returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, "RepulsiveCoatingAction")
set udg_DamageEventAmount = udg_DamageEventAmount * DamageFactor
endfunction
function ApplyRepulsiveCoating takes nothing returns nothing
if(RepulsiveCoatingCondition())then
call RepulsiveCoatingAction()
endif
endfunction
endlibrary
function ATRRocketCondition takes nothing returns boolean
return GetSpellAbilityId() == 'A00M'
endfunction
function ATRRocketAction takes nothing returns nothing
call SpellSpawnMissile()
endfunction
//===========================================================================
function InitTrig_ATRRocket takes nothing returns nothing
set gg_trg_ATRRocket = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_ATRRocket, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_ATRRocket, Condition(function ATRRocketCondition))
call TriggerAddAction(gg_trg_ATRRocket, function ATRRocketAction)
call RegisterMissileSource('A00M', 0, 0, 0, "Abilities\\Weapons\\RocketMissile\\RocketMissile.mdl", 1, 800, 1200, HomingHigh, 30, 15, ExplosiveDamage, 50, 0)
endfunction
function Trig_AerialShacklesOn_Conditions takes nothing returns boolean
if ( not ( GetSpellAbilityId() == 'Amls' ) ) then
return false
endif
return true
endfunction
function Trig_AerialShacklesOn_Actions takes nothing returns nothing
call UnitRemoveBuffBJ('Bmlt', GetSpellAbilityUnit())
call PauseUnit(GetSpellAbilityUnit(), false)
endfunction
//===========================================================================
function InitTrig_AerialShacklesOn takes nothing returns nothing
set gg_trg_AerialShacklesOn = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( gg_trg_AerialShacklesOn, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_AerialShacklesOn, Condition( function Trig_AerialShacklesOn_Conditions ) )
call TriggerAddAction( gg_trg_AerialShacklesOn, function Trig_AerialShacklesOn_Actions )
endfunction
library ObservatoryPingsLib initializer InitObservatoryPings requires MathLib
globals
private constant integer ElectronicMonitoringIndicatorTypeId = 'h015'
private constant real ElectronicMonitoringIndicatorUpdatePeriod = 0.06
private constant real Scale = 0.15
private constant string EnemyMinimapIconPath = "UI\\MiniMap\\MiniMapIcon\\TeamColor00.blp"//"UI\\MiniMap\\ping6.blp"
private constant string NeutralMinimapIconPath = "UI\\MiniMap\\ping4.blp"
private constant integer ObservatoryUnitType = 'h00N'
private constant real ObservatoryPingRange = 2400
private constant real ObservatoryPingPeriod = 5
private unit g_ObservatoryEnum_Observatory = null
private player g_ObservatoryEnum_Player = null
private group g_ObservatoryEnum_Group = CreateGroup()
private trigger ObservatoryCompleteTrigger
private sound EnemyPingSound
private sound NeutralPingSound
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct ElectronicMonitoringIndicator
private static hashtable ht = InitHashtable()
private static group recycled = CreateGroup()
unit source
unit target
unit indicator
boolean enemy
boolean showIndicator
minimapicon icon
trigger update
trigger visibilityChange
trigger death
private method PingTarget takes nothing returns nothing
local player p = GetOwningPlayer(this.source)
local boolean shouldPing = GetLocalPlayer() == p or IsPlayerAlly(p, GetLocalPlayer()) or GetPlayerAlliance(p, GetLocalPlayer(), ALLIANCE_SHARED_VISION) or GetPlayerAlliance(p, GetLocalPlayer(), ALLIANCE_SHARED_VISION_FORCED)
if(shouldPing == false)then
set p = null
return
endif
if(this.enemy)then
call PingMinimapEx(GetUnitX(this.target), GetUnitY(this.target), 0.66, 200, 50, 50, true)
call StartSound(EnemyPingSound)
else
call PingMinimapEx(GetUnitX(this.target), GetUnitY(this.target), 0.66, 200, 200, 50, false)
call StartSound(NeutralPingSound)
endif
set p = null
endmethod
private method AdjustPosition takes nothing returns nothing
call SetUnitPosition(this.indicator, GetUnitX(this.target), GetUnitY(this.target))
endmethod
private method AdjustVisibility takes nothing returns nothing
local player p = GetOwningPlayer(this.source)
local boolean isEnemy = IsUnitEnemy(this.target, p)
local boolean recreateMinimap = this.enemy != isEnemy
set this.enemy = isEnemy
if(recreateMinimap or this.icon == null)then
call DestroyMinimapIcon(this.icon)
if(this.enemy)then
set this.icon = CreateMinimapIconOnUnit(this.indicator, 200, 50, 50, EnemyMinimapIconPath, FOG_OF_WAR_MASKED)
else
set this.icon = CreateMinimapIconOnUnit(this.indicator, 200, 200, 50, NeutralMinimapIconPath, FOG_OF_WAR_MASKED)
endif
endif
if(GetPlayerAlliance(p, GetOwningPlayer(this.target), ALLIANCE_PASSIVE))then
set this.showIndicator = false // don't show allied/neutral player
elseif(IsUnitVisible(this.target, p) or IsUnitInvisible(this.target, p) == false)then
set this.showIndicator = false // don't show if the unit is in vision
elseif(GetLocalPlayer() == p or IsPlayerAlly(p, GetLocalPlayer()) or GetPlayerAlliance(p, GetLocalPlayer(), ALLIANCE_SHARED_VISION) or GetPlayerAlliance(p, GetLocalPlayer(), ALLIANCE_SHARED_VISION_FORCED))then
set this.showIndicator = true
else
set this.showIndicator = false
endif
if(this.showIndicator)then
// show indicator and icon
call SetUnitScale(this.indicator, Scale, Scale, Scale)
call SetMinimapIconVisible(this.icon, true)
else
// hide indicator and icon
call SetUnitScale(this.indicator, 0, 0, 0)
call SetMinimapIconVisible(this.icon, false)
endif
set p = null
endmethod
private static method OnUpdate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
if(UnitAlive(this.target) == false or this.target == null)then
call this.destroy()
return
endif
if(IsWithinDistance(GetUnitX(this.source), GetUnitY(this.source), GetUnitX(this.target), GetUnitY(this.target), ObservatoryPingRange) == false)then
call this.destroy()
return
endif
call this.AdjustVisibility()
call this.AdjustPosition()
endmethod
private static method OnVisibilityChange takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call this.AdjustVisibility()
endmethod
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 2, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
static method create takes unit source, unit target returns thistype
local thistype this = thistype.allocate()
local player p
set this.source = source
set this.target = target
set this.icon = null
set p = GetOwningPlayer(this.source)
// recycle or create indicator unit
set this.indicator = FirstOfGroup(thistype.recycled)
if(this.indicator == null)then
set this.indicator = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), ElectronicMonitoringIndicatorTypeId, GetUnitX(this.target), GetUnitY(this.target), 270)
call SetUnitColor(this.indicator, PLAYER_COLOR_RED)
else
call GroupRemoveUnit(thistype.recycled, this.indicator)
call UnitRemoveAbility(this.indicator, 'Aloc')
call ShowUnit(this.indicator, true)
call UnitAddAbility(this.indicator, 'Aloc')
endif
// update indicator
call this.AdjustVisibility()
call this.AdjustPosition()
// setup triggers
set this.update = CreateTrigger()
call TriggerRegisterTimerEvent(this.update, ElectronicMonitoringIndicatorUpdatePeriod, true)
call TriggerAddAction(this.update, function thistype.OnUpdate)
call SaveInteger(thistype.ht, 0, GetHandleId(this.update), this)
set this.visibilityChange = CreateTrigger()
call TriggerRegisterPlayerAllianceChange(this.visibilityChange, p, ALLIANCE_PASSIVE)
call TriggerRegisterPlayerAllianceChange(this.visibilityChange, p, ALLIANCE_SHARED_VISION)
call TriggerRegisterPlayerAllianceChange(this.visibilityChange, p, ALLIANCE_SHARED_VISION_FORCED)
call TriggerRegisterUnitEvent(this.visibilityChange, this.target, EVENT_UNIT_HIDDEN)
call TriggerRegisterUnitEvent(this.visibilityChange, this.target, EVENT_UNIT_DETECTED)
call TriggerRegisterUnitEvent(this.visibilityChange, this.target, EVENT_UNIT_LOADED)
call TriggerRegisterUnitEvent(this.visibilityChange, this.target, EVENT_UNIT_CHANGE_OWNER)
call TriggerAddAction(this.visibilityChange, function thistype.OnVisibilityChange)
call SaveInteger(thistype.ht, 1, GetHandleId(this.visibilityChange), this)
set this.death = CreateTrigger()
call TriggerRegisterUnitEvent(this.death, this.source, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.death, this.target, EVENT_UNIT_DEATH)
call TriggerAddAction(this.death, function thistype.OnDeath)
call SaveInteger(thistype.ht, 2, GetHandleId(this.death), this)
call Debug("ElectronicMonitoringIndicator create")
call this.PingTarget()
set p = null
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.update))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.visibilityChange))
call RemoveSavedInteger(thistype.ht, 2, GetHandleId(this.death))
call DestroyTrigger(this.update)
call DestroyTrigger(this.visibilityChange)
call DestroyTrigger(this.death)
call DestroyMinimapIcon(this.icon)
call GroupAddUnit(thistype.recycled, this.indicator)
call ShowUnit(this.indicator, false)
set this.source = null
set this.target = null
set this.indicator = null
set this.update = null
set this.visibilityChange = null
set this.death = null
set this.icon = null
call Debug("ElectronicMonitoringIndicator destroy")
call this.deallocate()
endmethod
endstruct
struct ElectricMonitoringSource
private static hashtable ht = InitHashtable()
private static unit f_source
unit source
trigger enter
trigger death
private static method OnEnter takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
if(GetOwningPlayer(this.source) == GetOwningPlayer(GetTriggerUnit()))then
return // don't track own units
endif
if(GetUnitAbilityLevel(GetTriggerUnit(), 'Aloc') > 0)then
return // don't track Locust units
endif
if(IsUnitType(GetTriggerUnit(), UNIT_TYPE_ANCIENT))then
return // don't tracked planets
endif
if(IsUnitType(GetTriggerUnit(), UNIT_TYPE_SUMMONED) or IsUnitType(GetTriggerUnit(), UNIT_TYPE_SAPPER))then
return // don't tracked summoned/suicidable
endif
call ElectronicMonitoringIndicator.create(this.source, GetTriggerUnit())
endmethod
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
static method create takes unit source returns thistype
local thistype this = thistype.allocate()
set this.source = source
set this.enter = CreateTrigger()
call TriggerRegisterUnitInRange(this.enter, this.source, ObservatoryPingRange, null)
call TriggerAddAction(this.enter, function thistype.OnEnter)
call SaveInteger(thistype.ht, 0, GetHandleId(this.enter), this)
set this.death = CreateTrigger()
call TriggerRegisterUnitEvent(this.death, this.source, EVENT_UNIT_DEATH)
call TriggerAddAction(this.death, function thistype.OnDeath)
call SaveInteger(thistype.ht, 1, GetHandleId(this.death), this)
call Debug("ElectricMonitoringSource create")
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.enter))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.death))
call DestroyTrigger(this.enter)
call DestroyTrigger(this.death)
set this.source = null
set this.enter = null
set this.death = null
call Debug("ElectricMonitoringSource destroy")
call this.deallocate()
endmethod
endstruct
function ObservatoryCompleteCondition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == ObservatoryUnitType
endfunction
function ObservatoryCompleteAction takes nothing returns nothing
call ElectricMonitoringSource.create(GetConstructedStructure())
endfunction
function InitObservatoryPings takes nothing returns nothing
// track new Observatories
set ObservatoryCompleteTrigger = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(ObservatoryCompleteTrigger, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(ObservatoryCompleteTrigger, Condition(function ObservatoryCompleteCondition))
call TriggerAddAction(ObservatoryCompleteTrigger, function ObservatoryCompleteAction)
endfunction
endlibrary
library TeamManagerLib initializer InitTeamManager
globals
integer PlayerCount
private force array PlayerTeams
private integer array PlayerTeamSizes
integer TeamCount = 0
private force array PlayerAllies
private force array PlayerFriending
private force array PlayerEnemies
private constant string WarSoundPath = "Sound\\Interface\\CreepAggroWhat1.flac"
private constant string RequestSoundPath = "Sound\\Interface\\QuestLog.flac"
private constant string AllianceSoundPath = "Sound\\Interface\\GoodJob.flac"
private sound WarSound
private sound RequestSound
private sound AllianceSound
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
function GetPlayerAllies takes player p returns force
local integer id = GetPlayerId(p)
return PlayerAllies[id]
endfunction
function GetPlayerEnemies takes player p returns force
local integer id = GetPlayerId(p)
return PlayerEnemies[id]
endfunction
function GetAlliesCount takes player p returns integer
local integer id = GetPlayerId(p)
return CountPlayersInForceBJ(PlayerAllies[id])
endfunction
function GetFriendingCount takes player p returns integer
local integer id = GetPlayerId(p)
return CountPlayersInForceBJ(PlayerFriending[id])
endfunction
function GetEnemiesCount takes player p returns integer
local integer id = GetPlayerId(p)
return CountPlayersInForceBJ(PlayerEnemies[id])
endfunction
function ArePlayerAllies takes player a, player b returns boolean
local integer aId = GetPlayerId(a)
local integer bId = GetPlayerId(b)
return IsPlayerInForce(b, PlayerAllies[aId]) and IsPlayerInForce(a, PlayerAllies[bId])
endfunction
function ArePlayerEnemies takes player a, player b returns boolean
local integer aId = GetPlayerId(a)
local integer bId = GetPlayerId(b)
return IsPlayerInForce(b, PlayerEnemies[aId]) or IsPlayerInForce(a, PlayerEnemies[bId])
endfunction
function IsPlayerFriending takes player a, player b returns boolean
local integer aId = GetPlayerId(a)
return IsPlayerInForce(b, PlayerFriending[aId])
endfunction
private function SetAlliance takes player a, player b, boolean allied returns nothing
call SetPlayerAlliance(a, b, ALLIANCE_HELP_REQUEST, allied)
call SetPlayerAlliance(a, b, ALLIANCE_HELP_RESPONSE, allied)
call SetPlayerAlliance(a, b, ALLIANCE_PASSIVE, allied)
call SetPlayerAlliance(a, b, ALLIANCE_SHARED_VISION, allied)
call SetPlayerAlliance(a, b, ALLIANCE_SHARED_XP, allied)
call SetPlayerAlliance(a, b, ALLIANCE_SHARED_SPELLS, allied)
endfunction
function MakePlayerAllies takes player a, player b returns nothing
local integer aId = GetPlayerId(a)
local integer bId = GetPlayerId(b)
call ForceAddPlayer(PlayerAllies[aId], b)
call ForceAddPlayer(PlayerAllies[bId], a)
call ForceRemovePlayer(PlayerFriending[aId], b)
call ForceRemovePlayer(PlayerFriending[bId], a)
call ForceRemovePlayer(PlayerEnemies[aId], b)
call ForceRemovePlayer(PlayerEnemies[bId], a)
call SetAlliance(a, b, true)
call SetAlliance(b, a, true)
endfunction
function MakePlayerEnemies takes player a, player b returns nothing
local integer aId = GetPlayerId(a)
local integer bId = GetPlayerId(b)
call ForceAddPlayer(PlayerEnemies[aId], b)
call ForceAddPlayer(PlayerEnemies[bId], a)
call ForceRemovePlayer(PlayerFriending[aId], b)
call ForceRemovePlayer(PlayerFriending[bId], a)
call ForceRemovePlayer(PlayerAllies[aId], b)
call ForceRemovePlayer(PlayerAllies[bId], a)
call SetAlliance(a, b, false)
call SetAlliance(b, a, false)
endfunction
private function AiFriending takes player ai, player other returns nothing
local integer aiId = GetPlayerId(ai)
call Debug("AiFriending")
if(GetAlliesCount(ai) > 0 or GetAlliesCount(other) > 0)then
call Debug("already has an ally")
return // already has an ally
endif
call MakePlayerAllies(ai, other)
endfunction
function MakePlayerFriending takes player a, player b returns nothing
local integer bId = GetPlayerId(b)
call ForceAddPlayer(PlayerFriending[bId], a)
if(GetPlayerController(b) == MAP_CONTROL_COMPUTER)then
call AiFriending(b, a)
endif
endfunction
function TryFriending takes player a, player b returns boolean
if(ArePlayerAllies(a, b))then
return false
endif
if(IsPlayerFriending(a, b))then
call MakePlayerAllies(a, b)
return true
endif
call MakePlayerFriending(a, b)
return true
endfunction
function SendAllyRequest takes player source, player target returns nothing
if(TryFriending(source, target) == false)then
call Debug("request already sent")
return // request already sent
endif
if(ArePlayerAllies(source, target))then
call DisplayTextToPlayer(source, 0, 0, "You and " + GetPlayerName(target) + " are now allies.")
call DisplayTextToPlayer(target, 0, 0, "You and " + GetPlayerName(source) + " are now allies.")
call StartSoundForPlayerBJ(source, AllianceSound)
call StartSoundForPlayerBJ(target, AllianceSound)
return
endif
call DisplayTextToPlayer(source, 0, 0, "You sent " + GetPlayerName(target) + " an alliance request.")
call DisplayTextToPlayer(target, 0, 0, GetPlayerName(source) + " sent you an alliance request.")
call StartSoundForPlayerBJ(source, RequestSound)
call StartSoundForPlayerBJ(target, RequestSound)
endfunction
function StartWar takes player source, player target returns nothing
if(ArePlayerEnemies(source, target))then
call DisplayTextToPlayer(source, 0, 0, "You are already with " + GetPlayerName(target) + ".")
return
endif
call MakePlayerEnemies(source, target)
call DisplayTextToPlayer(source, 0, 0, "You are now at war with " + GetPlayerName(target) + ".")
call DisplayTextToPlayer(target, 0, 0, "You are now at war with " + GetPlayerName(source) + ".")
call StartSoundForPlayerBJ(source, WarSound)
call StartSoundForPlayerBJ(target, WarSound)
endfunction
function SetFfaAlliances takes nothing returns nothing
local integer n = 0
local integer n2 = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING)then
set n2 = n + 1
loop
exitwhen n2 == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n2)) == PLAYER_SLOT_STATE_PLAYING)then
call MakePlayerEnemies(Player(n), Player(n2))
endif
set n2 = n2 + 1
endloop
endif
set n = n + 1
endloop
endfunction
private function InitTeamManager takes nothing returns nothing
local integer n = 0
set WarSound = CreateSound(WarSoundPath, false, false, false, 10, 10, "")
set RequestSound = CreateSound(RequestSoundPath, false, false, false, 10, 10, "")
set AllianceSound = CreateSound(AllianceSoundPath, false, false, false, 10, 10, "")
set PlayerCount = CountPlayersInForceBJ(bj_FORCE_ALL_PLAYERS)
loop
exitwhen n == bj_MAX_PLAYERS
set PlayerTeams[n] = CreateForce()
set PlayerTeamSizes[n] = 0
set PlayerAllies[n] = CreateForce()
set PlayerFriending[n] = CreateForce()
set PlayerEnemies[n] = CreateForce()
set n = n + 1
endloop
set n = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING)then
call ForceAddPlayer(PlayerTeams[GetPlayerTeam(Player(n))], Player(n))
set PlayerTeamSizes[GetPlayerTeam(Player(n))] = PlayerTeamSizes[GetPlayerTeam(Player(n))] + 1
set TeamCount = IMaxBJ(TeamCount, 1 + GetPlayerTeam(Player(n)))
endif
set n = n + 1
endloop
call Debug("Number of teams:" + I2S(TeamCount))
set n = 0
loop
exitwhen n == TeamCount
call Debug("Players in team " + I2S(n + 1) + ": " + I2S(PlayerTeamSizes[n]))
set n = n + 1
endloop
set n = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING)then
call ForceEnumAllies(PlayerAllies[n], Player(n), null)
call ForceRemovePlayer(PlayerAllies[n], Player(n))
call ForceEnumEnemies(PlayerEnemies[n], Player(n), null)
endif
set n = n + 1
endloop
endfunction
endlibrary
library PlayerDiplomacyMenuLib requires TeamManagerLib, Core
globals
private constant integer DiplomacyAlly = 0
private constant integer DiplomacyEnemy = 1
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct PlayerDiplomacyMenu
private static hashtable ht = InitHashtable()
private static thistype CreatePlayerButtons_Instance
player p
dialog diplomacyMenu
button allyButton
button enemyButton
integer diplomacy
dialog playerMenu
trigger showDiplomacyMenu
trigger diplomacyMenuClick
trigger playerButtonClick
private static method OnPlayerButtonClick takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 2, GetHandleId(GetTriggeringTrigger()))
local player target = LoadPlayerHandle(thistype.ht, -this, GetHandleId(GetClickedButton()))
call Debug("OnPlayerButtonClick")
call Debug("trigger id: " + I2S(GetHandleId(GetTriggeringTrigger())))
call Debug("this: " + I2S(this))
call Debug("button id: " + I2S(GetHandleId(GetClickedButton())))
if(this == 0 or this.p == null)then
call Debug("ERROR")
return // something went wrong
endif
call FlushChildHashtable(thistype.ht, this) // clear player mapping
call DialogDestroy(this.playerMenu) // destroy menu
set this.playerMenu = null // avoid leaks
call RemoveSavedInteger(thistype.ht, 2, GetHandleId(this.playerButtonClick)) // remove trigger mapping
call DestroyTrigger(this.playerButtonClick) // destroy trigger
set this.playerButtonClick = null // avoid leaks
if(target == null)then
call Debug("cancelled")
return // was cancelled
endif
if(this.diplomacy == DiplomacyAlly)then
call SendAllyRequest(this.p, target)
return
endif
if(this.diplomacy == DiplomacyEnemy)then
call StartWar(this.p, target)
endif
endmethod
private static method CreatePlayerButtonsEnum takes nothing returns nothing
local button b
if(IsPlayerFriending(thistype.CreatePlayerButtons_Instance.p, GetEnumPlayer()))then
set b = DialogAddButton(thistype.CreatePlayerButtons_Instance.playerMenu, "(*)" + GetPlayerName(GetEnumPlayer()), 0)
else
set b = DialogAddButton(thistype.CreatePlayerButtons_Instance.playerMenu, GetPlayerName(GetEnumPlayer()), 0)
endif
call SavePlayerHandle(thistype.ht, -thistype.CreatePlayerButtons_Instance, GetHandleId(b), GetEnumPlayer())
set b = null
endmethod
private method CreatePlayerButtons takes force players returns nothing
set thistype.CreatePlayerButtons_Instance = this
// create buttons
call ForForce(players, function thistype.CreatePlayerButtonsEnum)
call SavePlayerHandle(thistype.ht, -this, GetHandleId(DialogAddButton(this.playerMenu, "Cancel", 0)), null)
// setup trigger
set this.playerButtonClick = CreateTrigger()
call TriggerRegisterDialogEvent(this.playerButtonClick, this.playerMenu)
call TriggerAddAction(this.playerButtonClick, function thistype.OnPlayerButtonClick)
call SaveInteger(thistype.ht, 2, GetHandleId(this.playerButtonClick), this)
endmethod
private static method OnDiplomacyMenuClick takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call Debug("OnDiplomacyMenuClick")
// create and show player list dialog
if(GetClickedButton() == this.allyButton)then
call Debug("allyButton")
set this.diplomacy = DiplomacyAlly
set this.playerMenu = DialogCreate()
if(GetFriendingCount(this.p) > 0)then
call DialogSetMessage(this.playerMenu, "|cff55ff55ALLIANCE MENU|r\nSelect a player you want to ally with.\n(*) indicates alliance requests.")
else
call DialogSetMessage(this.playerMenu, "|cff55ff55ALLIANCE MENU|r\nSelect a player you want to ally with.")
endif
call CreatePlayerButtons(GetPlayerEnemies(this.p))
call DialogDisplay(this.p, this.playerMenu, true)
elseif(GetClickedButton() == this.enemyButton)then
call Debug("enemyButton")
set this.diplomacy = DiplomacyEnemy
set this.playerMenu = DialogCreate()
call DialogSetMessage(this.playerMenu, "|cffff5555WAR MENU|r\nSelect a player you want to fight with.")
call CreatePlayerButtons(GetPlayerAllies(this.p))
call DialogDisplay(this.p, this.playerMenu, true)
else
call Debug("canceled")
endif
// cleanup menu dialog and trigger
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.diplomacyMenuClick))
call DestroyTrigger(this.diplomacyMenuClick)
set this.diplomacyMenuClick = null
call DialogDestroy(this.diplomacyMenu)
set this.diplomacyMenu = null
set this.allyButton = null
set this.enemyButton = null
endmethod
private static method OnShowDiplomacyMenuFilter takes nothing returns boolean
return GetUnitTypeId(GetFilterUnit()) == 'H013'
endmethod
private static method OnShowDiplomacyMenuCondition takes nothing returns boolean
return GetSpellAbilityId() == 'A017'
endmethod
private static method OnShowDiplomacyMenu takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
local string allyString = "You have " + I2S(GetAlliesCount(this.p)) + " allied Empires."
local string enemyString = "You have " + I2S(GetEnemiesCount(this.p)) + " enemy Empires."
local integer friendingCount = GetFriendingCount(this.p)
if(friendingCount > 1)then
set allyString = allyString + "\n" + I2S(friendingCount) + " Empires want an alliance."
elseif(friendingCount == 1)then
set allyString = allyString + "\n1 Empire wants an alliance."
endif
// create dialog
set this.diplomacyMenu = DialogCreate()
set this.allyButton = DialogAddButton(this.diplomacyMenu, "|cff55ff55ALLIANCE MENU|r", 0)
set this.enemyButton = DialogAddButton(this.diplomacyMenu, "|cffff5555WAR MENU|r", 0)
call DialogAddButton(this.diplomacyMenu, "Cancel", 0)
call DialogSetMessage(this.diplomacyMenu, "|cffffcc00DIPLOMACY MENU|r\n|cffffffff" + allyString + "\n" + enemyString + "|r")
// setup trigger
set this.diplomacyMenuClick = CreateTrigger()
call TriggerRegisterDialogEvent(this.diplomacyMenuClick, this.diplomacyMenu)
call TriggerAddAction(this.diplomacyMenuClick, function thistype.OnDiplomacyMenuClick)
call SaveInteger(thistype.ht, 1, GetHandleId(this.diplomacyMenuClick), this)
// show to player
call DialogDisplay(this.p, this.diplomacyMenu, true)
endmethod
static method create takes player p returns thistype
local thistype this = thistype.allocate()
set this.p = p
set this.showDiplomacyMenu = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(this.showDiplomacyMenu, this.p, EVENT_PLAYER_UNIT_SPELL_EFFECT, Condition(function thistype.OnShowDiplomacyMenuFilter))
call TriggerAddCondition(this.showDiplomacyMenu, Condition(function thistype.OnShowDiplomacyMenuCondition))
call TriggerAddAction(this.showDiplomacyMenu, function thistype.OnShowDiplomacyMenu)
call SaveInteger(thistype.ht, 0, GetHandleId(this.showDiplomacyMenu), this)
return this
endmethod
endstruct
function InitPlayerDiplomacyMenu takes nothing returns nothing
local integer n = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(n)) == MAP_CONTROL_USER)then
call PlayerDiplomacyMenu.create(Player(n))
endif
set n = n + 1
endloop
endfunction
endlibrary
library AiDiplomacyLib requires TeamManagerLib, Core
globals
private constant integer DiplomacyAlly = 0
private constant integer DiplomacyEnemy = 1
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct AiDiplomacy
private static hashtable ht = InitHashtable()
player p
trigger killed
trigger attacked
private static method OnAttacked takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 4, GetHandleId(GetTriggeringTrigger()))
local player attacker = GetOwningPlayer(GetAttacker())
local player target = GetOwningPlayer(GetTriggerUnit())
if(attacker == this.p and ArePlayerEnemies(attacker, target) and GetAlliesCount(attacker) == 0 and GetAlliesCount(target) == 0)then
call SendAllyRequest(attacker, target)
endif
if(ArePlayerAllies(attacker, target))then
call DisableTrigger(this.attacked)
call TriggerSleepAction(5)
call EnableTrigger(this.attacked)
endif
set attacker = null
set target = null
endmethod
private static method OnKilled takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 3, GetHandleId(GetTriggeringTrigger()))
local player killer = GetOwningPlayer(GetKillingUnit())
if(ArePlayerAllies(this.p, killer))then
call StartWar(this.p, killer)
endif
set killer = null
call EnableTrigger(this.attacked)
call DisableTrigger(this.killed)
call TriggerSleepAction(5)
call EnableTrigger(this.killed)
endmethod
static method create takes player p returns thistype
local thistype this = thistype.allocate()
set this.p = p
set this.killed = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(this.killed, this.p, EVENT_PLAYER_UNIT_DEATH, null)
call TriggerAddAction(this.killed, function thistype.OnKilled)
call SaveInteger(thistype.ht, 3, GetHandleId(this.killed), this)
set this.attacked = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(this.attacked, EVENT_PLAYER_UNIT_ATTACKED)
call TriggerAddAction(this.attacked, function thistype.OnAttacked)
call SaveInteger(thistype.ht, 4, GetHandleId(this.attacked), this)
return this
endmethod
endstruct
function InitAiDiplomacy takes nothing returns nothing
local integer n = 0
loop
exitwhen n == bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(n)) == MAP_CONTROL_COMPUTER)then
call AiDiplomacy.create(Player(n))
endif
set n = n + 1
endloop
endfunction
endlibrary
library Diplomacy requires TeamManagerLib, PlayerDiplomacyMenuLib, AiDiplomacyLib
function InitDiplomacy takes boolean teamGame returns nothing
if(teamGame)then
return
endif
call SetFfaAlliances()
call InitPlayerDiplomacyMenu()
call InitAiDiplomacy()
endfunction
endlibrary
library SmoothOrdersLib initializer InitSmoothOrders
function interface IOrderTargetFilter takes unit source, unit target returns boolean
globals
private constant integer SmartOrder = 851971
private constant integer RallyOrder = 851970
private constant integer FogOrder = 851970
private constant real FindTargetRadius = 100
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
private function ColonizeFilter takes unit source, unit target returns boolean
return UnitAlive(target) and GetOwningPlayer(target) == Player(PLAYER_NEUTRAL_PASSIVE) and IsUnitType(target, UNIT_TYPE_ANCIENT)
endfunction
private function BonusResourcesFilter takes unit source, unit target returns boolean
return UnitAlive(target) and GetOwningPlayer(target) == GetOwningPlayer(source) and IsUnitType(target, UNIT_TYPE_ANCIENT)
endfunction
private function HarvestFilter takes unit source, unit target returns boolean
return UnitAlive(target) and GetOwningPlayer(target) == Player(PLAYER_NEUTRAL_PASSIVE) and GetResourceAmount(target) > 0
endfunction
struct SmoothOrder
private static hashtable ht = InitHashtable()
private static unit FindTarget_Source
private static IOrderTargetFilter FindTarget_Filter
private static unit FindTarget_Output
integer unitType
IOrderTargetFilter filter
integer orderId
trigger ordered
private static method FindTargetFilter takes nothing returns boolean
return thistype.FindTarget_Filter.evaluate(thistype.FindTarget_Source, GetFilterUnit())
endmethod
private static method FindTarget takes unit source, real targetX, real targetY, IOrderTargetFilter filter returns unit
local group g = CreateGroup()
set thistype.FindTarget_Source = source
set thistype.FindTarget_Filter = filter
call GroupEnumUnitsInRange(g, targetX, targetY, FindTargetRadius, Condition(function thistype.FindTargetFilter))
set FindTarget_Output = GroupPickRandomUnit(g)
call DestroyGroup(g)
set g = null
return FindTarget_Output
endmethod
private method Run takes unit source, unit target returns nothing
call Debug("Run " + OrderId2String(this.orderId))
if(target == null)then
set target = FindTarget(source, GetOrderPointX(), GetOrderPointY(), this.filter)
endif
if(target == null)then
call Debug("no area target found")
return
endif
if(this.filter.evaluate(source, target) == false)then
call Debug("no direct target found")
return
endif
if(IssueTargetOrderById(source, this.orderId, target))then
call Debug("target found: " + GetUnitName(target))
return
endif
call BlzQueueTargetOrderById(source, this.orderId, target)
call Debug("target queued: " + GetUnitName(target))
endmethod
private static method OnOrdered takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
local integer issuedOrder = GetIssuedOrderId()
if(issuedOrder != SmartOrder and issuedOrder != RallyOrder and issuedOrder != FogOrder)then
return // not a smart/fog/rally order
endif
if(GetUnitTypeId(GetOrderedUnit()) != unitType)then
return // unit type not habndled by this instance
endif
call this.Run(GetOrderedUnit(), GetOrderTargetUnit())
endmethod
static method create takes integer unitType, IOrderTargetFilter filter, integer orderId returns thistype
local thistype this = thistype.allocate()
set this.unitType = unitType
set this.filter = filter
set this.orderId = orderId
set this.ordered = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(this.ordered, EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterAnyUnitEventBJ(this.ordered, EVENT_PLAYER_UNIT_ISSUED_UNIT_ORDER)
call TriggerAddAction(this.ordered, function thistype.OnOrdered)
call SaveInteger(thistype.ht, 0, GetHandleId(this.ordered), this)
return this
endmethod
endstruct
private function InitSmoothOrders takes nothing returns nothing
// create all the smooth orders
call SmoothOrder.create('h002', ColonizeFilter, OrderId("magicleash"))
call SmoothOrder.create('h002', BonusResourcesFilter, OrderId("harvest"))
call SmoothOrder.create('h00L', HarvestFilter, OrderId("magicleash"))
endfunction
endlibrary
library MissilesRepository initializer InitMissilesRepository
globals
private hashtable ht = InitHashtable()
private constant integer MissileCount = -1
private constant integer MissileDataOffset = 20
private constant integer MissileSpawnDelay = 0
private constant integer MissileSpawnAngle = 1
private constant integer MissileSpawnOffset = 2
private constant integer MissileModel = 3
private constant integer MissileScale = 4
private constant integer MissileRange = 5
private constant integer MissileSpeed = 6
private constant integer MissileHoming = 7
private constant integer MissileCollision = 8
private constant integer MissileDamage = 9
private constant integer MissileDamageType = 10
private constant integer MissileSplash = 11
private constant integer MissilePassThrough = 12
private constant integer MissileImpactCallback = 13
private constant real MissileRangeBoost = 300
constant real HomingLow = 40
constant real HomingMedium = 80
constant real HomingHigh = 160
constant integer KineticDamage = 0
constant integer EnergyDamage = 1
constant integer ExplosiveDamage = 2
constant integer PlanetKillerDamage = 3
attacktype array AttackTypes
private integer LastSource = 0
private integer LastIndex = 0
endglobals
function interface MissileOnImpactCallback takes unit source, unit target, integer sourceId returns nothing
function RegisterMissileSource takes integer sourceId, real spawnDelay, real spawnAngle, real spawnOffset, string model, real scale, real range, real speed, real homing, real collision, real damage, integer damageType, real splash, real passThrough returns nothing
local integer count = 0
if(HaveSavedInteger(ht, sourceId, MissileCount))then
set count = LoadInteger(ht, sourceId, MissileCount)
endif
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileSpawnDelay, spawnDelay)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileSpawnAngle, spawnAngle)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileSpawnOffset, spawnOffset)
call SaveStr(ht, sourceId, MissileDataOffset * count + MissileModel, model)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileScale, scale)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileRange, range + MissileRangeBoost)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileSpeed, speed)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileHoming, homing)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileCollision, collision)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileDamage, damage)
call SaveInteger(ht, sourceId, MissileDataOffset * count + MissileDamageType, damageType)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissileSplash, splash)
call SaveReal(ht, sourceId, MissileDataOffset * count + MissilePassThrough, passThrough)
call SaveInteger(ht, sourceId, MissileDataOffset * count + MissileImpactCallback, 0)
// to add additional data to the misssile post declaration
set LastSource = sourceId
set LastIndex = count
set count = count + 1
call SaveInteger(ht, sourceId, MissileCount, count)
endfunction
function AddMissileImpactCallback takes MissileOnImpactCallback callback returns nothing
call SaveInteger(ht, LastSource, MissileDataOffset * LastIndex + MissileImpactCallback, callback)
endfunction
function IsMissileSource takes integer sourceId returns boolean
return HaveSavedInteger(ht, sourceId, MissileCount)
endfunction
function GetMissileCount takes integer sourceId returns integer
return LoadInteger(ht, sourceId, MissileCount)
endfunction
function GetMissileSpawnDelay takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileSpawnDelay)
endfunction
function GetMissileSpawnAngle takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileSpawnAngle)
endfunction
function GetMissileSpawnOffset takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileSpawnOffset)
endfunction
function GetMissileModel takes integer sourceId, integer index returns string
return LoadStr(ht, sourceId, MissileDataOffset * index + MissileModel)
endfunction
function GetMissileScale takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileScale)
endfunction
function GetMissileRange takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileRange)
endfunction
function GetMissileSpeed takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileSpeed)
endfunction
function GetMissileHoming takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileHoming)
endfunction
function GetMissileCollision takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileCollision)
endfunction
function GetMissileDamage takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileDamage)
endfunction
function GetMissileDamageType takes integer sourceId, integer index returns attacktype
return AttackTypes[LoadInteger(ht, sourceId, MissileDataOffset * index + MissileDamageType)]
endfunction
function GetMissileSplash takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissileSplash)
endfunction
function GetMissilePassThrough takes integer sourceId, integer index returns real
return LoadReal(ht, sourceId, MissileDataOffset * index + MissilePassThrough)
endfunction
function GetMissileImpactCallback takes integer sourceId, integer index returns MissileOnImpactCallback
return LoadInteger(ht, sourceId, MissileDataOffset * index + MissileImpactCallback)
endfunction
private function InitMissilesRepository takes nothing returns nothing
// constant definition
set AttackTypes[KineticDamage] = ATTACK_TYPE_MAGIC
set AttackTypes[EnergyDamage] = ATTACK_TYPE_MELEE
set AttackTypes[ExplosiveDamage] = ATTACK_TYPE_PIERCE
set AttackTypes[PlanetKillerDamage] = ATTACK_TYPE_CHAOS
// ship attack definitions
// defender "shotgun"
call RegisterMissileSource('h006', 0, 0, 0, "war3mapImported\\Bullet.mdl", 0.5, 600+0, 600, HomingMedium, 25, 10.0, KineticDamage, 0, 0)
call RegisterMissileSource('h006', 0.05, -20.0, -25, "war3mapImported\\Bullet.mdl", 0.5, 600+0, 600, HomingMedium, 25, 10.0, KineticDamage, 0, 0)
call RegisterMissileSource('h006', 0.1, 20.0, 25, "war3mapImported\\Bullet.mdl", 0.5, 600+0, 600, HomingMedium, 25, 10.0, KineticDamage, 0, 0)
// BATTLECRUISER + "B.R.B"
call RegisterMissileSource('h008', 0, 0, 0, "TinkerRocketMissile-NoSplat.mdl", 0.7, 700+0, 800, HomingHigh, 35, 10.0, ExplosiveDamage, 150, 0)
call RegisterMissileSource('h008', 0.08, -25, -30, "TinkerRocketMissile-NoSplat.mdl", 0.7, 730+0, 800, HomingHigh, 35, 10.0, ExplosiveDamage, 150, 0)
call RegisterMissileSource('h008', 0.16, 25, 30, "TinkerRocketMissile-NoSplat.mdl", 0.7, 730+0, 800, HomingHigh, 35, 10.0, ExplosiveDamage, 150, 0)
call RegisterMissileSource('h008', 0.24, -45, -60, "TinkerRocketMissile-NoSplat.mdl", 0.7, 760+0, 800, HomingHigh, 35, 10.0, ExplosiveDamage, 150, 0)
call RegisterMissileSource('h008', 0.32, 45, 60, "TinkerRocketMissile-NoSplat.mdl", 0.7, 760+0, 800, HomingHigh, 35, 10.0, ExplosiveDamage, 150, 0)
// destroyer
call RegisterMissileSource('h007', 0, 0, -30, "war3mapImported\\ShotGunBullet.mdx", .8, 400+0, 1400, HomingLow, 45, 35.0, KineticDamage, 0, 0)
call RegisterMissileSource('h007', 0, 0, 30, "war3mapImported\\ShotGunBullet.mdx", .8, 400+0, 1400, HomingLow, 45, 35.0, KineticDamage, 0, 0)
// hunter
call RegisterMissileSource('h00G', 0, -30, 40, "Abilities\\Weapons\\AncestralGuardianMissile\\AncestralGuardianMissile.mdl", 0.3, 450+0, 800, HomingHigh, 25, 10.0, EnergyDamage, 0, 0)
call RegisterMissileSource('h00G', 0.15, 30, -40, "Abilities\\Weapons\\AncestralGuardianMissile\\AncestralGuardianMissile.mdl", 0.3, 450+0, 800, HomingHigh, 25, 10.0, EnergyDamage, 0, 0)
// support
call RegisterMissileSource('h00O', 0, 0, 0, "Abilities\\Weapons\\LordofFlameMissile\\LordofFlameMissile.mdl", 0.8, 700+0, 700, HomingMedium, 30, 20.0, EnergyDamage, 0, 0.8)
// disruptor can hit its target directly
//call RegisterMissileSource('h00H', 0, 0, "Abilities\\Weapons\\FaerieDragonMissile\\FaerieDragonMissile.mdl", 1, 800+MissileRangeBoost, 1200, true, 30, 50, EnergyDamage, 0, 0)
// ravager
call RegisterMissileSource('h00I', 0, 0, 0, "Abilities\\Weapons\\BloodElfMissile\\BloodElfMissile.mdl", 1, 500+0, 800, HomingMedium, 25, 25.0, ExplosiveDamage, 0, 0)
// phalanx
call RegisterMissileSource('h00J', 0, 0, 0, "Abilities\\Weapons\\GreenDragonMissile\\GreenDragonMissile.mdl", 1, 350+0, 800, HomingLow, 60, 60.0, EnergyDamage, 0, 0.5)
// ancient frigate
call RegisterMissileSource('h00K', 0, 0, 25, "Abilities\\Weapons\\LichMissile\\LichMissile.mdl", 1, 350+0, 1000, HomingLow, 30, 15.0, EnergyDamage, 0, 1)
call RegisterMissileSource('h00K', 0, 0, -25, "Abilities\\Weapons\\LichMissile\\LichMissile.mdl", 1, 350+0, 1000, HomingLow, 30, 15.0, EnergyDamage, 0, 1)
endfunction
endlibrary
library MissileSystem requires MissilesRepository, EvasionUtils, MathLib, DamageDefinitionLib, InterceptorDroneLib
globals
private constant integer MissileTimerMapping = 0
private constant real MissileUpdateInterval = 0.04
private constant real MissileSplashDamageFactor = 0.5
constant real CollisionOffset = 256
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
globals
private unit f_TryCollide_owner
private real f_TryCollide_x
private real f_TryCollide_y
private real f_TryCollide_size
private group f_TryCollide_excepted
private unit f_TryCollide_OUTPUT // global to avoid local leak
endglobals
private function TryCollideFilter takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean notNeutral = GetOwningPlayer(u) != Player(PLAYER_NEUTRAL_PASSIVE)
local boolean notExcepted = f_TryCollide_excepted == null or IsUnitInGroup(u, f_TryCollide_excepted) == false
local boolean notOwner = f_TryCollide_owner == null or GetOwningPlayer(f_TryCollide_owner) != GetOwningPlayer(u) // no friendly-fire
local boolean notAlly = f_TryCollide_owner == null or IsUnitAlly(u, GetOwningPlayer(f_TryCollide_owner)) == false // no ally-fire
local boolean alive = UnitAlive(u)
local boolean notLocust = GetUnitAbilityLevel(u, 'Aloc') == 0
local boolean inRadius = IsWithinDistance(GetUnitX(u), GetUnitY(u), f_TryCollide_x, f_TryCollide_y, f_TryCollide_size + BlzGetUnitCollisionSize(u))
set u = null
return notNeutral and notOwner and notAlly and alive and notLocust and inRadius and notExcepted
endfunction
private function TryCollide takes unit owner, real x, real y, real size, unit forced, group excepted returns unit
local group g
// try to force the original target of the attack, if any; this allows players to damage their own unit if they use an attack command
if(forced != null and IsUnitInGroup(forced, excepted) == false and IsWithinDistance(x, y, GetUnitX(forced), GetUnitY(forced), size + BlzGetUnitCollisionSize(forced)))then
return forced
endif
set g = CreateGroup()
set f_TryCollide_owner = owner
set f_TryCollide_x = x
set f_TryCollide_y = y
set f_TryCollide_size = size
set f_TryCollide_excepted = excepted
call GroupEnumUnitsInRange(g, x, y, size + CollisionOffset, Condition(function TryCollideFilter))
set f_TryCollide_OUTPUT = FirstOfGroup(g)
call DestroyGroup(g)
set g = null
return f_TryCollide_OUTPUT
endfunction
function DamageM takes unit source, unit target, real damage, attacktype damageType returns nothing
if(damageType == AttackTypes[PlanetKillerDamage])then
set udg_NextDamageType = PlanetKillerMissileDamageType
call UnitDamageTarget(source, target, damage, false, false, damageType/*ATTACK_TYPE_NORMAL*/, DAMAGE_TYPE_UNIVERSAL, WEAPON_TYPE_WHOKNOWS)
else
set udg_NextDamageType = MissileDamageType
call UnitDamageTarget(source, target, damage, true, true, damageType, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
endif
//call TriggerEvaluate(udg_ClearDamageEvent)
endfunction
function DamageArea takes unit source, real x, real y, real size, real damage, attacktype damageType, unit except returns nothing
local group g = CreateGroup()
local unit u
set f_TryCollide_owner = source // don't allow friendly fire
set f_TryCollide_x = x
set f_TryCollide_y = y
set f_TryCollide_size = size
set f_TryCollide_excepted = null // don't filter targets
call GroupEnumUnitsInRange(g, x, y, size + CollisionOffset, Condition(function TryCollideFilter))
loop
set u = FirstOfGroup(g)
exitwhen u == null
if(u != except)then
call DamageM(source, u, damage, damageType)
endif
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
set g = null
set u = null
endfunction
struct Missile
private static hashtable ht = InitHashtable()
private integer sourceId
private unit source
private timer spawnDelayTimer
private timer updateTimer
private unit target
private real targetX
private real targetY
private integer index
private effect e
private real scale
private real range
private real speed
private real homing
private real collision
private real damage
private attacktype damageType
private real splash
private real passThrough
private MissileOnImpactCallback callback
private real x
private real y
private real z
private real facing
private real distanceTravelled
private group evaded
private boolean passingThrough
private boolean skipCollision
method UpdateTargetPosition takes nothing returns nothing
if(this.target != null and this.homing > 0)then
set this.targetX = GetUnitX(target)
set this.targetY = GetUnitY(target)
endif
endmethod
method AdjustTrajectory takes nothing returns nothing
local real angleToTarget
if(this.homing <= 0)then
return
endif
set angleToTarget = AngleBetweenCoordinates(this.x, this.y, this.targetX, this.targetY)
if(AngleSimilarity(this.facing, angleToTarget) < 2 * distanceTravelled / range - 1)then
set this.homing = 0
return
endif
set this.facing = AngleLerpFixed(this.facing, angleToTarget, this.homing * RMaxBJ(0.5, (1-0.5*(distanceTravelled / range))))
call BlzSetSpecialEffectYaw(this.e, this.facing * bj_DEGTORAD)
endmethod
method MoveTowardTarget takes nothing returns nothing
call this.AdjustTrajectory()
set this.x = PolarProjectionX(this.x, this.speed, this.facing)
set this.y = PolarProjectionY(this.y, this.speed, this.facing)
call BlzSetSpecialEffectPosition(this.e, this.x, this.y, this.z)
set this.distanceTravelled = distanceTravelled + this.speed
endmethod
method OnExplode takes unit collider returns nothing
call Debug("OnExplode")
call DamageArea(this.source, GetUnitX(collider), GetUnitY(collider), this.splash, this.damage * MissileSplashDamageFactor, damageType, collider)
endmethod
method OnDamage takes unit collider returns nothing
// single target damage
call DamageM(this.source, collider, this.damage, this.damageType)
call GroupAddUnit(this.evaded, collider)
if(this.target != null)then
set this.target = null
set this.homing = 0
endif
if(this.passingThrough == true)then
return // already passing through, return because we can't have both pass through and splash
endif
if(this.passThrough > 0)then
if(this.passThrough != 1)then
set this.scale = this.passThrough * this.scale
call BlzSetSpecialEffectScale(this.e, this.scale)
set this.speed = this.passThrough * this.speed
set this.collision = this.passThrough * this.collision
set this.damage = this.passThrough * this.damage
endif
set this.passingThrough = true
return // return because we can't have both pass through and splash
endif
if(this.splash > 0)then
call this.OnExplode(collider)
endif
endmethod
method OnCollide takes unit collider returns boolean
// only apply evasion for non-planet killer attacks
if(TryInterceptMissile(collider, this.damageType, this.x, this.y, this.z))then
call this.OnDamage(collider)
return true
endif
if(this.damageType != AttackTypes[PlanetKillerDamage] and GetRandomReal(0, 1) < GetRelativeEvasion(this.source, collider))then
call ShowEvasion(collider)
call GroupAddUnit(this.evaded, collider)
if(collider == this.target)then
set this.target = null
set this.homing = 0
endif
return false
endif
if(this.damage > 0)then
call this.OnDamage(collider)
endif
if(this.callback != 0)then
call this.callback.execute(this.source, collider, this.sourceId)
endif
return (this.passThrough > 0) == false
endmethod
method OnExpire takes nothing returns nothing
if(this.splash > 0)then
call this.OnExplode(null)
else
call BlzSetSpecialEffectTimeScale(this.e, 5000)
endif
endmethod
private static method OnUpdate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, MissileTimerMapping, GetHandleId(GetExpiredTimer()))
local unit collider
call this.UpdateTargetPosition()
call this.MoveTowardTarget()
set this.skipCollision = not skipCollision
if(skipCollision)then
return
endif
set collider = TryCollide(this.source, this.x, this.y, this.collision, this.target, this.evaded)
if(collider != null and this.OnCollide(collider))then
set collider = null
call this.destroy()
return
endif
if(this.distanceTravelled > this.range)then
call this.OnExpire()
call this.destroy()
return
endif
endmethod
method CreateMissileFrom takes integer sourceId, integer index, real x, real y, real z, real facing returns nothing
local real offset = GetMissileSpawnOffset(sourceId, index)
set this.x = PolarProjectionX(x, offset, this.facing + 90)
set this.y = PolarProjectionY(y, offset, this.facing + 90)
set this.z = z
set this.facing = facing + GetMissileSpawnAngle(sourceId, index)
set this.distanceTravelled = 0
set this.passingThrough = false
set this.e = AddSpecialEffect(GetMissileModel(sourceId, index), this.x, this.y)
call BlzSetSpecialEffectZ(this.e, this.z)
call BlzSetSpecialEffectScale(this.e, GetMissileScale(sourceId, index))
call BlzSetSpecialEffectYaw(this.e, this.facing * bj_DEGTORAD)
set this.range = GetMissileRange(sourceId, index)
set this.speed = GetMissileSpeed(sourceId, index) * MissileUpdateInterval
set this.homing = GetMissileHoming(sourceId, index) * MissileUpdateInterval
set this.collision = GetMissileCollision(sourceId, index)
set this.damage = GetMissileDamage(sourceId, index)
//if(GetUnitAbilityLevel(this.source, 'B008') > 0)then
// set this.damage = this.damage - 30
//endif
set this.damageType = GetMissileDamageType(sourceId, index)
set this.splash = GetMissileSplash(sourceId, index)
set this.passThrough = GetMissilePassThrough(sourceId, index)
set this.callback = GetMissileImpactCallback(sourceId, index)
endmethod
private static method Spawn takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, MissileTimerMapping, GetHandleId(GetExpiredTimer()))
call this.CreateMissileFrom(this.sourceId, this.index, GetUnitX(this.source), GetUnitY(this.source), GetUnitFlyHeight(this.source), GetUnitFacing(this.source))
set this.updateTimer = CreateTimer()
call SaveInteger(thistype.ht, MissileTimerMapping, GetHandleId(this.updateTimer), this)
call TimerStart(this.updateTimer, MissileUpdateInterval, true, function thistype.OnUpdate)
endmethod
method SetTargetUnit takes unit target returns nothing
set this.target = target
set this.targetX = GetUnitX(target)
set this.targetY = GetUnitY(target)
endmethod
method SetTargetCoordinates takes real x, real y returns nothing
set this.targetX = x
set this.targetY = y
endmethod
static method create takes unit source, integer sourceId, integer index returns thistype
local thistype this = thistype.allocate()
local real spawnDelay = GetMissileSpawnDelay(sourceId, index)
set this.sourceId = sourceId
set this.index = index
set this.source = source
set this.evaded = CreateGroup()
if(spawnDelay > 0)then
// create a timer delaying the spawn; only when it expires will the missile spawn and its update loop start
set this.spawnDelayTimer = CreateTimer()
call SaveInteger(thistype.ht, MissileTimerMapping, GetHandleId(this.spawnDelayTimer), this)
call TimerStart(this.spawnDelayTimer, spawnDelay, false, function thistype.Spawn)
set this.updateTimer = null
else
// spawn the missile immediately and start the update timer
set this.spawnDelayTimer = null
call this.CreateMissileFrom(this.sourceId, this.index, GetUnitX(this.source), GetUnitY(this.source), GetUnitFlyHeight(this.source), GetUnitFacing(this.source))
set this.updateTimer = CreateTimer()
call SaveInteger(thistype.ht, MissileTimerMapping, GetHandleId(this.updateTimer), this)
call TimerStart(this.updateTimer, MissileUpdateInterval, true, function thistype.OnUpdate)
endif
return this
endmethod
method destroy takes nothing returns nothing
if(this.spawnDelayTimer != null)then
call RemoveSavedInteger(thistype.ht, MissileTimerMapping, GetHandleId(this.spawnDelayTimer))
call DestroyTimer(this.spawnDelayTimer)
endif
if(this.updateTimer != null)then
call RemoveSavedInteger(thistype.ht, MissileTimerMapping, GetHandleId(this.updateTimer))
call DestroyTimer(this.updateTimer)
endif
call DestroyEffect(this.e)
call DestroyGroup(this.evaded)
set this.source = null
set this.spawnDelayTimer = null
set this.updateTimer = null
set this.target = null
set this.e = null
set this.damageType = null
set this.evaded = null
call this.deallocate()
endmethod
static method CreateAllTargetAngled takes unit source, integer sourceId, unit target returns nothing
local integer i = 0
local integer count = GetMissileCount(sourceId)
local real angle = AngleBetweenCoordinates(GetUnitX(source), GetUnitY(source), GetUnitX(target), GetUnitY(target))
local Missile m
//call DisplayTextToPlayer(Player(0), 0, 0, "CreateAllTarget (" + I2S(count) + ")")
loop
set m = Missile.create(source, sourceId, i)
call m.SetTargetUnit(target)
set m.facing = angle
call BlzSetSpecialEffectYaw(m.e, m.facing * bj_DEGTORAD)
set i = i + 1
exitwhen i == count
endloop
endmethod
static method CreateAllTarget takes unit source, integer sourceId, unit target returns nothing
local integer i = 0
local integer count = GetMissileCount(sourceId)
local Missile m
loop
set m = Missile.create(source, sourceId, i)
call m.SetTargetUnit(target)
set i = i + 1
exitwhen i == count
endloop
endmethod
static method CreateAllXY takes unit source, integer sourceId, real x, real y returns nothing
local integer i = 0
local integer count = GetMissileCount(sourceId)
local Missile m
loop
set m = Missile.create(source, sourceId, i)
call m.SetTargetCoordinates(x, y)
set i = i + 1
exitwhen i == count
endloop
endmethod
endstruct
function DamageSpawnMissile takes unit source, unit target returns nothing
call Missile.CreateAllTarget(source, GetUnitTypeId(udg_DamageEventSource), target)
endfunction
function SpellSpawnMissile takes nothing returns nothing
if(GetSpellTargetUnit() != null)then
//call DisplayTextToPlayer(Player(0), 0, 0, GetObjectName(GetSpellAbilityId()) + " SpellSpawnMissile (target)")
call Missile.CreateAllTarget(GetSpellAbilityUnit(), GetSpellAbilityId(), GetSpellTargetUnit())
else
//call DisplayTextToPlayer(Player(0), 0, 0, GetObjectName(GetSpellAbilityId()) + " SpellSpawnMissile (point)")
call Missile.CreateAllXY(GetSpellAbilityUnit(), GetSpellAbilityId(), GetSpellTargetX(), GetSpellTargetY())
endif
endfunction
function TryDamageSpawnMissile takes nothing returns boolean
if(udg_IsDamageSpell)then
return false // don't create from spell damage; spells spawn their own missiles
endif
if(udg_DamageEventType == MissileDamageType)then
return false // don't trigger missile on missile damage...
endif
if(udg_DamageEventAOE > 1)then
return false // don't trigger missile on AOE damage
endif
if(IsMissileSource(GetUnitTypeId(udg_DamageEventSource)) == false)then
return false // don't trigger missile if the source can't create a missile
endif
set udg_DamageEventAmount = 0 // negate the damage of the attack
call DamageSpawnMissile(udg_DamageEventSource, udg_DamageEventTarget) // do the thing!
return true
endfunction
endlibrary
library BombardSystem initializer InitBombardSystem requires MissileSystem, MissilesRepository
globals
private constant integer BombardTimerMapping = 0
private constant integer BombardTriggerMapping = 1
private constant integer GenericBombardAbility = 'A01L'
endglobals
struct Bombard
private static hashtable ht = InitHashtable()
private unit caster
private unit target
private real x
private real y
private integer sourceId
private integer abilityId
private real fireInterval
private timer fireTimer
private trigger endTrigger
private static method Fire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, BombardTimerMapping, GetHandleId(GetExpiredTimer()))
if(this.target != null)then
call Missile.CreateAllTarget(this.caster, this.sourceId, this.target)
else
call Missile.CreateAllXY(this.caster, this.sourceId, this.x, this.y)
endif
call BlzStartUnitAbilityCooldown(this.caster, this.abilityId, this.fireInterval)
call SetUnitAnimation(this.caster, "attack")
endmethod
private static method Interrupt takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, BombardTriggerMapping, GetHandleId(GetTriggeringTrigger()))
call IssueImmediateOrderById(this.caster, 851972)
call this.destroy()
endmethod
method SetTargetUnit takes unit target returns nothing
set this.target = target
call TriggerRegisterUnitEvent(this.endTrigger, this.target, EVENT_UNIT_DEATH)
endmethod
method SetTargetXY takes real x, real y returns nothing
set this.x = x
set this.y = y
endmethod
static method create takes unit caster, integer sourceId, integer abilityId, real fireInterval returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.sourceId = sourceId
set this.abilityId = abilityId
set this.fireInterval = fireInterval
set this.target = null
set this.fireTimer = CreateTimer()
set this.endTrigger = CreateTrigger()
call TimerStart(this.fireTimer, this.fireInterval, true, function thistype.Fire)
call SaveInteger(thistype.ht, BombardTimerMapping, GetHandleId(this.fireTimer), this)
call TriggerRegisterUnitEvent(this.endTrigger, this.caster, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.endTrigger, this.caster, EVENT_UNIT_SPELL_ENDCAST)
call TriggerRegisterUnitEvent(this.endTrigger, this.caster, EVENT_UNIT_CHANGE_OWNER)
call TriggerRegisterUnitEvent(this.endTrigger, this.target, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.endTrigger, this.target, EVENT_UNIT_CHANGE_OWNER)
call TriggerAddAction(this.endTrigger, function thistype.Interrupt)
call SaveInteger(thistype.ht, BombardTriggerMapping, GetHandleId(this.endTrigger), this)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, BombardTimerMapping, GetHandleId(this.fireTimer))
call RemoveSavedInteger(thistype.ht, BombardTriggerMapping, GetHandleId(this.endTrigger))
call PauseTimer(this.fireTimer)
call DestroyTimer(this.fireTimer)
call DestroyTrigger(this.endTrigger)
set this.caster = null
set this.target = null
set this.fireTimer = null
set this.endTrigger = null
call this.deallocate()
endmethod
endstruct
struct BombardAbility
readonly static trigger AbilityTrigger = CreateTrigger()
readonly static thistype array Abilities
readonly static integer AbilityCount = 0
readonly integer triggerAbilityId
readonly integer sourceId // set to 0 to use the ship default weapons
method Start takes nothing returns nothing
local integer sourceId = this.sourceId
local real cooldown = 0
local Bombard b
if(sourceId == 0)then
set sourceId = GetUnitTypeId(GetSpellAbilityUnit())
set cooldown = BlzGetUnitAttackCooldown(GetSpellAbilityUnit(), 0)
//call DisplayTextToPlayer(Player(0), 0, 0, GetObjectName(this.triggerAbilityId) + " starting with ship weapon missiles (" + GetObjectName(sourceId )+ ")")
else
set cooldown = BlzGetAbilityCooldown(sourceId, 0)
//call DisplayTextToPlayer(Player(0), 0, 0, GetObjectName(this.triggerAbilityId) + " starting with ability missiles (" + GetObjectName(sourceId) + ")")
endif
set b = Bombard.create(GetSpellAbilityUnit(), sourceId, this.triggerAbilityId, cooldown)
if(GetSpellTargetUnit() != null)then
call b.SetTargetUnit(GetSpellTargetUnit())
else
call b.SetTargetXY(GetSpellTargetX(), GetSpellTargetY())
endif
endmethod
static method create takes integer triggerAbilityId, integer sourceId returns thistype
local thistype this = thistype.allocate()
set this.triggerAbilityId = triggerAbilityId
set this.sourceId = sourceId
set thistype.Abilities[AbilityCount] = this
set thistype.AbilityCount = thistype.AbilityCount + 1
return this
endmethod
endstruct
private function BombardAbilityStartAction takes nothing returns nothing
local integer i = 0
local BombardAbility ba
loop
exitwhen i == BombardAbility.AbilityCount
set ba = BombardAbility.Abilities[i]
if(ba.triggerAbilityId == GetSpellAbilityId())then
call ba.Start()
return
endif
set i = i + 1
endloop
endfunction
private function InitBombardSystem takes nothing returns nothing
call TriggerRegisterAnyUnitEventBJ(BombardAbility.AbilityTrigger, EVENT_PLAYER_UNIT_SPELL_CHANNEL)
call TriggerAddAction(BombardAbility.AbilityTrigger, function BombardAbilityStartAction)
call BombardAbility.create(GenericBombardAbility, 0) // Bombard ability, use default ship weapon
call BombardAbility.create('A01K', 'A01K') // Planet Cracker ability
// planet cracker missile
call RegisterMissileSource('A01K', 0, 0, 0, "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl", 1.5, 300, 300, HomingMedium, 80, 100.0, PlanetKillerDamage, 0, 0)
endfunction
endlibrary
library AutocannonLib requires MissileSystem
function interface ISourceCondition takes unit source returns boolean
function interface ITargetCondition takes unit source, unit target returns boolean
function interface IOnFireAction takes unit source, unit target returns nothing
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct Autocannon
private static hashtable ht = InitHashtable()
private static thistype FindTarget_Instance
private static unit FindTarget_Output
unit source
integer missileType
real range
real cooldown
trigger shoot
trigger destroyed
ISourceCondition sourceCondition
ITargetCondition targetCondition
IOnFireAction onFireAction
private static method OnDestroyed takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
static method DefaultFindTargetFilter takes unit source, unit target returns boolean
if(source == target)then
call Debug("don't shoot at self")
return false // don't shoot at self
endif
if(UnitAlive(target) == false)then
call Debug("don't shoot at dead units")
return false // don't shoot at dead units
endif
if(GetOwningPlayer(source) == GetOwningPlayer(target))then
call Debug("don't shoot at player units")
return false // don't shoot at player units
endif
if(IsPlayerAlly(GetOwningPlayer(source), GetOwningPlayer(target)))then
call Debug("don't shoot at allies")
return false // don't shoot at allies
endif
if(IsVisibleToPlayer(GetUnitX(target), GetUnitY(target), GetOwningPlayer(source)) == false)then
call Debug("outside of vision range")
return false // outside of vision range
endif
if(IsUnitInvisible(target, GetOwningPlayer(source)))then
call Debug("invisible unit")
return false // invisible unit
endif
if(IsUnitVisible(target, GetOwningPlayer(source)) == false)then
call Debug("invisible unit")
return false // invisible unit
endif
return true
endmethod
private static method FindTargetFilter takes nothing returns boolean
local real range = thistype.FindTarget_Instance.range + (BlzGetUnitCollisionSize(thistype.FindTarget_Instance.source) + BlzGetUnitCollisionSize(GetFilterUnit())) / 2
call Debug("FindTargetFilter: " + R2S(range))
// check for the range offset
if(IsWithinDistance(GetUnitX(thistype.FindTarget_Instance.source), GetUnitY(thistype.FindTarget_Instance.source), GetUnitX(GetFilterUnit()), GetUnitY(GetFilterUnit()), range) == false)then
call Debug("not in range")
return false // not in range
endif
// check for the filter
if(thistype.FindTarget_Instance.targetCondition != 0 and thistype.FindTarget_Instance.targetCondition.evaluate(thistype.FindTarget_Instance.source, GetFilterUnit()) == false)then
call Debug("targetCondition not matching")
return false // targetCondition not matching
endif
// fallback, always true
call Debug("Valid target")
return true
endmethod
private method FindTarget takes nothing returns unit
local group g = CreateGroup()
local real radius = BlzGetUnitCollisionSize(this.source) / 2 + this.range + CollisionOffset
set thistype.FindTarget_Instance = this
call Debug("FindTarget: " + R2S(radius))
call GroupEnumUnitsInRange(g, GetUnitX(this.source), GetUnitY(this.source), radius, Condition(function thistype.FindTargetFilter))
call Debug("FindTarget done")
set FindTarget_Output = GroupPickRandomUnit(g)
call DestroyGroup(g)
set g = null
return FindTarget_Output
endmethod
private method TryFire takes nothing returns nothing
local unit target
call Debug("TryFire")
set target = this.FindTarget()
if(target == null)then
return
endif
call Debug("Found target")
call Missile.CreateAllTargetAngled(this.source, this.missileType, target)
if(this.onFireAction != 0)then
call this.onFireAction.execute(this.source, target)
endif
set target = null
endmethod
private static method OnShoot takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
call Debug("OnShoot")
if(this.sourceCondition != 0 and this.sourceCondition.evaluate(this.source) == false)then
return // source condition not met, don't try to shoot
endif
call this.TryFire()
endmethod
static method create takes unit source, integer missileType, real range, real cooldown returns thistype
local thistype this = thistype.allocate()
set this.source = source
set this.missileType = missileType
set this.range = range
set this.cooldown = cooldown
set this.shoot = CreateTrigger()
call SaveInteger(thistype.ht, 0, GetHandleId(this.shoot), this)
call TriggerRegisterTimerEvent(this.shoot, this.cooldown, true)
call TriggerAddAction(this.shoot, function thistype.OnShoot)
set this.destroyed = CreateTrigger()
call SaveInteger(thistype.ht, 1, GetHandleId(this.destroyed), this)
call TriggerRegisterUnitEvent(this.destroyed, this.source, EVENT_UNIT_DEATH)
call TriggerAddAction(this.destroyed, function thistype.OnDestroyed)
set this.sourceCondition = 0
set this.targetCondition = thistype.DefaultFindTargetFilter
set this.onFireAction = 0
call Debug("Autocannon create")
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.shoot))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.destroyed))
call DestroyTrigger(this.shoot)
call DestroyTrigger(this.destroyed)
set this.source = null
set this.shoot = null
set this.destroyed = null
call Debug("Autocannon destroy")
call this.deallocate()
endmethod
endstruct
endlibrary
library PlanetaryModuleLib initializer InitPlanetaryModule
globals
private PlanetaryModule ModuleCovertOps
private PlanetaryModule ModuleMissileBattery
private PlanetaryModule ModuleAutocannonArray
private PlanetaryModule ModuleFusionCore
private PlanetaryModule ModulePlanetaryShield
private PlanetaryModule ModuleSupplyStation
private PlanetaryModule ModuleExportVenture
private PlanetaryModule ModuleColonialDraftingCenter
private PlanetaryModule ModulePlanetaryFactory
private constant integer UpgradePlayerModulesTypeId = 'R00E'
private constant integer ModuleMenuOpenAbilityId = 'A02C'
private constant integer ModuleMenuCloseAbilityId = 'A02B'
private constant integer ModuleMenuToggleOrderId = 852100
private constant integer ModuleMenuOpenOrderId = 852055
private constant integer ModuleMenuCloseOrderId = 852056
private constant trigger ModuleMenuOpenTrigger = CreateTrigger()
private constant trigger ModuleMenuCloseTrigger = CreateTrigger()
private constant trigger ModuleMenuAutoCloseTrigger = CreateTrigger()
private constant trigger TrainingStartTrigger = CreateTrigger()
private constant trigger InstallModuleTrigger = CreateTrigger()
private constant trigger UpgradePlayerModulesTrigger = CreateTrigger()
private constant string ModuleInstalledSoundPath = "Advisor\\PlanetaryModuleDone1.wav"
private sound ModuleInstalledSound
endglobals
struct PlanetaryModuleInstance
private static hashtable ht = InitHashtable()
readonly unit planetUnit
readonly item moduleItem
private trigger removeModuleTrigger
readonly trigger onRemoveTrigger
private static method OnRemove takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
call TriggerEvaluate(this.onRemoveTrigger)
call this.destroy()
endmethod
static method create takes unit planetUnit, item moduleItem returns thistype
local thistype this = thistype.allocate()
set this.planetUnit = planetUnit
set this.moduleItem = moduleItem
set this.removeModuleTrigger = CreateTrigger()
call SaveInteger(thistype.ht, 0, GetHandleId(this.removeModuleTrigger), this)
call TriggerRegisterUnitEvent(this.removeModuleTrigger, this.planetUnit, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.removeModuleTrigger, this.planetUnit, EVENT_UNIT_CHANGE_OWNER)
call TriggerRegisterDeathEvent(this.removeModuleTrigger, this.moduleItem)
call TriggerAddAction(this.removeModuleTrigger, function thistype.OnRemove)
set this.onRemoveTrigger = CreateTrigger()
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.removeModuleTrigger))
call RemoveItem(this.moduleItem)
call DestroyTrigger(this.removeModuleTrigger)
call DestroyTrigger(this.onRemoveTrigger)
set this.planetUnit = null
set this.moduleItem = null
set this.removeModuleTrigger = null
set this.onRemoveTrigger = null
call this.deallocate()
endmethod
endstruct
struct PlanetaryModule
private static hashtable ht = InitHashtable()
integer unitId
integer itemId
integer itemId2
method ShowIcon takes unit u returns nothing
if(UnitHasItemOfTypeBJ(u, this.itemId))then
return // already has it, don't display
endif
if(UnitInventoryCount(u) == UnitInventorySize(u))then
return // no more available slots
endif
call SetPlayerTechMaxAllowed(GetOwningPlayer(u), this.unitId, -1)
endmethod
method HideIcon takes unit u returns nothing
call SetPlayerTechMaxAllowed(GetOwningPlayer(u), this.unitId, 0)
endmethod
method CanInstallModule takes unit u returns boolean
if(UnitHasItemOfTypeBJ(u, this.itemId))then
call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0, "Can't install |cffffcc00" + GetObjectName(this.itemId) + "|r: already installed.")
return false
endif
if(UnitInventoryCount(u) == UnitInventorySize(u))then
call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0, "Can't install |cffffcc00" + GetObjectName(this.itemId) + "|r: no free module slot.")
return false
endif
return true
endmethod
method RefundModule takes player p returns nothing
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetUnitGoldCost(this.unitId) + GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetUnitWoodCost(this.unitId) + GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER))
endmethod
method HasUpgrade takes nothing returns boolean
return this.itemId2 != 0
endmethod
method GetPlayerModuleTypeId takes player p returns integer
if(GetPlayerTechCount(p, UpgradePlayerModulesTypeId, true) == 0 or this.HasUpgrade() == false)then
return this.itemId
endif
return this.itemId2
endmethod
private static method UpgradeModulesFilter takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) // only alive planets
endmethod
method UpgradePlayerModules takes player p returns nothing
local group g = CreateGroup()
local unit planet
local integer slot = 0
call GroupEnumUnitsOfPlayer(g, p, function thistype.UpgradeModulesFilter)
loop
set planet = FirstOfGroup(g)
exitwhen planet == null
set slot = GetInventoryIndexOfItemTypeBJ(planet, this.itemId)-1
if(slot != -1)then
call RemoveItem(UnitItemInSlot(planet, slot))
call UnitAddItem(planet, CreateItem(this.itemId2, GetUnitX(planet), GetUnitY(planet)))
//call UnitAddItemToSlotById(planet, this.itemId2, slot)
endif
call GroupRemoveUnit(g, planet)
endloop
call DestroyGroup(g)
set g = null
set planet = null
endmethod
method TryUpgradePlayerModules takes player p returns nothing
if(this.HasUpgrade())then
call this.UpgradePlayerModules(p)
endif
endmethod
method InstallModule takes unit u returns nothing
local player p = GetOwningPlayer(u)
local integer moduleTypeId = this.GetPlayerModuleTypeId(p)
call UnitAddItem(u, CreateItem(moduleTypeId, 0, 0))
call this.HideIcon(u)
call DisplayTextToPlayer(p, 0, 0, "|cffffcc00" + GetObjectName(moduleTypeId) + "|r installed successfully")
if(GetLocalPlayer() == p)then
call StartSound(ModuleInstalledSound)
endif
set p = null
endmethod
static method UnlockMenuAction takes nothing returns nothing
call BlzUnitDisableAbility(GetTriggerUnit(), ModuleMenuOpenAbilityId, false, false)
call BlzUnitDisableAbility(GetTriggerUnit(), ModuleMenuCloseAbilityId, false, false)
if(GetUnitAbilityLevel(GetTriggerUnit(), ModuleMenuOpenAbilityId) == 0)then
call BlzUnitDisableAbility(GetTriggerUnit(), 'A01T', false, false) // demolish planteray module
endif
endmethod
static method ModuleCondition takes nothing returns boolean
return HaveSavedInteger(thistype.ht, 0, GetUnitTypeId(GetTrainedUnit()))
endmethod
static method InstallModuleAction takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetUnitTypeId(GetTrainedUnit()))
call RemoveUnit(GetTrainedUnit())
if(this.CanInstallModule(GetTriggerUnit()))then
call this.InstallModule(GetTriggerUnit())
else
call this.RefundModule(GetOwningPlayer(GetTriggerUnit()))
endif
endmethod
static method create takes integer unitId, integer itemId, integer itemId2 returns thistype
local thistype this = thistype.allocate()
set this.unitId = unitId
set this.itemId = itemId
set this.itemId2 = itemId2
call SaveInteger(thistype.ht, 0, this.unitId, this)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, this.unitId)
call this.deallocate()
endmethod
endstruct
// open
private function ModuleMenuOpenCondition takes nothing returns boolean
return GetSpellAbilityId() == ModuleMenuOpenAbilityId
endfunction
private function ModuleMenuOpenAction takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetOwningPlayer(u)
call SetPlayerTechMaxAllowed(p, 'h002', 0) // space builder
call SetPlayerTechMaxAllowed(p, 'h003', 0) // colonizer
call SetPlayerTechMaxAllowed(p, 'h00L', 0) // refinery
call SetPlayerTechMaxAllowed(p, 'h004', 0) // probe
call SetPlayerTechMaxAllowed(p, 'n000', 0) // frozen terraform
call SetPlayerTechMaxAllowed(p, 'n001', 0) // magma terraform
call SetPlayerTechMaxAllowed(p, 'n002', 0) // hospitable terraform
call BlzUnitDisableAbility(u, 'ARal', true, true) // rally point
call BlzUnitDisableAbility(u, 'A001', true, true) // home planet help
call BlzUnitDisableAbility(u, 'A002', true, true) // frozen planet help
call BlzUnitDisableAbility(u, 'A003', true, true) // magma planet help
call BlzUnitDisableAbility(u, 'A004', true, true) // hospitable planet help
call ModuleCovertOps.ShowIcon(u)
//call ModuleMissileBattery.ShowIcon(u)
call ModuleAutocannonArray.ShowIcon(u)
call ModuleFusionCore.ShowIcon(u)
//call ModulePlanetaryShield.ShowIcon(u)
//call ModuleSupplyStation.ShowIcon(u)
call ModuleExportVenture.ShowIcon(u)
call ModuleColonialDraftingCenter.ShowIcon(u)
call ModulePlanetaryFactory.ShowIcon(u)
call UnitRemoveAbility(u, ModuleMenuOpenAbilityId)
//call UnitRemoveAbility(u, 'A00X')
//call UnitRemoveAbility(u, 'A00W')
call UnitAddAbility(u, ModuleMenuCloseAbilityId)
call UnitAddAbility(u, 'A01T')
call BlzUnitDisableAbility(GetTriggerUnit(), ModuleMenuCloseAbilityId, false, false)
set u = null
set p = null
endfunction
// close
private function ModuleMenuCloseCondition takes nothing returns boolean
return GetSpellAbilityId() == ModuleMenuCloseAbilityId
endfunction
private function ModuleMenuCloseAction takes nothing returns nothing
local unit u = GetTriggerUnit()
local player p = GetOwningPlayer(u)
call SetPlayerTechMaxAllowed(p, 'h002', -1) // space builder
call SetPlayerTechMaxAllowed(p, 'h003', -1) // colonizer
call SetPlayerTechMaxAllowed(p, 'h00L', -1) // refinery
call SetPlayerTechMaxAllowed(p, 'h004', -1) // probe
call SetPlayerTechMaxAllowed(p, 'n000', -1) // frozen terraform
call SetPlayerTechMaxAllowed(p, 'n001', -1) // magma terraform
call SetPlayerTechMaxAllowed(p, 'n002', -1) // hospitable terraform
call BlzUnitDisableAbility(u, 'ARal', false, false) // rally point
call BlzUnitDisableAbility(u, 'A001', false, false) // home planet help
call BlzUnitDisableAbility(u, 'A002', false, false) // frozen planet help
call BlzUnitDisableAbility(u, 'A003', false, false) // magma planet help
call BlzUnitDisableAbility(u, 'A004', false, false) // hospitable planet help
call ModuleCovertOps.HideIcon(u)
//call ModuleMissileBattery.HideIcon(u)
call ModuleAutocannonArray.HideIcon(u)
call ModuleFusionCore.HideIcon(u)
//call ModulePlanetaryShield.HideIcon(u)
//call ModuleSupplyStation.HideIcon(u)
call ModuleExportVenture.HideIcon(u)
call ModuleColonialDraftingCenter.HideIcon(u)
call ModulePlanetaryFactory.HideIcon(u)
call UnitRemoveAbility(u, ModuleMenuCloseAbilityId)
call UnitRemoveAbility(u, 'A01T')
call UnitAddAbility(u, ModuleMenuOpenAbilityId)
//call UnitAddAbility(u, 'A00X')
//call UnitAddAbility(u, 'A00W')
call BlzUnitDisableAbility(GetTriggerUnit(), ModuleMenuOpenAbilityId, false, false)
set u = null
set p = null
endfunction
// auto-close
private function ModuleMenuAutoCloseFilter takes nothing returns boolean
return GetUnitAbilityLevel(GetFilterUnit(), ModuleMenuCloseAbilityId) > 0
endfunction
private function ModuleMenuAutoCloseAction takes nothing returns nothing
if(GetOwningPlayer(GetTriggerUnit()) != GetTriggerPlayer())then
return
endif
call IssueImmediateOrderById(GetTriggerUnit(), ModuleMenuToggleOrderId)
endfunction
// module upgrade
private function UpgradePlayerModulesCondition takes nothing returns boolean
return GetResearched() == UpgradePlayerModulesTypeId
endfunction
private function UpgradePlayerModulesAction takes nothing returns nothing
local player p = GetOwningPlayer(GetResearchingUnit())
call ModuleCovertOps.TryUpgradePlayerModules(p)
call ModuleAutocannonArray.TryUpgradePlayerModules(p)
call ModuleFusionCore.TryUpgradePlayerModules(p)
call ModuleExportVenture.TryUpgradePlayerModules(p)
call ModuleColonialDraftingCenter.TryUpgradePlayerModules(p)
call ModulePlanetaryFactory.TryUpgradePlayerModules(p)
set p = null
endfunction
private function InitPlanetaryModule takes nothing returns nothing
local integer n = 0
// opening the menu
call TriggerRegisterAnyUnitEventBJ(ModuleMenuOpenTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(ModuleMenuOpenTrigger, Condition(function ModuleMenuOpenCondition))
call TriggerAddAction(ModuleMenuOpenTrigger, function ModuleMenuOpenAction)
// manually closing the menu
call TriggerRegisterAnyUnitEventBJ(ModuleMenuCloseTrigger, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(ModuleMenuCloseTrigger, Condition(function ModuleMenuCloseCondition))
call TriggerAddAction(ModuleMenuCloseTrigger, function ModuleMenuCloseAction)
// automatically close the menu when selecting/deselecting a planet
loop
exitwhen n == 12
call TriggerRegisterPlayerUnitEvent(ModuleMenuAutoCloseTrigger, Player(n), EVENT_PLAYER_UNIT_DESELECTED, Condition(function ModuleMenuAutoCloseFilter))
set n = n + 1
endloop
call TriggerAddAction(ModuleMenuAutoCloseTrigger, function ModuleMenuAutoCloseAction)
// when producing a module dummy unit ends, create the item
call TriggerRegisterAnyUnitEventBJ(TrainingStartTrigger, EVENT_PLAYER_UNIT_TRAIN_START)
call TriggerAddAction(TrainingStartTrigger, function PlanetaryModule.UnlockMenuAction)
call TriggerRegisterAnyUnitEventBJ(InstallModuleTrigger, EVENT_PLAYER_UNIT_TRAIN_FINISH)
call TriggerAddCondition(InstallModuleTrigger, Condition(function PlanetaryModule.ModuleCondition))
call TriggerAddAction(InstallModuleTrigger, function PlanetaryModule.InstallModuleAction)
// when researching Offworld Logistics, upgrade all existing modules
call TriggerRegisterAnyUnitEventBJ(UpgradePlayerModulesTrigger, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddCondition(UpgradePlayerModulesTrigger, Condition(function UpgradePlayerModulesCondition))
call TriggerAddAction(UpgradePlayerModulesTrigger, function UpgradePlayerModulesAction)
// register the different module dummy units and items
set ModuleCovertOps = PlanetaryModule.create('h00T', 'I000', 'I00C') // covert ops
//set ModuleMissileBattery = PlanetaryModule.create('h00V', 'I003') // hurricane missile battery
set ModuleAutocannonArray = PlanetaryModule.create('h00U', 'I004', 'I00F') // GS autocannon array
set ModuleFusionCore = PlanetaryModule.create('h00W', 'I002', 'I00E') // fusion core
//set ModulePlanetaryShield = PlanetaryModule.create('h00X', 'I001') // planetary shield
//set ModuleSupplyStation = PlanetaryModule.create('h00Z', 'I007') // supply station
set ModuleExportVenture = PlanetaryModule.create('h010', 'I008', 'I00D') // export venture
set ModuleColonialDraftingCenter = PlanetaryModule.create('h011', 'I009', 'I00B') // colonial drafting center
set ModulePlanetaryFactory = PlanetaryModule.create('h014', 'I00A', 'I00G') // planetary factory
set ModuleInstalledSound = CreateSound(ModuleInstalledSoundPath, false, false, false, 10, 10, "")
endfunction
endlibrary
library ResourceDeliveryLib initializer InitResourceDelivery requires MathLib, MapGeneratorLib
globals
private hashtable DeliveryTimers = InitHashtable()
private constant integer MineralsProductionAbility = 'A003'
private constant integer HydrogenProductionAbility = 'A002'
private constant integer HybridProductionAbility = 'A004'
// how often the legacy income should happen
private constant integer IncomeInterval = 4
// income scaled by minute
private constant integer HighMineralsIncome = (15 * 60) / IncomeInterval
private constant integer LowMineralsIncome = (5 * 60) / IncomeInterval
private constant integer HighHydrogenIncome = (6 * 60) / IncomeInterval
private constant integer LowHydrogenIncome = (2 * 60) / IncomeInterval
private constant real OptimalDeliveryDistance = 1500
private constant real OptimalDeliveryDelay = 10 // every 10 seconds
private constant real LowestDeliveryDistance = 6000
private constant real LowestDeliveryDelay = 40 // every 40 seconds
private constant real LowestDeliveryRatio = 0.5 // bad delivery gets worst yield
private constant real SpawnOffset = 200
private constant real ArrivalOffset = 200
private constant integer CargoAbility = 'A01W'
private constant integer DeliveryShipType = 'h00Y'
private constant integer MineralsCargoType = 'I005'
private constant integer HydrogenCargoType = 'I006'
private constant integer ExportVentureModule = 'I008'
private constant integer ExportVentureModule2 = 'I00D'
private unit f_CreateDeliveryShip_output
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct Delivery
private static hashtable ht = InitHashtable()
private unit cargo
private unit target
private timer t
private trigger order
private trigger death
private item minerals
private item hydrogen
private method GetMineralsCargo takes nothing returns integer
local integer amount = GetItemCharges(minerals)
return amount
endmethod
private method GetHydrogenCargo takes nothing returns integer
local integer amount = GetItemCharges(hydrogen)
return amount
endmethod
private method DeliverMinerals takes nothing returns integer
local integer amount = GetMineralsCargo()
if(amount == 0)then
return 0
endif
call SetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_RESOURCE_GOLD, amount + GetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_RESOURCE_GOLD))
call SetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_GOLD_GATHERED, amount + GetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_GOLD_GATHERED))
return amount
endmethod
private method DeliverHydrogen takes nothing returns integer
local integer amount = GetHydrogenCargo()
if(amount == 0)then
return 0
endif
call SetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_RESOURCE_LUMBER, amount + GetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_RESOURCE_LUMBER))
call SetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_LUMBER_GATHERED, amount + GetPlayerState(GetOwningPlayer(this.target), PLAYER_STATE_LUMBER_GATHERED))
return amount
endmethod
private method OnArrival takes nothing returns nothing
// deliver resources
local integer minerals = this.DeliverMinerals()
local integer hydrogen = this.DeliverHydrogen()
call ShowResourceText(GetOwningPlayer(this.target), this.cargo, minerals, hydrogen)
// remove the cargo ship
call RemoveUnit(this.cargo)
// cleanup
call this.destroy()
endmethod
private method Reorder takes nothing returns nothing
call DisableTrigger(this.order)
call IssuePointOrderById(this.cargo, OrderId("smart"), GetUnitX(this.target), GetUnitY(this.target))
call EnableTrigger(this.order)
endmethod
private method TryPlunder takes nothing returns nothing
local player p = GetOwningPlayer(GetKillingUnit())
local integer minerals
local integer hydrogen
if(GetPlayerTechCount(p, PirateLordTech, true) == 0)then
//call DisplayTextToPlayer(Player(0), 0, 0, "no cargo plunder")
set p = null
return // no plunder
endif
set minerals = this.GetMineralsCargo() / 2
set hydrogen = this.GetHydrogenCargo() / 2
//call DisplayTextToPlayer(Player(0), 0, 0, "cargo plunder " + I2S(minerals) + "/" + I2S(hydrogen))
call ShowResourceText(p, this.cargo, minerals, hydrogen)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, minerals + GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD))
call SetPlayerState(p, PLAYER_STATE_GOLD_GATHERED, minerals + GetPlayerState(p, PLAYER_STATE_GOLD_GATHERED))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, hydrogen + GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER))
call SetPlayerState(p, PLAYER_STATE_LUMBER_GATHERED, hydrogen + GetPlayerState(p, PLAYER_STATE_LUMBER_GATHERED))
set p = null
endmethod
private static method OnTimer takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
if(this.cargo == null or UnitAlive(this.cargo) == false)then
call Debug("cargo timer cleanup")
call this.destroy()
endif
// check for arrival
if(DistanceBetweenCoordinates(GetUnitX(this.cargo), GetUnitY(this.cargo), GetUnitX(this.target), GetUnitY(this.target)) <= ArrivalOffset)then
call Debug("cargo arrival")
call this.OnArrival()
endif
endmethod
private static method OnOrder takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call Debug("cargo order")
call this.Reorder()
endmethod
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 2, GetHandleId(GetTriggeringTrigger()))
call TryPlunder()
// cleanup
call Debug("cargo death")
call this.destroy()
endmethod
static method create takes unit cargo, unit target returns thistype
local thistype this = thistype.allocate()
set this.cargo = cargo
set this.target = target
set this.t = CreateTimer()
call SaveInteger(thistype.ht, 0, GetHandleId(this.t), this)
call TimerStart(this.t, 1, true, function thistype.OnTimer)
set this.order = CreateTrigger()
call TriggerRegisterUnitEvent(this.order, this.cargo, EVENT_UNIT_ISSUED_ORDER)
call TriggerRegisterUnitEvent(this.order, this.cargo, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(this.order, this.cargo, EVENT_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddAction(this.order, function thistype.OnOrder)
call SaveInteger(thistype.ht, 1, GetHandleId(this.order), this)
set this.death = CreateTrigger()
call TriggerRegisterUnitEvent(this.death, this.cargo, EVENT_UNIT_DEATH)
call TriggerRegisterUnitEvent(this.death, this.cargo, EVENT_UNIT_DECAY)
call TriggerRegisterUnitEvent(this.death, this.cargo, EVENT_UNIT_DROP_ITEM)
call TriggerAddAction(this.death, function thistype.OnDeath)
call SaveInteger(thistype.ht, 2, GetHandleId(this.death), this)
set this.minerals = GetItemOfTypeFromUnitBJ(this.cargo, MineralsCargoType)
set this.hydrogen = GetItemOfTypeFromUnitBJ(this.cargo, HydrogenCargoType)
call this.Reorder()
call Debug("cargo created: " + GetUnitName(this.cargo) + ">" + GetUnitName(this.target))
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 2, GetHandleId(this.death))
call DestroyTrigger(this.death)
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.order))
call DestroyTrigger(this.order)
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.t))
call DestroyTimer(this.t)
call RemoveItem(this.minerals)
call RemoveItem(this.hydrogen)
set this.death = null
set this.order = null
set this.t = null
set this.cargo = null
set this.target = null
set this.minerals = null
set this.hydrogen = null
call Debug("cargo destroyed")
call this.deallocate()
endmethod
endstruct
private function GetDistanceFactor takes real distance returns real
if(distance <= OptimalDeliveryDistance)then
return (OptimalDeliveryDelay) / 60
elseif(distance >= LowestDeliveryDistance)then
return (LowestDeliveryDelay) / 60
else
return (((distance * LowestDeliveryDelay) / LowestDeliveryDistance)) / 60
endif
endfunction
private function GetDeliveryDelay takes real distance returns real
if(distance <= OptimalDeliveryDistance)then
return OptimalDeliveryDelay
elseif(distance >= LowestDeliveryDistance)then
return LowestDeliveryDelay
else
return distance * LowestDeliveryDelay / LowestDeliveryDistance
endif
endfunction
private function GetDeliveryMinerals takes unit planet, real distance returns integer
local integer amount = 0
if(GetUnitAbilityLevel(planet, MineralsProductionAbility) > 0)then
set amount = HighMineralsIncome // use high income for mineral planets
elseif(GetUnitAbilityLevel(planet, HybridProductionAbility) > 0)then
set amount = LowMineralsIncome // use low income for hybrid planet
else
return 0 // no mineral income
endif
if(UnitHasItemOfTypeBJ(planet, ExportVentureModule))then
set amount = (5 * amount) / 4 // 25%
endif
if(UnitHasItemOfTypeBJ(planet, ExportVentureModule2))then
set amount = (3 * amount) / 2 // 50%
endif
if(GetPlayerTechCount(GetOwningPlayer(planet), IndustrialComplexTech, true) > 0)then
set amount = (5 * amount) / 4 // 25%
endif
if(distance <= OptimalDeliveryDistance)then
return R2I((amount * OptimalDeliveryDelay) / 60)
elseif(distance >= LowestDeliveryDistance)then
return R2I((amount * LowestDeliveryDelay) / 60)
else
return R2I((amount * ((distance * LowestDeliveryDelay) / LowestDeliveryDistance)) / 60)
endif
endfunction
private function GetDeliveryHydrogen takes unit planet, real distance returns integer
local integer amount = 0
if(GetUnitAbilityLevel(planet, HydrogenProductionAbility) > 0)then
set amount = HighHydrogenIncome // use high income for hydrogen planets
elseif(GetUnitAbilityLevel(planet, HybridProductionAbility) > 0)then
set amount = LowHydrogenIncome // use low income for hybrid planet
else
return 0 // no hydrogen income
endif
if(UnitHasItemOfTypeBJ(planet, ExportVentureModule))then
set amount = (5 * amount) / 4 // 25%
endif
if(UnitHasItemOfTypeBJ(planet, ExportVentureModule2))then
set amount = (3 * amount) / 2 // 50%
endif
if(GetPlayerTechCount(GetOwningPlayer(planet), ScientificConglomerateTech, true) > 0)then
set amount = (5 * amount) / 4 // 25%
endif
if(distance <= OptimalDeliveryDistance)then
return R2I((amount * OptimalDeliveryDelay) / 60)
elseif(distance >= LowestDeliveryDistance)then
return R2I((amount * LowestDeliveryDelay) / 60)
else
return R2I((amount * ((distance * LowestDeliveryDelay) / LowestDeliveryDistance)) / 60)
endif
endfunction
private function CreateDeliveryShip takes player p, real x, real y, real facing, integer minerals, integer hydrogen returns unit
local item i
set f_CreateDeliveryShip_output = CreateUnit(p, DeliveryShipType, x, y, facing)
call SetUnitPathing(f_CreateDeliveryShip_output, false)
if(minerals > 0)then
// add minderals
set i = CreateItem(MineralsCargoType, x, y)
call SetItemCharges(i, minerals)
call UnitAddItem(f_CreateDeliveryShip_output, i)
endif
if(hydrogen > 0)then
// add hydrogen
set i = CreateItem(HydrogenCargoType, x, y)
call SetItemCharges(i, hydrogen)
call UnitAddItem(f_CreateDeliveryShip_output, i)
endif
set i = null
return f_CreateDeliveryShip_output
endfunction
private function GetAbilityDescription takes real delay, integer minerals, integer hydrogen returns string
local string output = "Every " + R2S(I2R(R2I(delay * 10))/10.0) + " seconds, this Planet sends a shipment of resources to your Home Planet.\n"
set output = output + "\n"
set output = output + "The shipment will contain:\n"
if(minerals > 0)then
set output = output + " + " + MineralsTextColor + I2S(minerals) + " Minerals|r\n"
endif
if(hydrogen > 0)then
set output = output + " + " + HydrogenTextColor + I2S(hydrogen) + " Hydrogen|r\n"
endif
set output = output + "\n"
set output = output + "|cffffcc00Make sure to protect your Cargo Ships. You will not earn any resources if they are destroyed.|r"
return output
endfunction
private function UpdateTooltip takes unit planet, real delay, integer minerals, integer hydrogen returns nothing
if(GetUnitAbilityLevel(planet, MineralsProductionAbility) > 0)then
call BlzSetAbilityStringLevelField(BlzGetUnitAbility(planet, MineralsProductionAbility), ABILITY_SLF_TOOLTIP_NORMAL_EXTENDED, 0, GetAbilityDescription(delay, minerals, hydrogen))
call BlzUnitDisableAbility(planet, MineralsProductionAbility, true, true)
call PauseUnit(planet, true)
call PauseUnit(planet, false)
call BlzUnitDisableAbility(planet, MineralsProductionAbility, false, false)
elseif(GetUnitAbilityLevel(planet, HydrogenProductionAbility) > 0)then
call BlzSetAbilityStringLevelField(BlzGetUnitAbility(planet, HydrogenProductionAbility), ABILITY_SLF_TOOLTIP_NORMAL_EXTENDED, 0, GetAbilityDescription(delay, minerals, hydrogen))
call BlzUnitDisableAbility(planet, HydrogenProductionAbility, true, true)
call BlzUnitDisableAbility(planet, HydrogenProductionAbility, false, false)
call PauseUnit(planet, true)
call PauseUnit(planet, false)
else
call BlzSetAbilityStringLevelField(BlzGetUnitAbility(planet, HybridProductionAbility), ABILITY_SLF_TOOLTIP_NORMAL_EXTENDED, 0, GetAbilityDescription(delay, minerals, hydrogen))
call BlzUnitDisableAbility(planet, HybridProductionAbility, true, true)
call BlzUnitDisableAbility(planet, HybridProductionAbility, false, false)
call PauseUnit(planet, true)
call PauseUnit(planet, false)
endif
endfunction
private function StartCooldown takes unit planet, real delay returns nothing
if(GetUnitAbilityLevel(planet, MineralsProductionAbility) > 0)then
call BlzStartUnitAbilityCooldown(planet, MineralsProductionAbility, delay)
elseif(GetUnitAbilityLevel(planet, HydrogenProductionAbility) > 0)then
call BlzStartUnitAbilityCooldown(planet, HydrogenProductionAbility, delay)
else
call BlzStartUnitAbilityCooldown(planet, HybridProductionAbility, delay)
endif
endfunction
function SendCargoShipCore takes unit origin, unit target, integer minerals, integer hydrogen returns nothing
local real facing = AngleBetweenCoordinates(GetUnitX(origin), GetUnitY(origin), GetUnitX(target), GetUnitY(target))
local unit cargo = CreateDeliveryShip(GetOwningPlayer(origin), PolarProjectionX(GetUnitX(origin), SpawnOffset, facing), PolarProjectionY(GetUnitY(origin), SpawnOffset, facing), facing, minerals, hydrogen)
call Delivery.create(cargo, target)
set cargo = null
endfunction
private function SendCargoShip takes unit origin returns real
local unit target = PlayerHomePlanets[GetPlayerId(GetOwningPlayer(origin))]
local real distance = DistanceBetweenCoordinates(GetUnitX(origin), GetUnitY(origin), GetUnitX(target), GetUnitY(target))
local real delay = GetDeliveryDelay(distance)
local integer minerals = GetDeliveryMinerals(origin, distance)
local integer hydrogen = GetDeliveryHydrogen(origin, distance)
call SendCargoShipCore(origin, target, minerals, hydrogen)
call UpdateTooltip(origin, delay, minerals, hydrogen)
call StartCooldown(origin, delay)
set target = null
return delay
endfunction
private function TrySendCargoShip takes unit origin returns boolean
local timer t
if(UnitAlive(origin) == false)then
set t = LoadTimerHandle(DeliveryTimers, 1, GetHandleId(origin))
call RemoveSavedHandle(DeliveryTimers, 0, GetHandleId(t))
call RemoveSavedHandle(DeliveryTimers, 1, GetHandleId(origin))
call DestroyTimer(t)
set t = null
return false
endif
if(GetUnitTypeId(origin) == 'n003')then
return false
endif
call SendCargoShip(origin)
return true
endfunction
private function OnDeliveryTimer takes nothing returns nothing
call TrySendCargoShip(LoadUnitHandle(DeliveryTimers, 0, GetHandleId(GetExpiredTimer())))
endfunction
private function StartCargoShipCondition takes nothing returns boolean
return IsUnitType(GetChangingUnit(), UNIT_TYPE_ANCIENT)
endfunction
private function StartCargoShipAction takes nothing returns nothing
local timer t
if(GetChangingUnitPrevOwner() != Player(PLAYER_NEUTRAL_PASSIVE))then
// cleaning-up previous delivery cycle
set t = LoadTimerHandle(DeliveryTimers, 1, GetHandleId(GetChangingUnit()))
call RemoveSavedHandle(DeliveryTimers, 0, GetHandleId(t))
call RemoveSavedHandle(DeliveryTimers, 1, GetHandleId(GetChangingUnit()))
call DestroyTimer(t)
endif
if(GetOwningPlayer(GetChangingUnit()) != Player(PLAYER_NEUTRAL_PASSIVE))then
// setting-up new delivery cycle
set t = CreateTimer()
call TimerStart(t, SendCargoShip(GetChangingUnit()), true, function OnDeliveryTimer)
call SaveUnitHandle(DeliveryTimers, 0, GetHandleId(t), GetChangingUnit())
call SaveTimerHandle(DeliveryTimers, 1, GetHandleId(GetChangingUnit()), t)
endif
set t = null
endfunction
private function InitResourceDelivery takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_CHANGE_OWNER)
call TriggerAddCondition(t, Condition (function StartCargoShipCondition))
call TriggerAddAction(t, function StartCargoShipAction)
set t = null
endfunction
endlibrary
library LightningBounceAbilityLib requires LinkedLightningEffectLib
function interface ITargetFilter takes unit source, unit target returns boolean
function interface IEffectCallback takes unit source, unit target returns nothing
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
struct LightningBoundAbilityInstance
private static hashtable ht = InitHashtable()
private static ITargetFilter m_targetFilter
private static unit m_source
readonly LightningBounceAbility bounceAbility
readonly unit source
readonly unit lastTarget
readonly group targets
private timer bounceTimer
private method Bounce takes unit target, IEffectCallback effectCallback returns nothing
call Debug("Bounce")
call LinkedLightningEffect.create(this.lastTarget, target, this.bounceAbility.lightningCode, this.bounceAbility.lightningDuration, this.bounceAbility.lightningFadeOut)
call effectCallback.execute(this.source, target)
call GroupAddUnit(this.targets, target)
set this.lastTarget = target
if(CountUnitsInGroup(this.targets) == this.bounceAbility.bounceLimit)then
call this.destroy()
else
call TimerStart(this.bounceTimer, this.bounceAbility.bounceDelay, false, function thistype.OnBounce)
endif
endmethod
private static method GetTargetsFilter takes nothing returns boolean
return thistype.m_targetFilter.evaluate(thistype.m_source, GetFilterUnit())
endmethod
private method GetTargets takes group g returns group
set thistype.m_targetFilter = this.bounceAbility.targetFilter
set thistype.m_source = this.source
call GroupEnumUnitsInRange(g, GetUnitX(this.lastTarget), GetUnitY(this.lastTarget), this.bounceAbility.bounceRadius, function thistype.GetTargetsFilter)
call GroupRemoveGroup(this.targets, g)
return g
endmethod
private static method OnBounce takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetExpiredTimer()))
local group newTargets = this.GetTargets(CreateGroup())
local unit newTarget = GroupPickRandomUnit(newTargets)
if(newTarget != null)then
call this.Bounce(newTarget, this.bounceAbility.effectCallback)
else
call this.destroy()
endif
call DestroyGroup(newTargets)
set newTargets = null
set newTarget = null
endmethod
static method create takes LightningBounceAbility bounceAbility, unit source, unit target returns thistype
local thistype this = thistype.allocate()
call Debug("create LightningBoundAbilityInstance")
set this.bounceAbility = bounceAbility
set this.source = source
set this.lastTarget = source
set this.targets = CreateGroup()
set this.bounceTimer = CreateTimer()
call SaveInteger(thistype.ht, 0, GetHandleId(this.bounceTimer), this)
call this.Bounce(target, this.bounceAbility.effectCallback)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.bounceTimer))
call DestroyGroup(this.targets)
call DestroyTimer(this.bounceTimer)
set this.source = null
set this.lastTarget = null
set this.targets = null
set this.bounceTimer = null
endmethod
endstruct
struct LightningBounceAbility
readonly real bounceDelay
readonly real bounceRadius
readonly integer bounceLimit
readonly string lightningCode
readonly real lightningDuration
readonly real lightningFadeOut
readonly ITargetFilter targetFilter
readonly IEffectCallback effectCallback
method StartBounce takes unit source, unit target returns nothing
call Debug("StartBounce")
call LightningBoundAbilityInstance.create(this, source, target)
endmethod
static method create takes real bounceDelay, real bounceRadius, integer bounceLimit, string lightningCode, real lightningDuration, real lightningFadeOut, ITargetFilter targetFilter, IEffectCallback effectCallback returns thistype
local thistype this = thistype.allocate()
call Debug("create LightningBounceAbility")
set this.bounceDelay = bounceDelay
set this.bounceRadius = bounceRadius
set this.bounceLimit = bounceLimit
set this.lightningCode = lightningCode
set this.lightningDuration = lightningDuration
set this.lightningFadeOut = lightningFadeOut
set this.targetFilter = targetFilter
set this.effectCallback = effectCallback
return this
endmethod
endstruct
endlibrary
library LinkedLightningEffectLib
globals
private constant real LightningEffectUpdatePeriod = 0.04
private constant integer LightningEffectUpdateTimer = 0
private constant integer LightningEffectExpirationTimer = 0
endglobals
struct LinkedLightningEffect
private static hashtable ht = InitHashtable()
private unit caster
private unit target
private lightning l
private timer updateTimer
private timer expirationTimer
private real fadePoint
private method GetAlpha takes nothing returns real
local real elapsedTime = TimerGetElapsed(this.expirationTimer)
local real duration = TimerGetTimeout(this.expirationTimer)
if(elapsedTime < this.fadePoint)then
// full strength
return 1.0
endif
// fading out
return 1.0 - (elapsedTime - this.fadePoint) / (duration - this.fadePoint)
endmethod
private method Update takes nothing returns nothing
call MoveLightningEx(l, true, GetUnitX(this.target), GetUnitY(this.target), GetUnitFlyHeight(this.target), GetUnitX(this.caster), GetUnitY(this.caster), GetUnitFlyHeight(this.caster))
call SetLightningColor(l, 1, 1, 1, GetAlpha())
endmethod
static method OnUpdate takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, LightningEffectUpdateTimer, GetHandleId(GetExpiredTimer()))
call this.Update()
endmethod
static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, LightningEffectExpirationTimer, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
method ResetExpirationTimer takes real duration, real fadepoint returns nothing
set this.fadePoint = fadepoint
call TimerStart(this.expirationTimer, duration, false, function thistype.OnExpire)
endmethod
static method create takes unit caster, unit target, string lightningCode, real duration, real fadepoint returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.target = target
set this.l = AddLightningEx(lightningCode, true, GetUnitX(target), GetUnitY(target), GetUnitFlyHeight(target), GetUnitX(caster), GetUnitY(caster), GetUnitFlyHeight(caster))
set this.updateTimer = CreateTimer()
set this.expirationTimer = CreateTimer()
set this.fadePoint = fadepoint
call SaveInteger(thistype.ht, LightningEffectUpdateTimer, GetHandleId(this.updateTimer), this)
call SaveInteger(thistype.ht, LightningEffectExpirationTimer, GetHandleId(this.expirationTimer), this)
call TimerStart(this.updateTimer, LightningEffectUpdatePeriod, true, function thistype.OnUpdate)
call TimerStart(this.expirationTimer, duration, false, function thistype.OnExpire)
call SetLightningColor(this.l, 1, 1, 1, 0)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, LightningEffectUpdateTimer, GetHandleId(this.updateTimer))
call RemoveSavedInteger(thistype.ht, LightningEffectExpirationTimer, GetHandleId(this.expirationTimer))
call DestroyLightning(this.l)
call DestroyTimer(this.updateTimer)
call DestroyTimer(this.expirationTimer)
set this.caster = null
set this.target = null
set this.l = null
set this.updateTimer = null
set this.expirationTimer = null
call this.deallocate()
endmethod
endstruct
endlibrary
library SwarmSystemLib
globals
private constant integer SwarmTimerMapping = 0
private constant integer SwarmSettingsSummonedType = 100
private constant integer SwarmSettingsSummonedCount = 101
private constant integer SwarmSettingsSpawnDelay = 102
private constant integer SwarmSettingsOrderDelay = 103
private constant integer SwarmSettingsOrderIdleOnly = 104
private constant integer SwarmSettingsDuration = 105
private constant integer SwarmSettingsRange = 106
private constant integer Patrol = 851990
private constant integer PatrolAlt = 851991 // ???
private constant integer Stop = 851972
endglobals
struct Swarm
private static hashtable ht = InitHashtable()
private static thistype m_ReorderUnits_swarm
private unit caster
private unit anchor
private integer summonedType
private integer summonedCount
private real spawnDelay
private real orderDelay
private boolean orderIdlesOnly
private real duration
private real range
private group spawnedUnits
private integer spawnedCount
private timer spawnTimer
private timer orderTimer
private timer durationTimer
private method OrderUnit takes unit u returns nothing
local location anchorLocation = GetUnitLoc(this.anchor)
local location l = PolarProjectionBJ(anchorLocation, this.range, GetRandomReal(0, 360))
call IssuePointOrderByIdLoc(u, Patrol, l)
call RemoveLocation(anchorLocation)
call RemoveLocation(l)
set anchorLocation = null
set l = null
endmethod
private method SpawnUnit takes nothing returns nothing
local unit u = CreateUnit(GetOwningPlayer(this.caster), this.summonedType, GetUnitX(this.caster), GetUnitY(this.caster), GetUnitFacing(this.caster))
local location l = GetUnitLoc(this.caster)
call GroupAddUnit(this.spawnedUnits, u)
set this.spawnedCount = this.spawnedCount + 1
call this.OrderUnit(u)
call RemoveLocation(l)
set l = null
if(this.spawnedCount == this.summonedCount)then
call PauseTimer(this.spawnTimer)
endif
endmethod
private static method ReorderUnitsEnum takes nothing returns nothing
local unit u = GetEnumUnit()
local integer currentOrder = GetUnitCurrentOrder(u)
//if(GetUnitCurrentOrder(u) == Patrol or GetUnitCurrentOrder(u) == PatrolAlt or GetUnitCurrentOrder(u) == Stop)then
call m_ReorderUnits_swarm.OrderUnit(u)
//endif
set u = null
endmethod
private method ReorderUnits takes nothing returns nothing
set thistype.m_ReorderUnits_swarm = this
call ForGroup(this.spawnedUnits, function thistype.ReorderUnitsEnum)
endmethod
private static method OnSpawn takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, SwarmTimerMapping, GetHandleId(GetExpiredTimer()))
call this.SpawnUnit()
endmethod
private static method OnReorder takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, SwarmTimerMapping, GetHandleId(GetExpiredTimer()))
call this.ReorderUnits()
endmethod
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, SwarmTimerMapping, GetHandleId(GetExpiredTimer()))
call this.destroy()
endmethod
static method create takes unit caster, unit anchor, integer abilityId returns thistype
local thistype this = thistype.allocate()
set this.caster = caster
set this.anchor = anchor
// load presaved settings
set this.summonedType = LoadInteger(thistype.ht, SwarmSettingsSummonedType, abilityId)
set this.summonedCount = LoadInteger(thistype.ht, SwarmSettingsSummonedCount, abilityId)
set this.spawnDelay = LoadReal(thistype.ht, SwarmSettingsSpawnDelay, abilityId)
set this.orderDelay = LoadReal(thistype.ht, SwarmSettingsOrderDelay, abilityId)
set this.orderIdlesOnly = LoadBoolean(thistype.ht, SwarmSettingsOrderIdleOnly, abilityId)
set this.duration = LoadReal(thistype.ht, SwarmSettingsDuration, abilityId)
set this.range = LoadReal(thistype.ht, SwarmSettingsRange, abilityId)
set this.spawnedUnits = CreateGroup()
set this.spawnedCount = 0
set this.spawnTimer = CreateTimer()
set this.orderTimer = CreateTimer()
set this.durationTimer = CreateTimer()
call SaveInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.spawnTimer), this)
call SaveInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.orderTimer), this)
call SaveInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.durationTimer), this)
call TimerStart(this.spawnTimer, this.spawnDelay, true, function thistype.OnSpawn)
call TimerStart(this.orderTimer, this.orderDelay, true, function thistype.OnReorder)
call TimerStart(this.durationTimer, this.duration, false, function thistype.OnExpire)
return this
endmethod
private static method destroyEnum takes nothing returns nothing
call KillUnit(GetEnumUnit())
endmethod
method destroy takes nothing returns nothing
call ForGroup(this.spawnedUnits, function thistype.destroyEnum)
call DestroyGroup(this.spawnedUnits)
call RemoveSavedInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.spawnTimer))
call RemoveSavedInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.orderTimer))
call RemoveSavedInteger(thistype.ht, SwarmTimerMapping, GetHandleId(this.durationTimer))
call DestroyTimer(this.spawnTimer)
call DestroyTimer(this.orderTimer)
call DestroyTimer(this.durationTimer)
set this.caster = null
set this.spawnedUnits = null
set this.spawnTimer = null
set this.orderTimer = null
set this.durationTimer = null
call this.deallocate()
endmethod
static method DeclareSwarmAbilitySettings takes integer abilityId, integer summonedType, integer summonedCount, real spawnDelay, real orderDelay, boolean orderIdlesOnly, real duration, real range returns nothing
call SaveInteger(thistype.ht, SwarmSettingsSummonedType, abilityId, summonedType)
call SaveInteger(thistype.ht, SwarmSettingsSummonedCount, abilityId, summonedCount)
call SaveReal(thistype.ht, SwarmSettingsSpawnDelay, abilityId, spawnDelay)
call SaveReal(thistype.ht, SwarmSettingsOrderDelay, abilityId, orderDelay)
call SaveBoolean(thistype.ht, SwarmSettingsOrderIdleOnly, abilityId, orderIdlesOnly)
call SaveReal(thistype.ht, SwarmSettingsDuration, abilityId, duration)
call SaveReal(thistype.ht, SwarmSettingsRange, abilityId, range)
endmethod
endstruct
endlibrary
library ManaTimedLifeLib initializer InitManaTimedLife
globals
private constant integer ManaTimedLifeId = 'A02U'
private trigger OnEnterTrigger
endglobals
struct ManaTimedLife
private static hashtable ht = InitHashtable()
unit u
trigger death
trigger expire
private static method OnDeath takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 0, GetHandleId(GetTriggeringTrigger()))
call this.destroy()
endmethod
private static method OnExpire takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, 1, GetHandleId(GetTriggeringTrigger()))
call KillUnit(this.u)
endmethod
static method create takes unit u returns thistype
local thistype this = thistype.allocate()
set this.u = u
set this.death = CreateTrigger()
call SaveInteger(thistype.ht, 0, GetHandleId(this.death), this)
call TriggerRegisterUnitEvent(this.death, u, EVENT_UNIT_DEATH)
call TriggerAddAction(this.death, function thistype.OnDeath)
set this.expire = CreateTrigger()
call SaveInteger(thistype.ht, 1, GetHandleId(this.expire), this)
call TriggerRegisterUnitStateEvent(this.expire, u, UNIT_STATE_MANA, LESS_THAN_OR_EQUAL, 0.1)
call TriggerAddAction(this.expire, function thistype.OnExpire)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, 0, GetHandleId(this.death))
call RemoveSavedInteger(thistype.ht, 1, GetHandleId(this.expire))
call DestroyTrigger(this.death)
call DestroyTrigger(this.expire)
set u = null
set this.death = null
set this.expire = null
call this.deallocate()
endmethod
endstruct
private function OnEnterCondition takes nothing returns boolean
return GetUnitAbilityLevel(GetEnteringUnit(), ManaTimedLifeId) > 0
endfunction
private function OnEnterAction takes nothing returns nothing
call ManaTimedLife.create(GetEnteringUnit())
endfunction
private function InitManaTimedLife takes nothing returns nothing
set OnEnterTrigger = CreateTrigger()
call TriggerRegisterEnterRectSimple(OnEnterTrigger, bj_mapInitialPlayableArea)
call TriggerAddCondition(OnEnterTrigger, Condition(function OnEnterCondition))
call TriggerAddAction(OnEnterTrigger, function OnEnterAction)
endfunction
endlibrary
library EvasionUtils requires DamageDefinitionLib, ShotCallerLib
globals
private constant string EvasionText = "evaded"
private constant integer NegateEvasion = 'B002'
private constant integer Evasion6 = 'B00F'
private constant integer Evasion16 = 'A01O'
private constant integer Evasion20 = 'A01P'
private constant integer Shroud1 = 'B00R'
private constant integer Shroud2 = 'B00S'
private constant integer Shroud3 = 'B00T'
endglobals
function GetUnitEvasion takes unit u returns real
local real evasion = 0
if(GetUnitAbilityLevel(u, NegateEvasion) > 0)then
return 0.0
endif
if(GetUnitAbilityLevel(u, Evasion6) > 0)then
set evasion = evasion + 0.06
endif
if(GetUnitAbilityLevel(u, Evasion16) > 0)then
set evasion = evasion + 0.16
endif
if(GetUnitAbilityLevel(u, Evasion20) > 0)then
set evasion = evasion + 0.20
endif
if(GetUnitAbilityLevel(u, Shroud1) > 0)then
set evasion = evasion + 0.10
endif
if(GetUnitAbilityLevel(u, Shroud2) > 0)then
set evasion = evasion + 0.20
endif
if(GetUnitAbilityLevel(u, Shroud3) > 0)then
set evasion = evasion + 0.30
endif
return evasion
endfunction
function GetRelativeEvasion takes unit attacker, unit target returns real
return GetShotCallerFactor(attacker, GetUnitEvasion(target))
endfunction
function ShowEvasion takes unit u returns nothing
local texttag tt = CreateTextTag()
call SetTextTagPos(tt, GetUnitX(u), GetUnitY(u), GetUnitFlyHeight(u))
call SetTextTagText(tt, EvasionText, TextTagSize2Height(8))
call SetTextTagPermanent(tt, false)
call SetTextTagLifespan(tt, 1)
call SetTextTagFadepoint(tt, 0.7)
call SetTextTagVelocity(tt, 0, TextTagSpeed2Velocity(64))
set tt = null
endfunction
endlibrary
library Evasion requires MissileSystem, EvasionUtils
private function EvasionCondition takes nothing returns boolean
if(udg_DamageEventType == MissileDamageType)then
return false // missile damage evasion is managed in the missile system
endif
if(udg_DamageEventType == BulwarkDamageType)then
return false // redirected Bulwark damage type cannot be evaded
endif
if(udg_DamageEventType == PlanetKillerMissileDamageType or udg_DamageEventAttackT == udg_ATTACK_TYPE_CHAOS)then
return false // planet killer damage can't be evaded
endif
if(udg_IsDamageSpell == true)then
return false // spells can't be evaded
endif
if(udg_DamageEventAOE > 1)then
return false // AOE can't be evaded
endif
// roll for evasion!
return GetRandomReal(0, 1) < GetRelativeEvasion(udg_DamageEventSource, udg_DamageEventTarget)
endfunction
private function EvasionAction takes nothing returns nothing
set udg_DamageEventAmount = 0
call ShowEvasion(udg_DamageEventTarget)
endfunction
function TryApplyEvasion takes nothing returns boolean
if(EvasionCondition())then
call EvasionAction()
return true
endif
return false
endfunction
endlibrary
//===========================================================================
function InitTrig_Evasion takes nothing returns nothing
endfunction
globals
constant integer fGold = 0
constant integer fWood = 4+2
constant integer mGold = 10+5
constant integer mWood = 0
constant integer hGold = 5
constant integer hWood = 2
constant integer hpGold = (10+5)*2
constant integer hpWood = (4+2)*2
constant integer sbGold = 3
constant integer sbWood = 1
constant real IncomePeriod = 4
timer IncomeTimer
//timerdialog IncomeTimerDialog
endglobals
function RunIncomeEnum takes nothing returns nothing
local unit u = GetEnumUnit()
local integer unitType = GetUnitTypeId(u)
local player p = null
local integer goldIncome = 0
local integer woodIncome = 0
if(GetUnitAbilityLevel(u, 'B005') > 0)then
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdl", GetUnitX(u), GetUnitY(u)))
set u = null
return // sabotage prevents income
endif
/*if(unitType == 'n001')then
set goldIncome = mGold
set woodIncome = mWood
elseif(unitType == 'n000')then
set goldIncome = fGold
set woodIncome = fWood
elseif(unitType == 'n002')then
set goldIncome = hGold
set woodIncome = hWood
else*/if(unitType == 'h001')then
set goldIncome = hpGold
set woodIncome = hpWood
call BlzStartUnitAbilityCooldown(u, 'A001', IncomePeriod)
elseif(unitType == 'h002' and GetUnitAbilityLevel(u, 'A010') > 0)then
set goldIncome = sbGold * GetUnitAbilityLevel(u, 'A00C')
set woodIncome = sbWood * GetUnitAbilityLevel(u, 'A00C')
call BlzStartUnitAbilityCooldown(u, 'A00C', IncomePeriod)
else
set u = null
return
endif
set p = GetOwningPlayer(u)
if(GetPlayerTechCount(p, IndustrialComplexTech, true) > 0)then
set goldIncome = (5 * goldIncome) / 4
endif
if(GetPlayerTechCount(p, ScientificConglomerateTech, true) > 0)then
set woodIncome = (5 * woodIncome) / 4
endif
call ShowResourceText(p, u, goldIncome, woodIncome)
call AdjustPlayerStateBJ(goldIncome, p, PLAYER_STATE_RESOURCE_GOLD)
call AdjustPlayerStateBJ(woodIncome, p, PLAYER_STATE_RESOURCE_LUMBER)
set u = null
set p = null
endfunction
function RunIncome takes nothing returns nothing
//local group magma = CreateGroup()
//local group frozen = CreateGroup()
//local group hospitable = CreateGroup()
local group home = CreateGroup()
local group builder = CreateGroup()
//call GroupEnumUnitsOfType(magma, "custom_n001", null)
//call GroupEnumUnitsOfType(frozen, "custom_n000", null)
//call GroupEnumUnitsOfType(hospitable, "custom_n002", null)
call GroupEnumUnitsOfType(home, UnitId2String('h001'), null)
call GroupEnumUnitsOfType(builder, UnitId2String('h002'), null)
//call ForGroup(magma, function RunIncomeEnum)
//call ForGroup(frozen, function RunIncomeEnum)
//call ForGroup(hospitable, function RunIncomeEnum)
call ForGroup(home, function RunIncomeEnum)
call ForGroup(builder, function RunIncomeEnum)
//call DisplayTextToPlayer(Player(0), 0, 0, UnitId2String('h001'))
//call DisplayTextToPlayer(Player(0), 0, 0, UnitId2String('h002'))
//call DestroyGroup(magma)
//call DestroyGroup(frozen)
//call DestroyGroup(hospitable)
call DestroyGroup(home)
call DestroyGroup(builder)
//set magma = null
//set frozen = null
//set hospitable = null
set home = null
set builder = null
endfunction
function Trig_PeriodicIncome_Actions takes nothing returns nothing
set IncomeTimer = CreateTimer()
//set IncomeTimerDialog = CreateTimerDialog(IncomeTimer)
call TimerStart(IncomeTimer, IncomePeriod, true, function RunIncome)
//call TimerDialogSetTitle(IncomeTimerDialog, "Income")
//call TimerDialogDisplay(IncomeTimerDialog, true)
endfunction
//===========================================================================
function InitTrig_PeriodicIncome takes nothing returns nothing
set gg_trg_PeriodicIncome = CreateTrigger()
call TriggerRegisterTimerEvent(gg_trg_PeriodicIncome, 0, false)
call TriggerAddAction(gg_trg_PeriodicIncome, function Trig_PeriodicIncome_Actions)
endfunction
globals
real MS_THRESHOLD_SLOW = 250
real MS_THRESHOLD_FAST = 450
group COMMANDBUCKET_SLOW = CreateGroup()
group COMMANDBUCKET_AVG = CreateGroup()
group COMMANDBUCKET_FAST = CreateGroup()
integer SB_ATTACK_ARMY = 'A00X'
integer SB_MOVE_ARMY = 'A00W'
integer array unitCounter
endglobals
function Trig_Spellbringer_Army_Commands_Conditions takes nothing returns boolean
return GetSpellAbilityId() == SB_ATTACK_ARMY or GetSpellAbilityId() == SB_MOVE_ARMY
endfunction
function Trig_Spellbringer_Army_Commands_Filter takes nothing returns boolean
return IsArmyUnit(GetFilterUnit())
endfunction
function Trig_Spellbringer_Army_Commands_ExecOrder takes group commandGroup, string order, integer index returns nothing
if (GetSpellTargetUnit() != null) then
call GroupTargetOrder(commandGroup, order, GetSpellTargetUnit())
else
call GroupPointOrder(commandGroup, order, GetSpellTargetX(), GetSpellTargetY())
endif
call GroupClear(commandGroup)
set unitCounter[index] = 0
endfunction
function Trig_Spellbringer_Army_Commands_Actions takes nothing returns nothing
local group armyUnits = GetUnitsOfPlayerMatching(GetOwningPlayer(GetSpellAbilityUnit()), Condition(function Trig_Spellbringer_Army_Commands_Filter))
local group commandUnits = null
local string order = null
local real ms = 0.0
local integer counterIndex = 0
local unit pickedUnit = null
set unitCounter[0] = 0
set unitCounter[1] = 0
set unitCounter[2] = 0
call GroupClear(COMMANDBUCKET_SLOW)
call GroupClear(COMMANDBUCKET_AVG)
call GroupClear(COMMANDBUCKET_FAST)
if (GetSpellAbilityId() == SB_ATTACK_ARMY) then
set order = "attack"
elseif (GetSpellTargetUnit() != null) then
set order = "patrol"
else
set order = "smart"
endif
loop
set pickedUnit = FirstOfGroup(armyUnits)
exitwhen pickedUnit == null
call GroupRemoveUnit(armyUnits, pickedUnit)
set ms = GetUnitMoveSpeed(pickedUnit)
if (ms <= MS_THRESHOLD_SLOW) then
set commandUnits = COMMANDBUCKET_SLOW
set counterIndex = 0
elseif (ms <= MS_THRESHOLD_FAST) then
set commandUnits = COMMANDBUCKET_AVG
set counterIndex = 1
else
set commandUnits = COMMANDBUCKET_FAST
set counterIndex = 2
endif
call GroupAddUnit(commandUnits, pickedUnit)
set unitCounter[counterIndex] = unitCounter[counterIndex] + 1
if (unitCounter[counterIndex] >= 12) then
call Trig_Spellbringer_Army_Commands_ExecOrder(commandUnits, order, counterIndex)
endif
endloop
if (unitCounter[0] > 0) then
call Trig_Spellbringer_Army_Commands_ExecOrder(COMMANDBUCKET_SLOW, order, 0)
endif
if (unitCounter[1] > 0) then
call Trig_Spellbringer_Army_Commands_ExecOrder(COMMANDBUCKET_AVG, order, 1)
endif
if (unitCounter[2] > 0) then
call Trig_Spellbringer_Army_Commands_ExecOrder(COMMANDBUCKET_FAST, order, 2)
endif
call DestroyGroup(armyUnits)
endfunction
//===========================================================================
function InitTrig_Spellbringer_Army_Commands takes nothing returns nothing
set gg_trg_Spellbringer_Army_Commands = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spellbringer_Army_Commands, EVENT_PLAYER_UNIT_SPELL_CAST )
call TriggerAddCondition( gg_trg_Spellbringer_Army_Commands, Condition( function Trig_Spellbringer_Army_Commands_Conditions ) )
call TriggerAddAction( gg_trg_Spellbringer_Army_Commands, function Trig_Spellbringer_Army_Commands_Actions )
endfunction
library PlanetUncapLib initializer InitPlanetUncap
globals
private trigger InitTrigger
private trigger UncapTrigger
private constant real DefaultUncapFactor = 0.6
private constant real Improved1UncapFactor = 0.4
private constant real Improved2UncapFactor = 0.2
private constant integer ImproveUncapItemId1 = 'I009'
private constant integer ImproveUncapItemId2 = 'I00B'
private constant string PlanetLostSoundPath = "Advisor\\PlanetLost1.wav"
private sound PlanetLostSound
endglobals
private function InitCondition takes nothing returns boolean
local unit u = GetEnteringUnit()
local boolean planet = (GetUnitAbilityLevel(u, 'A002') + GetUnitAbilityLevel(u, 'A003') + GetUnitAbilityLevel(u, 'A004') + GetUnitAbilityLevel(u, 'A00D')) > 0
set u = null
return planet
endfunction
private function InitAction takes nothing returns nothing
local unit u = GetEnteringUnit()
call TriggerRegisterUnitStateEvent(UncapTrigger, u, UNIT_STATE_LIFE, LESS_THAN, GetUnitState(u, UNIT_STATE_MAX_LIFE) * DefaultUncapFactor)
call TriggerRegisterUnitStateEvent(UncapTrigger, u, UNIT_STATE_LIFE, LESS_THAN, GetUnitState(u, UNIT_STATE_MAX_LIFE) * Improved1UncapFactor)
call TriggerRegisterUnitStateEvent(UncapTrigger, u, UNIT_STATE_LIFE, LESS_THAN, GetUnitState(u, UNIT_STATE_MAX_LIFE) * Improved2UncapFactor)
set u = null
endfunction
private function UncapAction takes nothing returns nothing
local unit u = GetTriggerUnit()
local real uncapFactor = DefaultUncapFactor
if(UnitHasItemOfTypeBJ(u, ImproveUncapItemId1))then
set uncapFactor = Improved1UncapFactor
elseif(UnitHasItemOfTypeBJ(u, ImproveUncapItemId2))then
set uncapFactor = Improved2UncapFactor
endif
if(GetUnitState(u, UNIT_STATE_LIFE) < GetUnitState(u, UNIT_STATE_MAX_LIFE) * uncapFactor)then
call RemoveItem(UnitItemInSlot(u, 0))
call RemoveItem(UnitItemInSlot(u, 1))
call RemoveItem(UnitItemInSlot(u, 2))
call RemoveItem(UnitItemInSlot(u, 3))
call RemoveItem(UnitItemInSlot(u, 4))
call RemoveItem(UnitItemInSlot(u, 5))
call SetUnitOwner(u, Player(PLAYER_NEUTRAL_PASSIVE), true)
return
endif
set u = null
endfunction
private function InitPlanetUncap takes nothing returns nothing
set InitTrigger = CreateTrigger()
call TriggerRegisterEnterRectSimple(InitTrigger, GetEntireMapRect())
call TriggerAddCondition(InitTrigger, Condition(function InitCondition))
call TriggerAddAction(InitTrigger, function InitAction)
set UncapTrigger = CreateTrigger()
call TriggerAddAction(UncapTrigger, function UncapAction)
set PlanetLostSound = CreateSound(PlanetLostSoundPath, false, false, false, 10, 10, "")
endfunction
endlibrary
function Trig_PlanetDestroyed_Conditions takes nothing returns boolean
local unit u = GetDyingUnit()
local boolean planet = (GetUnitAbilityLevel(u, 'A002') + GetUnitAbilityLevel(u, 'A003') + GetUnitAbilityLevel(u, 'A004')) > 0
set u = null
return planet
endfunction
function Trig_PlanetDestroyed_Actions takes nothing returns nothing
local location loc = GetUnitLoc(GetDyingUnit())
local unit u = GetDyingUnit()
call DisplayTextToPlayer(GetOwningPlayer(u), 0, 0, "|cffff0000You lost a " + GetUnitName(u) + "!|r")
call PingMinimapForPlayer(GetOwningPlayer(u), GetUnitX(u), GetUnitY(u), 2)
call RemoveUnit(u)
set u = CreateUnitAtLoc(Player(PLAYER_NEUTRAL_PASSIVE), 'n003', loc, 270)
call UnitAddAbility(u, 'Ane2')
call RemoveLocation(loc)
set loc = null
set u = null
endfunction
//===========================================================================
function InitTrig_PlanetDestroyed takes nothing returns nothing
set gg_trg_PlanetDestroyed = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_PlanetDestroyed, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_PlanetDestroyed, Condition( function Trig_PlanetDestroyed_Conditions ) )
call TriggerAddAction( gg_trg_PlanetDestroyed, function Trig_PlanetDestroyed_Actions )
endfunction
library Tips initializer InitTips requires Core
globals
string TipTitle = "|cffccccffTUTORIAL|r\n"
string Minerals = "|c00808080Minerals|r"
string Hydrogen = "|c000080FFHydrogen|r"
string FleetLimit = "|c00FF8080Fleet Limit|r"
integer TipTriggerMapping = 0
endglobals
function interface SetupTipTrigger takes nothing returns trigger
struct TipMessage
private static hashtable ht = InitHashtable()
private trigger t
private force f
private integer playerCount
private string message
method DisplayForPlayer takes player p returns nothing
if(p == null)then
call DisplayTextToForce(this.f, TipTitle + this.message)
call DisplayTextToForce(this.f, " ")
call StartSound(bj_questHintSound)
call ForceClear(this.f)
set playerCount = 0
return
endif
if(IsPlayerInForce(p, this.f))then
call DisplayTextToPlayer(p, 0, 0, TipTitle + this.message)
call DisplayTextToPlayer(p, 0, 0, " ")
call StartSoundForPlayerBJ(p, bj_questHintSound)
call ForceRemovePlayer(this.f, p)
set playerCount = playerCount - 1
return
endif
endmethod
static method FindTriggerPlayer takes nothing returns player
if(GetTriggerPlayer() != null)then
return GetTriggerPlayer()
endif
if(GetTrainedUnit() != null)then
return GetOwningPlayer(GetTrainedUnit())
endif
if(GetConstructedStructure() != null)then
return GetOwningPlayer(GetConstructedStructure())
endif
if(GetConstructingStructure() != null)then
return GetOwningPlayer(GetConstructingStructure())
endif
if(GetTriggerUnit() != null)then
return GetOwningPlayer(GetTriggerUnit())
endif
return null
endmethod
static method Display takes nothing returns nothing
local thistype this = LoadInteger(thistype.ht, TipTriggerMapping, GetHandleId(GetTriggeringTrigger()))
local player p = thistype.FindTriggerPlayer()
call this.DisplayForPlayer(p)
if(this.playerCount == 0)then
call this.destroy()
endif
set p = null
endmethod
static method create takes string message, SetupTipTrigger triggerSetupCallback returns thistype
local thistype this = thistype.allocate()
local integer i = 0
set this.t = triggerSetupCallback.evaluate()
set this.f = CreateForce()
set this.playerCount = 0
set this.message = message
loop
call ForceAddPlayer(this.f, Player(i))
set this.playerCount = this.playerCount + 1
set i = i + 1
exitwhen i == bj_MAX_PLAYERS
endloop
call TriggerAddAction(this.t, function thistype.Display)
call SaveInteger(thistype.ht, TipTriggerMapping, GetHandleId(this.t), this)
return this
endmethod
method destroy takes nothing returns nothing
call RemoveSavedInteger(thistype.ht, TipTriggerMapping, GetHandleId(this.t))
call DestroyTrigger(this.t)
call DestroyForce(this.f)
set this.t = null
set this.f = null
set this.message = null
call this.deallocate()
endmethod
endstruct
// game time 10 seconds
private function SetupTip00 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterTimerEvent(output, 10, false)
return output
endfunction
// game time 60 seconds
private function SetupTip0 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterTimerEvent(output, 60, false)
return output
endfunction
// selected space builder
private function SetupTip1Condition takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h001' and GetOwningPlayer(GetTriggerUnit()) == GetTriggerPlayer()
endfunction
private function SetupTip1 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_SELECTED)
call TriggerAddCondition(output, Condition(function SetupTip1Condition))
return output
endfunction
// selected home planet
private function SetupTip2Condition takes nothing returns boolean
return GetUnitTypeId(GetTriggerUnit()) == 'h002' and GetOwningPlayer(GetTriggerUnit()) == GetTriggerPlayer()
endfunction
private function SetupTip2 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_SELECTED)
call TriggerAddCondition(output, Condition(function SetupTip2Condition))
return output
endfunction
// built start
private function SetupTip3 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_START)
return output
endfunction
// built observatory
private function SetupTip4Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00N'
endfunction
private function SetupTip4 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip4Condition))
return output
endfunction
// built starport
private function SetupTip5Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h000'
endfunction
private function SetupTip5 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip5Condition))
return output
endfunction
// trained colonizer
private function SetupTip6Condition takes nothing returns boolean
return GetTrainedUnitType() == 'h003'
endfunction
private function SetupTip6 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_TRAIN_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip6Condition))
return output
endfunction
// trained probe
private function SetupTip7Condition takes nothing returns boolean
return GetTrainedUnitType() == 'h004'
endfunction
private function SetupTip7 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_TRAIN_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip7Condition))
return output
endfunction
// clonized planet
private function SetupTip8Condition takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
private function SetupTip8 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(output, Condition(function SetupTip8Condition))
return output
endfunction
// automated energy canon
private function SetupTip9Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00F'
endfunction
private function SetupTip9 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip9Condition))
return output
endfunction
// built research center
private function SetupTip10Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h009'
endfunction
private function SetupTip10 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip10Condition))
return output
endfunction
// built assembling facility
private function SetupTip11Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00A'
endfunction
private function SetupTip11 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip11Condition))
return output
endfunction
// built refinery
private function SetupTip12Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00L'
endfunction
private function SetupTip12 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip12Condition))
return output
endfunction
// built habitation bubble
private function SetupTip13Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00B'
endfunction
private function SetupTip13 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip13Condition))
return output
endfunction
// built molecular synthsizer
private function SetupTip14Condition takes nothing returns boolean
return GetUnitTypeId(GetConstructedStructure()) == 'h00C'
endfunction
private function SetupTip14 takes nothing returns trigger
local trigger output = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(output, EVENT_PLAYER_UNIT_CONSTRUCT_FINISH)
call TriggerAddCondition(output, Condition(function SetupTip14Condition))
return output
endfunction
private function InitTips takes nothing returns nothing
call TipMessage.create("|cffffcc00Space Workers|r can be assigned to any Planet (right-click) to generate extra resources.", SetupTip00)
call TipMessage.create("Alliance settings (|cffffcc00(F11) Allies|r) are unlocked, it is recommended to engage in |cffffcc00Diplomacy|r!", SetupTip0)
call TipMessage.create("Your |cffffcc00Home Planet|r generates resources periodically, creates basic ships, and gives global Fleet commands to all your military ships.\r|cffff0000You will be defeated if your home Planet is destroyed.|r", SetupTip1)
call TipMessage.create("Use your initial |cffffcc00Space Builder|r to create a |cffffcc00Starport|r and an |cffffcc00Observatory|r, unlocking the |cffffcc00Colonizer|r and the |cffffcc00Probe|r.", SetupTip2)
call TipMessage.create("Structures will complete automatically, but you can powerbuild (|cffffcc00Space Builder: Repair|r) to speed-up the building process.", SetupTip3)
call TipMessage.create("The |cffffcc00Observatory|r helps you find your initial |cffffcc00Planets|r and allows you to create |cffffcc00Probes|r from any |cffffcc00Planet|r.", SetupTip4)
call TipMessage.create("The |cffffcc00Starport|r produces all ships with |cffffcc00Plating Armor|r, and allows you to create |cffffcc00Colonizer|r from any |cffffcc00Planet|r.", SetupTip5)
call TipMessage.create("The |cffffcc00Colonizer|r allows you to claim (|cffffcc00Colonize|r) additional |cffffcc00Planets|r, increasing your " + Minerals + " and " + Hydrogen + " income, as well as your " + FleetLimit + ".", SetupTip6)
call TipMessage.create("The |cffffcc00Probe|r is a slow scout with a very large vision range. It is vital to help you detect enemy fleets, structures, and planets.", SetupTip7)
call TipMessage.create("Different |cffffcc00Planets|r give different resources priodically. Later, you will be able to |cffffcc00Terraform|r planets to adjust the resources they yield.", SetupTip8)
call TipMessage.create("|cffffcc00Automated Energy Cannons|r are very effective at defending early aggression.", SetupTip9)
call TipMessage.create("The |cffffcc00Research Station|r develops new technologies, unlocking more ships, buildings, and abilities.", SetupTip10)
call TipMessage.create("The |cffffcc00Assembling Facility|r produces special ships with |cffffcc00Repulsive Armor|r and |cffffcc00Adaptive Armor|r.", SetupTip11)
call TipMessage.create("The |cffffcc00Refinery|r allows you to create |cffffcc00Haversters|r that can gather " + Minerals + " from |cffffcc00Atseroids|r and " + Hydrogen + " from |cffffcc00Stars|r.", SetupTip12)
call TipMessage.create("The |cffffcc00Habitation Bubble|r greatly increases your " + FleetLimit + ", allowing you to |cffffcc00Terraform|r your |cffffcc00Hospitable Planets|r into more useful |cffffcc00Magma Planets|r or |cffffcc00Frozen Planets|r.", SetupTip13)
call TipMessage.create("The |cffffcc00Molecular Synthesizer|r can convert your excess " + Minerals + " into " + Hydrogen + " and vice-versa. It also allows you to |cffffcc00Terraform Planets|r to adjust your periodic income.", SetupTip14)
endfunction
endlibrary
//===========================================================================
function InitTrig_Tips takes nothing returns nothing
endfunction
library AiUtilsLib
globals
private constant integer CMD_GATHER_X = 0
private constant integer CMD_GATHER_Y = 1
private constant integer CMD_GATHER_COMMIT = 2
private constant integer CMD_COMPETITIVE = 3
endglobals
function AiSetGatherPoint takes player p, real x, real y returns nothing
call CommandAI(p, CMD_GATHER_X, R2I(x))
call CommandAI(p, CMD_GATHER_Y, R2I(y))
call CommandAI(p, CMD_GATHER_COMMIT, 0)
endfunction
function AiCompetitive takes player p, boolean competitive returns nothing
if(competitive)then
call CommandAI(p, CMD_COMPETITIVE, 0)
endif
endfunction
endlibrary
function Trig_AiSurrender_Conditions takes nothing returns boolean
if(GetPlayerSlotState(GetOwningPlayer(GetDyingUnit())) == PLAYER_SLOT_STATE_LEFT)then
return false
endif
return IsUnitType(GetDyingUnit(), UNIT_TYPE_STRUCTURE) and IsUnitType(GetDyingUnit(), UNIT_TYPE_ANCIENT) == false and GetPlayerController(GetOwningPlayer(GetDyingUnit())) == MAP_CONTROL_COMPUTER
endfunction
function Trig_AiSurrender_Func001Func002001001002 takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and IsUnitType(GetFilterUnit(), UNIT_TYPE_STRUCTURE) and IsUnitType(GetFilterUnit(), UNIT_TYPE_ANCIENT) == false
endfunction
function Trig_AiSurrender_Actions takes nothing returns nothing
local player p = GetOwningPlayer(GetDyingUnit())
local group aliveBuildings = GetUnitsOfPlayerMatching(p, Condition(function Trig_AiSurrender_Func001Func002001001002))
local integer count = CountUnitsInGroup(aliveBuildings)
if(count == 0)then
call PlayerChatAll(p, "gg")
call TriggerSleepAction(2)
call KillUnit(PlayerHomePlanets[GetPlayerId(p)])
endif
call DestroyGroup(aliveBuildings)
set p = null
set aliveBuildings = null
endfunction
//===========================================================================
function InitTrig_AutoSurrender takes nothing returns nothing
set gg_trg_AutoSurrender = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_AutoSurrender, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_AutoSurrender, Condition(function Trig_AiSurrender_Conditions))
call TriggerAddAction(gg_trg_AutoSurrender, function Trig_AiSurrender_Actions)
endfunction
library AutoExtractorLib initializer InitAutoExtractor requires AiUtilsLib, MathLib
globals
private constant integer Extractor = 'h00L'
private constant integer HarvestingBuffId = 'B00G'
private constant integer AsteroidSmall = 'n004'
private constant integer AsteroidMedium = 'n005'
private constant integer AsteroidLarge = 'n006'
private constant integer GasCloud = 'n008'
private player g_p
private unit g_HomePlanet
private group ResourceNodes = null
private unit array ResourceNodesArray
private real array ResourceNodeDistancesArray
private integer ResourceNodesCount
private unit array ExtractorInstance
private unit array ExtractorTarget
endglobals
private function Debug takes string s returns nothing
//call DisplayTextToPlayer(Player(0), 0, 0, s)
endfunction
private function SortResourceNodes takes integer start, integer end returns nothing
local integer pivotIndex = (start + end) / 2
local real pivot = ResourceNodeDistancesArray[pivotIndex]
local integer iS = start
local integer iE = end
local real tempI
local unit tempU
if(start >= end)then
return // end recursion
endif
loop
exitwhen iS > iE
if((ResourceNodeDistancesArray[iS] > pivot and ResourceNodeDistancesArray[iE] <= pivot) or (ResourceNodeDistancesArray[iE] < pivot and ResourceNodeDistancesArray[iS] >= pivot))then
set tempI = ResourceNodeDistancesArray[iS]
set ResourceNodeDistancesArray[iS] = ResourceNodeDistancesArray[iE]
set ResourceNodeDistancesArray[iE] = tempI
set tempU = ResourceNodesArray[iS]
set ResourceNodesArray[iS] = ResourceNodesArray[iE]
set ResourceNodesArray[iE] = tempU
set tempU = null
endif
if(ResourceNodeDistancesArray[iS] <= pivot and iS < end)then
set iS = iS + 1
endif
if(ResourceNodeDistancesArray[iE] >= pivot and iE > start)then
set iE = iE - 1
endif
endloop
if(start == iS and end == iE)then
return // end recursion
endif
call SortResourceNodes(start, iE)
call SortResourceNodes(iS, end)
endfunction
private function FilterExtractor takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and GetOwningPlayer(GetFilterUnit()) == g_p
endfunction
private function FilterResource takes nothing returns boolean
return UnitAlive(GetFilterUnit()) and GetUnitAbilityLevel(GetFilterUnit(), HarvestingBuffId) == 0
endfunction
private function AddPlayerExtractors takes group g returns nothing
local group g2 = CreateGroup()
call GroupEnumUnitsOfType(g2, UnitId2String(Extractor), Condition(function FilterExtractor))
call GroupAddGroup(g2, g)
call DestroyGroup(g2)
set g2 = null
endfunction
private function RefreshExtractor takes nothing returns nothing
local group g
if(ExtractorInstance[GetPlayerId(g_p)] != null and UnitAlive(ExtractorInstance[GetPlayerId(g_p)]))then
return // current Extractor instance is valid
endif
// try to find new extractor instance
set g = CreateGroup()
call AddPlayerExtractors(g)
set ExtractorInstance[GetPlayerId(g_p)] = FirstOfGroup(g)
call DestroyGroup(g)
set g = null
endfunction
private function AddAsteroids takes group g returns nothing
local group g2 = CreateGroup()
call GroupEnumUnitsOfType(g2, UnitId2String(AsteroidSmall), Condition(function FilterResource))
call GroupAddGroup(g2, g)
call GroupClear(g2)
call GroupEnumUnitsOfType(g2, UnitId2String(AsteroidMedium), Condition(function FilterResource))
call GroupAddGroup(g2, g)
call GroupClear(g2)
call GroupEnumUnitsOfType(g2, UnitId2String(AsteroidLarge), Condition(function FilterResource))
call GroupAddGroup(g2, g)
call DestroyGroup(g2)
set g2 = null
endfunction
private function AddGasClouds takes group g returns nothing
local group g2 = CreateGroup()
call GroupEnumUnitsOfType(g2, UnitId2String(GasCloud), Condition(function FilterResource))
call GroupAddGroup(g2, g)
call DestroyGroup(g2)
set g2 = null
endfunction
private function ResourceNodesToArrayEnum takes nothing returns nothing
set ResourceNodesArray[ResourceNodesCount] = GetEnumUnit()
set ResourceNodeDistancesArray[ResourceNodesCount] = DistanceBetweenCoordinates(GetUnitX(GetEnumUnit()), GetUnitY(GetEnumUnit()), GetUnitX(g_HomePlanet), GetUnitY(g_HomePlanet))
set ResourceNodesCount = ResourceNodesCount + 1
endfunction
private function ResourceNodesToArray takes nothing returns nothing
set ResourceNodesCount = 0
call ForGroup(ResourceNodes, function ResourceNodesToArrayEnum)
call SortResourceNodes(0, ResourceNodesCount - 1)
endfunction
private function CheckExtractorStatus takes unit extractor, unit target returns boolean
if(target == null or UnitAlive(target) == false)then
call Debug("no target " + I2S(GetPlayerId(g_p)))
return false
endif
if(GetUnitCurrentOrder(extractor) != OrderId("magicleash"))then
call Debug("not harvesting " + I2S(GetPlayerId(g_p)))
return false
endif
return true
endfunction
private function SelectExtractorTarget takes unit extractor returns unit
local integer i = 0
loop
exitwhen i == ResourceNodesCount
if(IssueTargetOrderById(extractor, OrderId("magicleash"), ResourceNodesArray[i]))then
call AiSetGatherPoint(g_p, GetUnitX(ResourceNodesArray[i]), GetUnitY(ResourceNodesArray[i]))
return ResourceNodesArray[i]
else
call AiSetGatherPoint(g_p, GetUnitX(ResourceNodesArray[i]), GetUnitY(ResourceNodesArray[i]))
call IssuePointOrderById(extractor, OrderId("smart"), GetUnitX(ResourceNodesArray[i]), GetUnitY(ResourceNodesArray[i]))
call BlzQueueTargetOrderById(extractor, OrderId("magicleash"), ResourceNodesArray[i])
return ResourceNodesArray[i]
endif
set i = i + 1
endloop
call Debug("no extractor target found " + I2S(GetPlayerId(g_p)))
call AiSetGatherPoint(g_p, GetUnitX(g_HomePlanet), GetUnitY(g_HomePlanet))
return null
endfunction
private function AssignExtractor takes player p returns nothing
set g_p = p
set g_HomePlanet = PlayerHomePlanets[GetPlayerId(g_p)]
call RefreshExtractor()
if(ExtractorInstance[GetPlayerId(g_p)] == null)then
call Debug("no extractors, abort " + I2S(GetPlayerId(g_p)))
call AiSetGatherPoint(g_p, GetUnitX(g_HomePlanet), GetUnitY(g_HomePlanet))
return // no extractors, abort
endif
if(CheckExtractorStatus(ExtractorInstance[GetPlayerId(p)], ExtractorTarget[GetPlayerId(g_p)]))then
call Debug("already harvesting properly, abort " + I2S(GetPlayerId(g_p)))
return // already harvesting properly, abort
endif
call Debug("looking for new target " + I2S(GetPlayerId(g_p)))
if(ResourceNodes == null)then
set ResourceNodes = CreateGroup()
endif
call GroupClear(ResourceNodes)
call AddAsteroids(ResourceNodes)
//call AddGasClouds(ResourceNodes)
call ResourceNodesToArray()
if(ResourceNodesCount == 0)then
call Debug("no targets for extractors, abort " + I2S(GetPlayerId(g_p)))
call AiSetGatherPoint(g_p, GetUnitX(g_HomePlanet), GetUnitY(g_HomePlanet))
return // no targets for extractors, abort
endif
set ExtractorTarget[GetPlayerId(g_p)] = SelectExtractorTarget(ExtractorInstance[GetPlayerId(g_p)])
endfunction
private function OnTimer takes nothing returns nothing
local integer n = 0
loop
exitwhen n >= bj_MAX_PLAYERS
if(GetPlayerSlotState(Player(n)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(n)) == MAP_CONTROL_COMPUTER)then
call Debug("extractor " + I2S(n))
call AssignExtractor(Player(n))
endif
set n = n + 1
endloop
endfunction
private function InitAutoExtractor takes nothing returns nothing
local timer t = CreateTimer()
call TimerStart(t, 2, true, function OnTimer)
endfunction
endlibrary
globals
real g_x_GroupGetClosestToPoint
real g_y_GroupGetClosestToPoint
unit g_closest_GroupGetClosestToPoint
real g_distance_GroupGetClosestToPoint
unit g_output_TryColonizeWith
group g_output_GetPlanetsAroundUnit
group array g_PlayerColonizerGroups
group array g_PlayerClaimTargetGroups
trigger g_OnTrainedColonizer = CreateTrigger()
trigger g_OnCycleColonizer = CreateTrigger()
trigger g_OnColonized = CreateTrigger()
constant integer ColonizeSpellId = 'A02Z'
constant integer ColonizeBuffId = 'B00W'
constant string ColonizeOrderId = "magicleash"
endglobals
function GroupGetClosestUnitEnum takes nothing returns nothing
local unit u = GetEnumUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real dx = x - g_x_GroupGetClosestToPoint
local real dy = y - g_y_GroupGetClosestToPoint
local real distance = SquareRoot(dx * dx + dy * dy)
if(GetUnitTypeId(u) == 'n000')then
set distance = distance + 200
endif
if(GetUnitTypeId(u) == 'n001')then
set distance = distance - 600
endif
if(GetUnitTypeId(u) == 'n002')then
set distance = distance - 200
endif
if(GetUnitTypeId(u) == 'n003')then
set distance = distance + 600
endif
if(g_closest_GroupGetClosestToPoint == null or distance < g_distance_GroupGetClosestToPoint)then
set g_closest_GroupGetClosestToPoint = u
set g_distance_GroupGetClosestToPoint = distance
endif
set u = null
endfunction
function GroupGetClosestUnit takes group g, real x, real y returns unit
set g_x_GroupGetClosestToPoint = x
set g_y_GroupGetClosestToPoint = y
set g_closest_GroupGetClosestToPoint = null
set g_distance_GroupGetClosestToPoint = -1
call ForGroup(g, function GroupGetClosestUnitEnum)
return g_closest_GroupGetClosestToPoint
endfunction
function GetPlanetsAroundUnitFilter takes nothing returns boolean
local unit u = GetFilterUnit()
local boolean neutral = (GetOwningPlayer(u) == Player(PLAYER_NEUTRAL_PASSIVE))
local boolean planet = (GetUnitAbilityLevel(u, 'A002') + GetUnitAbilityLevel(u, 'A003') + GetUnitAbilityLevel(u, 'A004') + GetUnitAbilityLevel(u, 'A00D')) > 0
local boolean notColonizing = GetUnitAbilityLevel(u, ColonizeBuffId) == 0
set u = null
return neutral and planet and notColonizing
endfunction
function GetPlanetsAroundUnit takes unit u, real radius returns group
set g_output_GetPlanetsAroundUnit = CreateGroup()
call GroupEnumUnitsInRange(g_output_GetPlanetsAroundUnit, GetUnitX(u), GetUnitY(u), radius, Condition(function GetPlanetsAroundUnitFilter))
return g_output_GetPlanetsAroundUnit
endfunction
function GetColonizePlanetRange takes player p returns real
return 6400 + GetPlayerState(p, PLAYER_STATE_RESOURCE_FOOD_CAP) * 160.0
endfunction
function FindColonizePlanetTarget takes unit u returns unit
local player p = GetOwningPlayer(u)
local real distance = GetColonizePlanetRange(p)
local group planets = GetPlanetsAroundUnit(u, distance)
local integer id = GetPlayerId(p)
//local unit target = GroupGetClosestUnit(planets, GetPlayerStartLocationX(p), GetPlayerStartLocationY(p))
local unit target = GroupGetClosestUnit(planets, GetUnitX(PlayerHomePlanets[id]), GetUnitY(PlayerHomePlanets[id]))
call DestroyGroup(planets)
set planets = null
set p = null
return target
endfunction
function TryColonizeWith takes unit u returns unit
if(GetUnitCurrentOrder(u) == OrderId(ColonizeOrderId))then
return null
endif
if(GetUnitCurrentOrder(u) == OrderId("smart"))then
return null
endif
if(GetUnitCurrentOrder(u) != 0 and GetUnitCurrentOrder(u) != OrderId("harvest"))then
return null
endif
set g_output_TryColonizeWith = FindColonizePlanetTarget(u)
if(g_output_TryColonizeWith == null)then
return null
endif
if(IssueTargetOrder(u, ColonizeOrderId, g_output_TryColonizeWith) == false)then
call IssuePointOrder(u, "smart", GetUnitX(g_output_TryColonizeWith), GetUnitY(g_output_TryColonizeWith))
endif
return g_output_TryColonizeWith
endfunction
function RunColonizationRoutine takes integer p returns nothing
local unit u
local unit targetPlanet
//call Debug("RunColonizationRoutine p" + I2S(p) + " " + I2S(CountUnitsInGroup(g_PlayerColonizerGroups[p])))
if(CountUnitsInGroup(g_PlayerColonizerGroups[p]) == 0)then
return
endif
set u = GroupPickRandomUnit(g_PlayerColonizerGroups[p])
set targetPlanet = TryColonizeWith(u)
if(not(targetPlanet == null))then
call GroupAddUnit(g_PlayerClaimTargetGroups[p], targetPlanet)
endif
set u = null
set targetPlanet = null
endfunction
function TryResetColonizedPlanet takes integer p, unit colonizedPlanet returns nothing
//call Debug("TryResetColonizedPlanet " + I2S(p))
if(IsUnitInGroup(colonizedPlanet, g_PlayerClaimTargetGroups[p]))then
//call Debug(B2S(true))
call GroupRemoveUnit(g_PlayerClaimTargetGroups[p], colonizedPlanet)
call RunColonizationRoutine(p)
endif
endfunction
function CleanPlayerColonizerEnum takes nothing returns nothing
if(IsUnitDeadBJ(GetEnumUnit()) == true)then
call GroupRemoveUnit(g_PlayerColonizerGroups[GetPlayerId(GetOwningPlayer(GetEnumUnit()))], GetEnumUnit())
endif
endfunction
function OnTrainedColonizerCondition takes nothing returns boolean
if (GetPlayerController(GetOwningPlayer(GetEnteringUnit())) != MAP_CONTROL_COMPUTER) then
return false // not an AI
endif
if(GetPlayerSlotState(GetOwningPlayer(GetEnteringUnit())) != PLAYER_SLOT_STATE_PLAYING)then
return false // not playing
endif
return GetUnitAbilityLevel(GetEnteringUnit(), ColonizeSpellId) > 0
endfunction
function OnColonizedCondition takes nothing returns boolean
local unit u = GetChangingUnit()
local boolean planet = (GetUnitAbilityLevel(u, 'A002') + GetUnitAbilityLevel(u, 'A003') + GetUnitAbilityLevel(u, 'A004')) > 0
//call Debug("OnColonizedCondition")
set u = null
return planet
endfunction
function OnTrainedColonizerAction takes nothing returns nothing
local player p = GetOwningPlayer(GetEnteringUnit())
local unit targetPlanet
//call Debug("OnTrainedColonizerAction")
set targetPlanet = TryColonizeWith(GetEnteringUnit())
call GroupAddUnit(g_PlayerColonizerGroups[GetPlayerId(p)], GetEnteringUnit())
if(targetPlanet != null)then
call GroupAddUnit(g_PlayerClaimTargetGroups[GetPlayerId(p)], targetPlanet)
set targetPlanet = null
endif
set p = null
endfunction
function OnCycleColonizerAction takes nothing returns nothing
local integer p = 0
//call Debug("OnCycleColonizerAction")
loop
if(GetPlayerController(Player(p)) == MAP_CONTROL_COMPUTER and GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING)then
call RunColonizationRoutine(p)
endif
set p = p + 1
exitwhen p == 12
endloop
endfunction
function OnColonizedAction takes nothing returns nothing
local integer p = 0
//call Debug("OnColonizedAction")
//call Debug(I2S(GetPlayerId(GetOwningPlayer(GetChangingUnit()))))
call ForGroup(g_PlayerColonizerGroups[GetPlayerId(GetOwningPlayer(GetChangingUnit()))], function CleanPlayerColonizerEnum)
loop
if(GetPlayerController(Player(p)) == MAP_CONTROL_COMPUTER and GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING)then
call TryResetColonizedPlanet(p, GetChangingUnit())
endif
set p = p + 1
exitwhen p == 12
endloop
endfunction
function Trig_AutoColonize_Actions takes nothing returns nothing
local integer p = 0
//call Debug("Trig_AutoColonize_Actions")
loop
exitwhen p == 12
if(GetPlayerSlotState(Player(p)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(p)) == MAP_CONTROL_COMPUTER)then
set g_PlayerClaimTargetGroups[p] = CreateGroup()
set g_PlayerColonizerGroups[p] = CreateGroup()
endif
set p = p + 1
endloop
endfunction
//===========================================================================
function InitTrig_AutoColonize takes nothing returns nothing
set gg_trg_AutoColonize = CreateTrigger()
call TriggerRegisterTimerEvent(gg_trg_AutoColonize, 0, false)
call TriggerAddAction(gg_trg_AutoColonize, function Trig_AutoColonize_Actions)
call TriggerRegisterEnterRectSimple(g_OnTrainedColonizer, GetPlayableMapRect())
call TriggerAddCondition(g_OnTrainedColonizer, Condition(function OnTrainedColonizerCondition))
call TriggerAddAction(g_OnTrainedColonizer, function OnTrainedColonizerAction)
call TriggerRegisterTimerEvent(g_OnCycleColonizer, 1, true)
call TriggerAddAction(g_OnCycleColonizer, function OnCycleColonizerAction)
call TriggerRegisterAnyUnitEventBJ(g_OnColonized, EVENT_PLAYER_UNIT_CHANGE_OWNER)
call TriggerAddCondition(g_OnColonized,Condition(function OnColonizedCondition))
call TriggerAddAction(g_OnColonized, function OnColonizedAction)
endfunction
function Trig_PrintOrders_Actions takes nothing returns nothing
call DisplayTextToPlayer(Player(0), 0, 0, GetUnitName(GetOrderedUnit()) + "-" + OrderId2String(GetIssuedOrderId()) + " " + I2S(GetIssuedOrderId()))
call DisplayTextToPlayer(Player(0), 0, 0, GetUnitName(GetOrderTargetUnit()) + "(" + R2S(GetUnitX(GetOrderTargetUnit())) + "," + R2S(GetUnitY(GetOrderTargetUnit())) + ")")
call DisplayTextToPlayer(Player(0), 0, 0, R2S(GetOrderPointX()) + "," + R2S(GetOrderPointY()))
endfunction
//===========================================================================
function InitTrig_PrintOrders takes nothing returns nothing
set gg_trg_PrintOrders = CreateTrigger()
call TriggerRegisterPlayerUnitEvent(gg_trg_PrintOrders, Player(0), EVENT_PLAYER_UNIT_ISSUED_ORDER, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_PrintOrders, Player(0), EVENT_PLAYER_UNIT_ISSUED_POINT_ORDER, null)
call TriggerRegisterPlayerUnitEvent(gg_trg_PrintOrders, Player(0), EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER, null)
call TriggerAddAction(gg_trg_PrintOrders, function Trig_PrintOrders_Actions)
endfunction