// Arcing Text Tag v1.0.2.0 by Maker with added API by Bribe and features proposed by Ugabunda and Kusanagi Kuro
//
// Added API in 1.0.1.0:
// public static ArcingTextTag lastCreated
// - Get the last created ArcingTextTag
// public real scaling
// - Set the size ratio of the texttag - 1.00 is the default
// public real timeScaling
// - Set the duration ratio of the texttag - 1.00 is the default
// https://www.hiveworkshop.com/threads/arcing-floating-text-1-0-0-3.228710/
library FloatingTextArc
globals
private constant real SIZE_MIN = 0.023 // Minimum size of text
private constant real TIME_LIFE = 1.0 // How long the text lasts
private constant real TIME_FADE = 0.8 // When does the text start to fade
private constant real Z_OFFSET = 100 // Height above unit
private constant real Z_OFFSET_BON = 75 // How much extra height the text gains
private constant real VELOCITY = 1 // How fast the text move in z plane
// ANGLE_RND is true
private timer TMR = CreateTimer()
endglobals
struct ArcingTextTag extends array
private texttag tt
private real t // time
private real x // origin x
private real y // origin y
private string s // text
private static integer array next
private static integer array prev
private static integer array rn
private static integer ic = 0 // Instance count
private real scale
private real timeScale
public static thistype lastCreated = 0
private static method update takes nothing returns nothing
local thistype this=next[0]
local real p
loop
set p = (1 - this.t)
set .t = .t - 0.03125
call SetTextTagPos(.tt, this.x, this.y, Z_OFFSET + p*Z_OFFSET_BON*VELOCITY)
call SetTextTagText(.tt, .s, SIZE_MIN*.scale)
if .t <= 0 then
set .tt = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
if next[0]==0 then
call PauseTimer(TMR)
call DestroyTextTag(this.tt)
endif
endif
set this = next[this]
exitwhen this == 0
endloop
endmethod
public static method createEx takes string s, unit u, real duration, real size, player p returns thistype
local thistype this = rn[0]
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set this.scale = size
set this.timeScale = RMaxBJ(duration, 0.001)
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
set this.s = s
set this.x = GetUnitX(u)
set this.y = GetUnitY(u)
set this.t = this.timeScale
if IsUnitVisible(u, p) and (GetLocalPlayer() == p) then
set this.tt = CreateTextTag()
call SetTextTagVisibility(this.tt, false)
call SetTextTagPermanent(this.tt, false)
call SetTextTagLifespan(this.tt, TIME_LIFE*duration)
call SetTextTagFadepoint(this.tt, TIME_FADE*duration)
call SetTextTagText(this.tt, s, SIZE_MIN)
call SetTextTagPos(this.tt, .x, .y, Z_OFFSET)
call SetTextTagVisibility(this.tt, true)
else
set .tt = null
endif
if prev[this] == 0 then
call TimerStart(TMR, 0.03125, true, function thistype.update)
endif
set .lastCreated = this
return this
endmethod
public static method create takes string s, unit u returns thistype
return thistype.createEx(s, u, TIME_LIFE, 1.00, GetLocalPlayer())
endmethod
endstruct
endlibrary
Name | Type | is_array | initial_value |
AfterDamageEvent | real | No | |
AIAttackPointer | integer | No | |
AICoreBuilding | unit | No | |
AIMainBuildings | group | Yes | |
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 | |
caster_2 | unit | No | |
CONVERTED_ATTACK_TYPE | attacktype | Yes | |
CONVERTED_DAMAGE_TYPE | damagetype | Yes | |
Cube_Model | string | No | |
Cube_Unit | unit | No | |
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 | |
Demon_Timer | timer | No | |
DruidSpell_2 | group | No | |
DruidSpell_2_Dummy | unit | No | |
dummy | unit | No | |
EnhancedDamageTarget | unit | No | |
FastLoc | unit | No | |
Fog | fogmodifier | No | |
GnollAI_MainBuilding | unit | No | |
GoldenBranchKeeper | unit | No | |
InfernoPortalGroup | group | No | |
IsDamageAttack | boolean | No | |
IsDamageCode | boolean | No | |
IsDamageMelee | boolean | No | |
IsDamageRanged | boolean | No | |
IsDamageSpell | boolean | No | |
ItemDropLoc | location | No | |
Leshi | unit | No | |
LeshiMoveOutTimer | timer | No | |
LeshiRessurectTimer | timer | No | |
LethalDamageEvent | real | No | |
LethalDamageHP | real | No | |
location | location | No | |
Market | unit | Yes | |
NeutralSawMill | unit | Yes | |
NextDamageIsAttack | boolean | No | |
NextDamageIsMelee | boolean | No | |
NextDamageIsRanged | boolean | No | |
NextDamageType | integer | No | |
NextDamageWeaponT | integer | No | |
OnDamageEvent | real | No | |
OverloadGroup | group | No | |
PlayersInGame | force | No | |
PlayersWithoutBranch | force | No | |
PreDamageEvent | real | No | |
PS_Current_Page | integer | Yes | |
PS_Loop | integer | No | |
PS_Page_Count | integer | No | |
PS_Page_Max_Range | integer | Yes | |
PS_Page_Min_Range | integer | Yes | |
PS_Player | player | No | |
PS_PN | integer | No | |
PS_Tech_Type | techcode | Yes | |
PS_Unit_Type | unitcode | Yes | |
RandomNumber | integer | No | |
RandomNumbersound | integer | No | |
RandomScroll | integer | No | |
RandomUnit | unitcode | Yes | |
RemoveDamageEvent | boolean | No | |
ReportLife | real | No | |
SawMillCount | integer | 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 | |
unitLocation | location | 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 | |
WispCountLV0 | integer | No | |
WispHarvestLV0 | unit | Yes | |
WispLV0Timer | timer | Yes | |
Zeppelin | unit | No | |
ZeroDamageEvent | real | No |
library ToolTipLib initializer onInit
globals
private real TTW = 0.29
private real TTPX = 0.8
private real TTPY = 0.162
endglobals
struct TTS
static method ToolTipCreate takes string TooltipBasic returns framehandle
local framehandle Parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)
//
local framehandle ToolTip = BlzCreateFrame("HeroSelectorTextBox", Parent, 0, 0)
local framehandle ToolTipText = BlzCreateFrame("HeroSelectorTextArea", ToolTip, 0, 0)
call BlzFrameSetText(ToolTipText, TooltipBasic)
//
call BlzFrameSetAbsPoint(ToolTip, FRAMEPOINT_BOTTOMRIGHT, TTPX, TTPY)
call BlzFrameSetSize(ToolTip, TTW, 0.10)
//
call BlzFrameSetPoint(ToolTipText, FRAMEPOINT_BOTTOMRIGHT, ToolTip, FRAMEPOINT_BOTTOMRIGHT, -0.005, 0.007)
call BlzFrameSetSize(ToolTipText, TTW-0.01, 0)
//
call BlzFrameSetSize(ToolTip, TTW, BlzFrameGetHeight(ToolTipText)+0.014)
return ToolTip
endmethod
static method ToolTipSetTextForPlayer takes framehandle TT, player pl, string TooltipBasic returns nothing
call BlzFrameSetText(BlzFrameGetChild(TT, 0), TooltipBasic)
endmethod
endstruct
endlibrary
library HeroButtonLib initializer onInit uses ToolTipLib
struct HeroButton
framehandle button
framehandle tooltip
framehandle ficon
framehandle ficonPushed
framehandle ficonDisabled
private trigger trigger
private trigger trigger_oskey
private static oskeytype array key_array
static method os_key_focusAction takes nothing returns nothing
if GetTriggerPlayer() == GetLocalPlayer() then
call BlzFrameSetEnable(BlzGetTriggerFrame(), false)
call BlzFrameSetEnable(BlzGetTriggerFrame(), true)
endif
endmethod
method SetTTTForPlayer takes player pl, string TooltipBasic returns nothing
if(GetLocalPlayer() == pl)then
call BlzFrameSetText(BlzFrameGetChild(this.tooltip, 0), TooltipBasic + " (|cffffcc00F"+I2S(this)+"|r)")
endif
endmethod
method hide takes nothing returns nothing
call BlzFrameSetVisible(this.button, false)
endmethod
method HideForPlayer takes player pl returns nothing
if(GetLocalPlayer() == pl)then
call BlzFrameSetVisible(this.button, false)
endif
endmethod
method ShowForPlayer takes player pl returns nothing
if(GetLocalPlayer() == pl)then
call BlzFrameSetVisible(this.button, true)
endif
endmethod
method SetIconForPlayer takes player pl, string IconPath returns nothing
if(GetLocalPlayer() == pl)then
call SetIcon(IconPath)
endif
endmethod
method SetIcon takes string IconPath returns nothing
call BlzFrameSetTexture(this.ficon, IconPath, 0, false)
call BlzFrameSetTexture(this.ficonPushed, IconPath, 0, false)
call BlzFrameSetTexture(this.ficonDisabled, IconPath, 0, false)
endmethod
method AddAction takes code f returns nothing
call TriggerAddAction(this.trigger, f)
call TriggerAddAction(this.trigger_oskey, f)
endmethod
method AddCondition takes conditionfunc cf returns nothing
call TriggerAddCondition(this.trigger, cf)
call TriggerAddCondition(this.trigger_oskey, cf)
endmethod
static method Create takes string Tooltip_basic, string IconPath returns thistype
local framehandle SuperParent = BlzGetFrameByName("ConsoleUIBackdrop", 0)
local framehandle Parent = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BAR, 0)
local integer i = 0
//
local thistype this = allocate()
set this.button = BlzCreateFrame("HeroSelectorButton", SuperParent, 0, 0)
//
set this.ficon = BlzGetFrameByName("HeroSelectorButtonIcon", 0)
set this.ficonPushed = BlzGetFrameByName("HeroSelectorButtonIconPushed", 0)
set this.ficonDisabled = BlzGetFrameByName("HeroSelectorButtonIconDisabled", 0)
call this.SetIcon(IconPath)
//
call BlzFrameSetPoint(this.button, FRAMEPOINT_TOPLEFT, Parent, FRAMEPOINT_TOPLEFT, 0, -(this-1)*(0.036))
set this.tooltip = TTS.ToolTipCreate(Tooltip_basic + " (|cffffcc00F"+I2S(this)+"|r)")
call BlzFrameSetTooltip(this.button, this.tooltip)
//
set this.trigger = CreateTrigger()
set this.trigger_oskey = CreateTrigger()
call BlzTriggerRegisterFrameEvent(this.trigger, this.button, FRAMEEVENT_CONTROL_CLICK)
call TriggerAddAction(this.trigger, function thistype.os_key_focusAction)
// Loop for all players to register the key event
loop
exitwhen i >= bj_MAX_PLAYERS
call BlzTriggerRegisterPlayerKeyEvent(this.trigger_oskey, Player(i), key_array[this-1], 0, false)
set i = i + 1
endloop
return this
endmethod
private static method onInit takes nothing returns nothing
call BlzLoadTOCFile("war3mapImported\\HeroSelector.toc")
set key_array[0] = OSKEY_F1
set key_array[1] = OSKEY_F2
set key_array[2] = OSKEY_F3
set key_array[3] = OSKEY_F4
set key_array[4] = OSKEY_F5
set key_array[5] = OSKEY_F6
set key_array[6] = OSKEY_F7
endmethod
endstruct
endlibrary
library DefaultTextTag initializer InitDefaultTextTag
globals
constant integer TextTagGoldBounty = 0
constant integer TextTagLumberBounty = 1
constant integer TextTagMiss = 2
constant integer TextTagCriticalStrike = 3
constant integer TextTagManaBurn = 4
constant integer TextTagShadowStrike = 5
constant real fontSize = 0.024
integer array color[4][16]
real array setting[5][16]
endglobals
function DefaultTextTag takes integer index, real x, real y, string text returns texttag
local texttag tt = CreateTextTag()
call SetTextTagText(tt, text, fontSize)
call SetTextTagPos(tt, x + setting[4][index], y, 0.0)
call SetTextTagColor(tt, color[0][index], color[1][index], color[2][index], color[3][index])
call SetTextTagVelocity(tt, setting[0][index], setting[1][index])
call SetTextTagFadepoint(tt, setting[2][index])
call SetTextTagLifespan(tt, setting[3][index])
call SetTextTagVisibility(tt, false) // Изначально видимость отключена
call SetTextTagPermanent(tt, false)
return tt
endfunction
function DefaultTextTagWidget takes integer index, widget target, string text returns texttag
return DefaultTextTag(index, GetWidgetX(target), GetWidgetY(target), text)
endfunction
function addColor takes integer index, integer c0, integer c1, integer c2, integer c3 returns nothing
set color[0][index] = c0
set color[1][index] = c1
set color[2][index] = c2
set color[3][index] = c3
endfunction
function addSetting takes integer index, real s0, real s1, real s2, real s3, real s4 returns nothing
set setting[0][index] = s0 // velocity 1
set setting[1][index] = s1 // velocity 2
set setting[2][index] = s2 // fadepoint
set setting[3][index] = s3 // lifespan
set setting[4][index] = s4 // offsetX
endfunction
function InitDefaultTextTag takes nothing returns nothing
call addColor(TextTagGoldBounty, 255, 220, 0, 255)
call addSetting(TextTagGoldBounty, 0.0, 0.03, 2.0, 3.0, -16.0)
call addColor(TextTagLumberBounty, 0, 200, 80, 255)
call addSetting(TextTagLumberBounty, 0.0, 0.03, 2.0, 3.0, -16.0)
call addColor(TextTagMiss, 255, 0, 0, 255)
call addSetting(TextTagMiss, 0.0, 0.03, 1.0, 3.0, 0.0)
call addColor(TextTagCriticalStrike, 255, 0, 0, 255)
call addSetting(TextTagCriticalStrike, 0.0, 0.04, 2.0, 5.0, 0.0)
call addColor(TextTagManaBurn, 82, 82, 255, 255)
call addSetting(TextTagManaBurn, 0.0, 0.04, 2.0, 5.0, 0.0)
call addColor(TextTagShadowStrike, 160, 255, 0, 255)
call addSetting(TextTagShadowStrike, 0.0, 0.04, 2.0, 5.0, 0.0)
endfunction
endlibrary
/*
vJass Damage Engine 5.A.0.0
// https://www.hiveworkshop.com/threads/damage-engine-5-a-0-0.201016/
This update enables compatibility with AttackIndexer.
*/
/*
JASS API:
struct Damage extends array
readonly static unit source // udg_DamageEventSource in real-time
readonly static unit target // udg_DamageEventTarget in real-time
static real amount // udg_DamageEventAmount in real-time
readonly unit sourceUnit // udg_DamageEventSource by index
readonly unit targetUnit // udg_DamageEventTarget by index
real damage // udg_DamageEventAmount by index
readonly real prevAmt // udg_DamageEventPrevAmt by index
attacktype attackType // udg_DamageEventAttackT by index
damagetype damageType // udg_DamageEventDamageT by index
weapontype weaponType // udg_DamageEventWeaponT by index
integer userType // udg_DamageEventType by index
readonly boolean isAttack // udg_IsDamageAttack by index
readonly boolean isCode // udg_IsDamageCode by index
readonly boolean isMelee // udg_IsDamageMelee by index
readonly boolean isRanged // udg_IsDamageRanged by index
readonly boolean isSpell // udg_IsDamageSpell by index
real armorPierced // udg_DamageEventArmorPierced by index
integer armorType // udg_DamageEventArmorT by index
integer defenseType // udg_DamageEventDefenseT by index
readonly integer eFilter
Set to false to disable the damage event triggers or to true to reverse that:
static boolean operator enabled
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 apply takes
unit source,
unit target,
real amount,
boolean isAttack,
boolean isRanged,
attacktype at,
damagetype dt,
weapontype wt
returns Damage
A simplified version of the above function that autofills each boolean, attacktype and weapontype.
static method applySpell takes
unit src,
unit tgt,
real amt,
damagetype dt
returns Damage
A different variation of the above which autofills the "isAttack" boolean
and populates damagetype as DAMAGE_TYPE_NORMAL.
static method applyAttack takes
unit src,
unit tgt,
real amt,
boolean ranged,
attacktype at,
weapontype wt
returns Damage
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:
- integer DamageEngine_FILTER_ATTACK
- integer DamageEngine_FILTER_MELEE
- integer DamageEngine_FILTER_OTHER
- integer DamageEngine_FILTER_RANGED
- integer DamageEngine_FILTER_SPELL
- integer DamageEngine_FILTER_CODE
boolean configured //set to True after configuring any filters listed below.
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
method configure takes nothing returns nothing
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 whichTrig,
string eventName,
real value,
boolean reset
returns boolean
static method getIndex takes
trigger fromTrigger,
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.
Use it via DamageTrigger[function MyCallbackFunction]
static method operator [] takes
code callback
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 opId
returns nothing
function TriggerRegisterDamageEngine takes
trigger whichTrig,
string eventName,
real value
returns nothing
function RegisterDamageEngineEx takes
code callback,
string eventName,
real value,
integer opId
returns nothing
function RegisterDamageEngine takes
code callback,
string eventName,
real value
returns nothing
*/
//===========================================================================
library DamageEngine requires optional AttackIndexer
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 SourceDamageEvent, 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
/*
When manually-enabled recursion is enabled via DamageEngine_inception,
the engine will never go deeper than MAX_RECURSIVE_TOLERANCE:
*/
private constant integer MAX_RECURSIVE_TOLERANCE = 16
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 M$ ever changes this, it'll be a quick fix here.
private timer async = null
private boolean timerStarted = false
//Values to track the original pre-spirit Link/defensive damage values
private Damage lastInstance = 0
private boolean isNotNativeRecursiveDamage = true
private boolean waitingForDamageEventToRun = false
private boolean array attacksImmune
private boolean array damagesImmune
//Primary triggers used to handle all damage events.
private trigger damagingTrigger = null
private trigger damagedTrigger = null
private trigger recursiveTrigger = null //Catches, stores recursive events
/*
These variables coincide with Blizzard's "limitop" type definitions
so as to enable GUI users with some performance perks - however,
these optimizations need to be tested
*/
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
/*
When true, it allows your trigger to go recursively up to
MAX_RECURSIVE_TOLERANCE (if needed). It must be set before dealing damage.
*/
public boolean inception = false
private boolean callbacksInProgress = false
private integer recursiveCallbackDepth = 0
private group recursionSources = null
private group recursionTargets = null
private boolean recursiveCallbaksInProgress = false
private boolean nativeEventsCompleted = false
private boolean atLeastOneLethalDamageEventRegistered = false
// Struct members made private to this library.
private keyword run
private keyword trigFrozen
private keyword ownRecursiveDepth
private keyword manualRecursionRequested
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)
//Added in 5.9
real udg_SourceDamageEvent //Like AOEDamageEvent, fires each time the source unit has finished dealing damage, but doesn't care if the damage hit multiple units.
real udg_PreDamageEvent //Like DamageModifierEvent 3.99 or less, except can be any real value.
real udg_ArmorDamageEvent //Like DamageModifierEvent 4.00 or more, except can be any real value.
real udg_OnDamageEvent //Like DamageEvent equal to 1.00 or some non-zero/non-2 value, except can be any real value.
real udg_ZeroDamageEvent //Like DamageEvent equal to 0.00 or 2.00, except can be any real value.
*/
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 probably not use these filters,
unless someone tests performance to see
if such an ugly hack is even worth it.
*/
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
private thistype next
private trigger rootTrig
//The below variables are to be treated as private
boolean trigFrozen //Whether the trigger is currently disabled due to recursion
integer ownRecursiveDepth //How deep the user recursion currently is.
boolean manualRecursionRequested //Added in 5.4.2 to simplify the inception variable for very complex DamageEvent triggers.
//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
// getter:
method operator runChance takes nothing returns real
return 1.00 - this.failChance
endmethod
// setter:
method operator runChance= takes real chance returns nothing
set this.failChance = 1.00 - chance
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_DamageFilterSource = null
set udg_DamageFilterTarget = null
//These handles can have a valid value of 0, so we need to distinguish them.
set udg_DamageFilterAttackT = -1
set udg_DamageFilterDamageT = -1
set udg_DamageFilterSourceC = -1
set udg_DamageFilterTargetC = -1
set udg_DamageFilterSourceT = 0
set udg_DamageFilterTargetT = 0
set udg_DamageFilterType = 0
set udg_DamageFilterSourceB = 0
set udg_DamageFilterTargetB = 0
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
//! runtextmacro optional ATTACK_INDEXER_GUI_VARS()
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 opId returns nothing
set this = this * FILTER_MAX
if opId == FILTER_OTHER then
call this.toggleAllFilters(true)
else
if opId == 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 + opId] = 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
//allows GUI to register multiple different types of Damage filters to the same trigger
set filters[lastRegistered*FILTER_MAX + filt] = true
return 0
endif
set atLeastOneLethalDamageEventRegistered = /*
*/ atLeastOneLethalDamageEventRegistered or index == LETHAL
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 callbacksInProgress then
return
endif
set callbacksInProgress = true
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
call EnableTrigger(recursiveTrigger)
//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(recursiveTrigger)
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set callbacksInProgress = false
endmethod
/*
Used by RegisterDamageEngineEx to create triggers behind-the-scenes,
allowing the user to simply pass the function they want to execute.
*/
static trigger array autoTriggers
static boolexpr array autoFuncs
static integer autoN = 0
static method operator [] takes code callback returns trigger
local integer i = 0
local boolexpr b = Filter(callback)
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
readonly unit targetUnit
real damage
readonly real prevAmt
attacktype attackType
damagetype damageType
weapontype weaponType
integer userType
readonly boolean isAttack
readonly boolean isCode
readonly boolean isSpell
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 from != to not == due 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 runDamagingEvents 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(recursionSources, udg_DamageEventSource)
call GroupAddUnit(recursionTargets, 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()
// Using not == instead of !=; the idea is to eliminate floating point bugs when two numbers are very close to 0,
// because JASS uses a less-strict comparison for checking if a number is equal than when it is unequal.
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 //return value is based on whether the event is a 0 damage event (true) or not (false).
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.ownRecursiveDepth = 0
endloop
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
set recursiveCallbaksInProgress = false
set damageStack = 0
set prepped = 0
set callbacksInProgress = false
set recursiveCallbackDepth = 0
call GroupClear(recursionSources)
call GroupClear(recursionTargets)
//call BJDebugMsg("Cleared up the groups")
endmethod
static method runAfterDamageEvents takes nothing returns nothing
local Damage i = 0
local integer exit
if nativeEventsCompleted then
set nativeEventsCompleted = false
call afterDamage()
endif
if isNotNativeRecursiveDamage and not recursiveCallbaksInProgress then
if damageStack != 0 then
set recursiveCallbaksInProgress = true
loop
/*
Use two loops. The outer loop handles all normal event
execution, while the inner loop intelligently handles
recursive execution (when it's used).
*/
set recursiveCallbackDepth = recursiveCallbackDepth + 1
set exit = damageStack
loop
set prepped = i.stackRef
if UnitAlive(prepped.targetUnit) then
// We don't need to trigger `damagingTrigger` itself, so just call its handler directly.
call prepped.runDamagingEvents(false)
if prepped.damage > 0.00 then
call DisableTrigger(damagingTrigger) // Disallow `damagingTrigger` because we only want `damageTrigger` to run.
call EnableTrigger(damagedTrigger) // Re-enable `damagedTrigger` in case the user forgot to do so.
set waitingForDamageEventToRun = true
call UnitDamageTarget( /*
*/ prepped.sourceUnit, /*
*/ prepped.targetUnit, /*
*/ prepped.damage, /*
*/ prepped.isAttack, /*
*/ prepped.isRanged, /*
*/ prepped.attackType, /*
*/ prepped.damageType, /*
*/ prepped.weaponType /*
*/ )
else
if udg_DamageEventDamageT != 0 then
//No native events run at all in this case
call DamageTrigger.DAMAGE.run()
endif
if prepped.damage < 0.00 then
/*
No need for BlzSetEventDamage/UnitDamageTarget here,
because we can safely adjust the unit's life instead.
*/
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 isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
set waitingForDamageEventToRun = false
if udg_DamageEventDamageT != 0 then
call DamageTrigger.DAMAGE.run()
set nativeEventsCompleted = true
endif
call runAfterDamageEvents()
endmethod
static method operator enabled= takes boolean b returns nothing
if b then
if callbacksInProgress then
call EnableTrigger(recursiveTrigger)
else
call EnableTrigger(damagingTrigger)
call EnableTrigger(damagedTrigger)
endif
else
if callbacksInProgress then
call DisableTrigger(recursiveTrigger)
else
call DisableTrigger(damagingTrigger)
call DisableTrigger(damagedTrigger)
endif
endif
endmethod
static method operator enabled takes nothing returns boolean
return IsTriggerEnabled(damagingTrigger)
endmethod
private static boolean threadCompleted = false
private static method asyncCallbackSafeCallback takes nothing returns nothing
if waitingForDamageEventToRun then
/*
This means that WarCraft 3 didn't run the DAMAGED event despite running the DAMAGING event.
*/
call failsafeClear()
else
set isNotNativeRecursiveDamage = true
set recursiveCallbaksInProgress = false
call runAfterDamageEvents()
endif
static if USE_EXTRA then
call onAOEEnd()
endif
set threadCompleted = true
endmethod
private static method asyncCallback takes nothing returns nothing
set callbacksInProgress = false
set Damage.enabled = true
/*
Open a new thread in case of a thread crash during callback.
*/
call ForForce(bj_FORCE_PLAYER[0], function thistype.asyncCallbackSafeCallback)
if not threadCompleted then
//call BJDebugMsg("DamageEngine issue: thread crashed!")
call unfreeze()
else
set threadCompleted = false
endif
set Damage.count = 0
set Damage.index = 0
set timerStarted = false
//call BJDebugMsg("Timer wrapped up")
endmethod
private method addRecursive takes nothing returns nothing
local DamageTrigger currentIndex
if not (this.damage == 0.00) then
set currentIndex = DamageTrigger.eventIndex
set this.recursiveTrig = currentIndex
if not this.isCode then
/*
If the recursive damage trigger is executed, this can only
mean that the user has manually dealt damage from a trigger.
Hence flag the damage as being 'code' if they didn't already
manually do this.
*/
set this.isCode = true
set this.userType = TYPE_CODE
endif
set inception = inception or /*
*/ currentIndex.manualRecursionRequested
if recursiveCallbaksInProgress and /*
*/ IsUnitInGroup(this.sourceUnit, recursionSources) and /*
*/ IsUnitInGroup(this.targetUnit, recursionTargets) /*
*/ then
if not inception then
set currentIndex.trigFrozen = true
elseif not currentIndex.trigFrozen then
set currentIndex.manualRecursionRequested = true
if currentIndex.ownRecursiveDepth < recursiveCallbackDepth then
set currentIndex.ownRecursiveDepth = /*
*/ currentIndex.ownRecursiveDepth + 1
if currentIndex.ownRecursiveDepth >= MAX_RECURSIVE_TOLERANCE then
set currentIndex.trigFrozen = true
endif
endif
endif
endif
// push the reference to the top of the damage stack.
set damageStack.stackRef = this
set damageStack = damageStack + 1
//call BJDebugMsg("damageStack: " + I2S(damageStack) + " ownRecursiveDepth: " + I2S(currentIndex.ownRecursiveDepth) + " recursiveCallbackDepth: " + I2S(recursiveCallbackDepth))
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 isAttack, /*
*/ 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.damageType = dt
set d.attackType = at
set d.weaponType = wt
set d.isAttack = udg_NextDamageIsAttack or isAttack
set d.isSpell = d.attackType == null and not d.isAttack
return d
endmethod
private static method createFromEvent takes nothing returns Damage
local Damage d = thistype.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
// Added in version 5.A in order to allow an optional external
// Attack Indexer system to reset the event weapon type to normal.
//! runtextmacro optional ATTACK_INDEXER_ADJUSTMENTS()
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
// Melee units always play a sound when damaging in WC3,
// so this is an easy check.
set d.isMelee = d.weaponType != null
// In the case where a unit is both ranged and melee,
// the ranged attack plays no sound.
set d.isRanged = not d.isMelee
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
// Spells are neither melee nor ranged.
set d.isMelee = false
set d.isRanged = false
endif
endif
endif
call clearNexts()
return d
endmethod
private static method onRecursiveDamageCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
call d.addRecursive()
call BlzSetEventDamage(0.00)
return false
endmethod
private static method onDamagingCallback takes nothing returns boolean
local Damage d = Damage.createFromEvent()
//call BJDebugMsg("Pre-damage event running for " + GetUnitName(GetTriggerUnit()))
if timerStarted then
if waitingForDamageEventToRun 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 waitingForDamageEventToRun = false
set lastInstance = Damage.index
set isNotNativeRecursiveDamage = false
else
call failsafeClear() //Not an overlapping event - just wrap it up
endif
else
call runAfterDamageEvents() //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
set udg_EnhancedDamageTarget = d.targetUnit
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(async, 0.00, false, function Damage.asyncCallback)
set timerStarted = 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.runDamagingEvents(true) then
call DamageTrigger.ZERO.run()
set isNotNativeRecursiveDamage = true
call runAfterDamageEvents()
endif
set waitingForDamageEventToRun = 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 onDamagedCallback 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 callbacksInProgress or d.prevAmt == 0.00 then
return false
elseif waitingForDamageEventToRun then
set waitingForDamageEventToRun = false
else
/*
This should only happen for native recursive WarCraft 3 damage
such as Spirit Link, Thorns Aura, or Spiked Carapace / Barricades.
*/
call afterDamage()
set Damage.index = lastInstance
set lastInstance = 0
set d = Damage.index
/*
Since the native recursive damage has now wrapped up, we can resume
handling events as normal at this point. This means that the original
target that the DAMAGING event was triggered for is now finally getting
its DAMAGED event.
*/
set isNotNativeRecursiveDamage = 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 atLeastOneLethalDamageEventRegistered or udg_DamageEventType < 0 then
set udg_LethalDamageHP = /*
*/ GetWidgetLife(udg_DamageEventTarget) - udg_DamageEventAmount
if udg_LethalDamageHP <= DEATH_VAL then
if atLeastOneLethalDamageEventRegistered 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 nativeEventsCompleted = true
if udg_DamageEventAmount == 0.00 then
call runAfterDamageEvents()
endif
// This return statement was needed years ago to avoid potential crashes on Mac.
// I am not sure if that's still a thing.
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 callbacksInProgress 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 runAfterDamageEvents()
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
/*
This part is the most critical to get things kicked off. All the code we've seen up until now
is related to event handling, trigger assignment, edge cases, etc. But it's the following that
is really quite esesntial for any damage engine - not just this one.
*/
private static method onInit takes nothing returns nothing
set async = CreateTimer()
set recursionSources = CreateGroup()
set recursionTargets = CreateGroup()
set damagingTrigger = CreateTrigger()
set damagedTrigger = CreateTrigger()
set recursiveTrigger = CreateTrigger() //Moved from globals block as per request of user Ricola3D
call TriggerRegisterAnyUnitEventBJ(damagingTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(damagingTrigger, Filter(function Damage.onDamagingCallback))
call TriggerRegisterAnyUnitEventBJ(damagedTrigger, EVENT_PLAYER_UNIT_DAMAGED)
call TriggerAddCondition(damagedTrigger, Filter(function Damage.onDamagedCallback))
//For recursion
call TriggerRegisterAnyUnitEventBJ(recursiveTrigger, EVENT_PLAYER_UNIT_DAMAGING)
call TriggerAddCondition(recursiveTrigger, Filter(function Damage.onRecursiveDamageCallback))
call DisableTrigger(recursiveTrigger) //starts disabled. Will be enabled during recursive event handling.
/*
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
// Called from the GUI configuration trigger once the assignments are in place.
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
/*
The remaining stuff is an ugly 'optimization' that I did a long
time ago, thinking that it would improve performance for GUI users
by not having so many different triggerconditions evaluating per
damage event. I am not sure if it even worked; in Lua it might
perform worse, but in vJass it remains to be tested.
*/
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
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 opId /*
*/ returns DamageTrigger
return DamageTrigger.registerVerbose( /*
*/ whichTrig, /*
*/ DamageTrigger.getVerboseStr(eventName), /*
*/ value, /*
*/ false, /*
*/ opId /*
*/ )
endfunction
function TriggerRegisterDamageEngine takes /*
*/ trigger whichTrig, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return DamageTrigger.registerTrigger(whichTrig, eventName, value)
endfunction
function RegisterDamageEngineEx takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value, /*
*/ integer opId /*
*/ returns DamageTrigger
return TriggerRegisterDamageEngineEx(DamageTrigger[callback], eventName, value, opId)
endfunction
//Similar to TriggerRegisterDamageEvent, but takes code instead of trigger as the first argument.
function RegisterDamageEngine takes /*
*/ code callback, /*
*/ string eventName, /*
*/ real value /*
*/ returns DamageTrigger
return RegisterDamageEngineEx(callback, eventName, value, FILTER_OTHER)
endfunction
/*
The below macros are 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
library GolemSpawn initializer onInit uses HandlerLib, StatisticLib, TimerHandlerLib
//! novjass
function AddCave takes CAVE CV returns nothing
function AddGolemType takes /*
*/integer objectid, /*
*/real lambda, /*
*/integer maxspawn /*
*/returns CaveGuardType
//! endnovjass
globals
private HandlerUnit GoldenCave
private trigger udg_trg_dyingcave
endglobals
private struct CaveGuardType
integer objectid
real lambda
integer maxspawn
static integer Count
method TrySpawn takes real dl returns boolean
local real p = 1 - stat.poisson(0, this.lambda*dl)
if(GetRandomReal(0, 1) < p)then
return true
else
return false
endif
endmethod
static method create takes integer objectid, real lambda, integer maxspawn returns thistype
local thistype this = thistype.allocate()
set this.objectid = objectid
set this.lambda = lambda
set this.maxspawn = maxspawn
set thistype.Count = thistype.Count + 1
return this
endmethod
private static method onInit takes nothing returns nothing
set thistype.Count = 0
endmethod
endstruct
private struct CAVE extends UNIT
method operator LastGold takes nothing returns integer
return this.LoadInteger(this.thishandler.p)
endmethod
method operator LastGold= takes integer value returns nothing
call this.SaveInteger(this.thishandler.p, value)
endmethod
method CreateCaveUnit takes CaveGuardType GT returns nothing
local unit un
local real randomreal = GetRandomReal(0,2*bj_PI)
local real x = GetUnitX(this.unit) + 120 * Cos(randomreal)
local real y = GetUnitY(this.unit) + 120 * Sin(randomreal)
local sound loc_sound
local string soundpath
local string effpath = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
local integer randomint
local effect loc_ef
set un = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), GT.objectid, x, y, 0)
call SetUnitAnimation( un, "Birth" )
set randomint = GetRandomInt(0,3)
if (randomint == 0)then
set soundpath = "Units/Creeps/RockGolem/RockGolemWhat1.flac"
elseif(randomint == 1)then
set soundpath = "Units/Creeps/RockGolem/RockGolemWhat2.flac"
elseif(randomint == 2)then
set soundpath = "Units/Creeps/RockGolem/Yes1.flac"
elseif(randomint == 3)then
set soundpath = "Units/Creeps/RockGolem/Yes2.flac"
endif
set loc_ef = AddSpecialEffect(effpath,GetUnitX(un),GetUnitY(un))
call addEffectTimer(loc_ef, 2)
set loc_ef = AddSpecialEffect(effpath,x,y)
call BlzSetSpecialEffectScale(loc_ef,2)
call addEffectTimer(loc_ef, 2)
set loc_sound = CreateSound(soundpath, false, true, true, 1, 1, "DoodadsEAX")
call SetSoundPosition(loc_sound, x, y, 0)
call SetSoundVolume(loc_sound, 172)
call SetSoundDistanceCutoff(loc_sound, 3000)
call StartSound(loc_sound)
call KillSoundWhenDone(loc_sound)
endmethod
method CreateCaveUnits takes integer maxun, CaveGuardType GT returns nothing
local integer randint = GetRandomInt(1, maxun)
local integer i = 0
loop
exitwhen(i == randint)
call this.CreateCaveUnit(GT)
set i = i + 1
endloop
endmethod
endstruct
private function RemoveCave takes nothing returns nothing
local unit un = GetDyingUnit()
local CAVE CV = GetHandleId(un)
if(HandlerUnit.isUnitIn(un))then
if(GoldenCave.isUnitInGroup(CV)) then
call GoldenCave.Remove(CV)
call CV.flush()
endif
endif
endfunction
private function GoldenCaveAction takes unit cave returns nothing
local CAVE CV = GetHandleId(cave)
local integer CurrGold = CV.GetResourceAmount()
local integer LastGold = CV.LastGold
local CaveGuardType GT = 1
if (LastGold > CurrGold) then
set CV.LastGold = CurrGold
set CurrGold = (LastGold - CurrGold)/10
loop
exitwhen(GT == CaveGuardType.Count+1)
if (GT.TrySpawn(CurrGold)) then
call CV.CreateCaveUnits(GT.maxspawn, GT)
endif
set GT = GT + 1
endloop
endif
endfunction
struct GCL
private static method GoldenCaveCheck takes nothing returns nothing
call GoldenCave.forAll(GoldenCaveAction)
endmethod
static method AddCave takes unit un returns nothing
local CAVE CV = CAVE.create(un)
set CV = GoldenCave.Add(CV)
set CV.LastGold = CV.GetResourceAmount()
endmethod
static method AddGolemType takes integer objectid, real lambda, integer maxspawn returns CaveGuardType
return CaveGuardType.create(objectid, lambda, maxspawn)//'n013''ngrk'//
endmethod
private static method onInit takes nothing returns nothing
local timer loc_timer
set GoldenCave = HandlerUnit.create(1)
set loc_timer = CreateTimer()
call TimerStart(loc_timer, 1.0 ,true, function thistype.GoldenCaveCheck )
// Инициализация триггера отслеживающая мертвых харвестеров
set udg_trg_dyingcave = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( udg_trg_dyingcave, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddAction( udg_trg_dyingcave, function RemoveCave )
endmethod
endstruct
endlibrary
library SpawnerLib initializer onInit uses HandlerLib, StatisticLib, TimerHandlerLib, MultidimensionalArray
struct SpawnType
Integer1D id
Integer1D sw
Integer1D max
integer wsum
integer Count
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.id = Integer1D.create()
set this.sw = Integer1D.create()
set this.max = Integer1D.create()
set this.Count = 0
set this.wsum = 0
return this
endmethod
method addType takes integer objectid, integer sw, integer max returns nothing
set this.id[this.Count] = objectid
set this.sw[this.Count] = sw
set this.max[this.Count] = max
set this.Count = this.Count + 1
set this.wsum = this.wsum + sw
endmethod
method GetRandomType takes nothing returns integer
local integer swrem = this.wsum
local integer statint = GetRandomInt(1, swrem)
local integer Type = 0
loop
set swrem = swrem - this.sw[Type]
exitwhen(statint > swrem)
set Type = Type + 1
endloop
return Type
endmethod
method GetRandomId takes nothing returns integer
return this.id[GetRandomType()]
endmethod
method GetType takes nothing returns integer
if(this.Count > 1)then
return this.GetRandomType()
else
return 0
endif
endmethod
private static method onInit takes nothing returns nothing
endmethod
endstruct
private struct GUARD extends UNIT
static HandlerUnit group
// ==== Свойтва класса ========================================
// Id спавнера прикрепелнного к юниту
method operator SpawnerId takes nothing returns integer
return this.LoadInteger(group.p)
endmethod
method operator SpawnerId= takes integer value returns nothing
call this.SaveInteger(group.p, value)
endmethod
// Номер типа в структуре
method operator TypeId takes nothing returns integer
return this.LoadInteger(group.p + 1)
endmethod
method operator TypeId= takes integer value returns nothing
call this.SaveInteger(group.p + 1, value)
endmethod
//
static method onInit takes nothing returns nothing
set thistype.group = HandlerUnit.create(2)
endmethod
endstruct
private struct SPAWNER extends UNIT
static HandlerUnit group
// ==== Свойтва класса =============================================
// ==== Число защитников в спавнере определенного типа =============
method operator GCountArray takes nothing returns Integer1D
return this.LoadInteger(group.p)
endmethod
method operator GCountArray= takes Integer1D value returns nothing
call this.SaveInteger(group.p, value)
endmethod
// ==== Общее число защитников в спавнере ==========================
method operator GCount takes nothing returns integer
return this.LoadInteger(group.p+1)
endmethod
method operator GCount= takes integer value returns nothing
call this.SaveInteger(group.p+1, value)
endmethod
// ==== Общее максимальное число защитников в спавнере =============
method operator MaxGCount takes nothing returns integer
return this.LoadInteger(group.p+2)
endmethod
method operator MaxGCount= takes integer value returns nothing
call this.SaveInteger(group.p+2, value)
endmethod
// ==== Время спавна ================================================
method operator SpawnTime takes nothing returns real
return this.LoadReal(group.p+3)
endmethod
method operator SpawnTime= takes real value returns nothing
call this.SaveReal(group.p+3, value)
endmethod
// ==== Тип спавна ===================================================
method operator SpawnType takes nothing returns SpawnType
return this.LoadInteger(group.p+4)
endmethod
method operator SpawnType= takes SpawnType ST returns nothing
call this.SaveInteger(group.p+4, ST)
endmethod
// ==== Таймер спавнера ==============================================
method operator SpawnTimer takes nothing returns TMR
return this.LoadInteger(group.p+5)
endmethod
method operator SpawnTimer= takes integer objectid returns nothing
call this.SaveInteger(group.p+5, objectid)
endmethod
// ===================================================================
method SpawnAnyway takes integer typeid returns GUARD
local GUARD GU
local real r_real = GetRandomReal(0,2*bj_PI)
local real x = GetUnitX(this.unit) + 120 * Cos(r_real)
local real y = GetUnitY(this.unit) + 120 * Sin(r_real)
local string effpath = "Objects\\Spawnmodels\\Undead\\ImpaleTargetDust\\ImpaleTargetDust.mdl"
set GU = GUARD.group.Add(GUARD.create(/*
*/ CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), SpawnType.id[typeid], x, y, 0)))
set GU.SpawnerId = this
set GU.TypeId = typeid
// call addEffectTimer(/*
// */ AddSpecialEffect(effpath, GetUnitX(GU.unit), GetUnitY(GU.unit)), 2)
set this.GCountArray[typeid] = this.GCountArray[typeid] + 1
set this.GCount = this.GCount + 1
return GU
endmethod
method Spawn takes nothing returns GUARD
local integer typeid
local integer i = 0
if( this.MaxGCount > this.GCount ) then
loop
set typeid = this.SpawnType.GetType()
exitwhen(this.SpawnType.max[typeid] > this.GCountArray[typeid] or i == 5)
set i = i + 1
endloop
if(this.SpawnType.max[typeid] > this.GCountArray[typeid])then
return this.SpawnAnyway(typeid)
else
return 0
endif
endif
return 0
endmethod
static method SpawnPeriodic takes nothing returns nothing
local TMR thistimer = GetHandleId(GetExpiredTimer())
local thistype this = thistimer.integer
local GUARD GU = this.Spawn()
if (GU != 0) then
call SetUnitPathing( GU.unit, false )
endif
endmethod
static method Add takes unit un, integer maxcount, real SpawnTime, SpawnType ST returns thistype
local thistype this = thistype.create(un)
set this.GCountArray = Integer1D.create()
set this.MaxGCount = maxcount
set this.SpawnTime = SpawnTime
set this.SpawnType = ST
set this.SpawnTimer = TMR.StartInteger(this.SpawnTime, true, function thistype.SpawnPeriodic, this)
call thistype.group.Add(this)
return this
endmethod
method flush takes nothing returns nothing
call this.GCountArray.flush()
call this.SpawnTimer.flush()
call super.flush()
endmethod
static method onInit takes nothing returns nothing
set thistype.group = HandlerUnit.create(6)
endmethod
endstruct
struct SPL
static trigger Trg_GuardDeath
static trigger Trg_SpawnerDeath
private static integer locint
private static real spawnTime
private static method SpawnerDeathCond takes nothing returns boolean
return SPAWNER.group.isUnitInGroup(GetHandleId(GetDyingUnit()))
endmethod
private static method SpawnerDeath takes nothing returns nothing
local SPAWNER SP = GetHandleId(GetTriggerUnit())
call SPAWNER.group.Remove(SP)
call SP.flush()
endmethod
private static method GuardDeathCond takes nothing returns boolean
return GUARD.group.isUnitInGroup(GetHandleId(GetDyingUnit()))
endmethod
private static method GuardDeath takes nothing returns nothing
local GUARD GU = GetHandleId(GetDyingUnit())
local SPAWNER SP = GU.SpawnerId
set SP.GCount = SP.GCount - 1
set SP.GCountArray[GU.TypeId] = SP.GCountArray[GU.TypeId] - 1
call GUARD.group.Remove(GU)
call GU.flush()
endmethod
private static method SetType takes SPAWNER SP returns nothing
set SP.SpawnType = locint
endmethod
private static method SetMax takes SPAWNER SP returns nothing
set SP.MaxGCount = locint
endmethod
private static method SetSpawnTime takes SPAWNER SP returns nothing
set SP.SpawnTime = spawnTime
call SP.SpawnTimer.flush() // Останавливаем текущий таймер
set SP.SpawnTimer = TMR.StartInteger(spawnTime, true, function SPAWNER.SpawnPeriodic, SP) // Перезапускаем таймер с новым временем спавна
endmethod
static method SetTypeGuardForAll takes integer Type returns nothing
set locint = Type
call SPAWNER.group.forAllUNIT(SetMax)
endmethod
static method SetMaxGuardForAll takes integer MaxGuard returns nothing
set locint = MaxGuard
call SPAWNER.group.forAllUNIT(SetMax)
endmethod
static method SetSpawnTimeForAll takes real newSpawnTime returns nothing
set spawnTime = newSpawnTime
call SPAWNER.group.forAllUNIT(SetSpawnTime)
endmethod
static method addSpawner takes unit un, integer mcount, real SpawnTime, SpawnType ST returns nothing
call SPAWNER.Add(un, mcount, spawnTime, ST) // Используем глобальную переменную spawnTime для новых спаунеров
endmethod
private static method onInit takes nothing returns nothing
set thistype.Trg_GuardDeath = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent( /*
*/ thistype.Trg_GuardDeath, /*
*/ Player(PLAYER_NEUTRAL_AGGRESSIVE), /*
*/ EVENT_PLAYER_UNIT_DEATH, /*
*/ null)
call TriggerAddCondition( thistype.Trg_GuardDeath, Condition(function thistype.GuardDeathCond) )
call TriggerAddAction( thistype.Trg_GuardDeath, function thistype.GuardDeath )
//
set thistype.Trg_SpawnerDeath = CreateTrigger( )
call TriggerRegisterPlayerUnitEvent( /*
*/ thistype.Trg_SpawnerDeath, /*
*/ Player(PLAYER_NEUTRAL_AGGRESSIVE), /*
*/ EVENT_PLAYER_UNIT_DEATH, /*
*/ null)
call TriggerAddCondition( thistype.Trg_SpawnerDeath, Condition(function thistype.SpawnerDeathCond) )
call TriggerAddAction( thistype.Trg_SpawnerDeath, function thistype.SpawnerDeath )
endmethod
endstruct
endlibrary
library QuasiRandom uses MatMapLib, MathLib
private struct RB
MatMap map
nj_I1D xar
nj_I1D yar
rect rec
integer K
real R
method operator minX takes nothing returns integer
return R2I(GetRectMinX(this.rec))
endmethod
method operator minY takes nothing returns integer
return R2I(GetRectMinY(this.rec))
endmethod
method operator maxX takes nothing returns integer
return R2I(GetRectMaxX(this.rec))
endmethod
method operator maxY takes nothing returns integer
return R2I(GetRectMaxY(this.rec))
endmethod
static method create takes real R, integer K, rect rec returns thistype
local thistype this = thistype.allocate()
local location loc
local real x1
local real y1
//
set this.K = K
set this.R = R
set this.xar = nj_I1D.create(0)
set this.yar = nj_I1D.create(0)
set this.map = GridCreate(R)
set this.rec = rec
return this
endmethod
method GenerateLocation takes real x0, real y0, real r returns location
local real xi_r = r*SquareRoot(GetRandomReal(0, 1)) + r
local real xi_phi = GetRandomReal(0, 2*bj_PI)
local real x = xi_r*Cos(xi_phi) + x0
local real y = xi_r*Sin(xi_phi) + y0
if(this.minX < x and x < this.maxX and /*
*/ this.minY < y and y < this.maxY)then
return Location(x, y)
else
return null
endif
endmethod
method GetFirst takes nothing returns location
local integer x = GetRandomInt(this.minX, this.maxX)
local integer y = GetRandomInt(this.minY, this.maxY)
return Location(I2R(x), I2R(y))
endmethod
static method GridCreate takes real r returns MatMap
local real DX = r/SquareRoot(2)
local real DY = r/SquareRoot(2)
local integer nx = math.floor(I2R(MatMap.maxX - MatMap.minX)/DX)+1
local integer ny = math.floor(I2R(MatMap.maxY - MatMap.minY)/DY)+1
return MatMap.create_fill(nx, ny, -1)
endmethod
method AddPointAnyWay takes real x, real y returns nothing
local integer i = this.map.mat_x2i(x)
local integer j = this.map.mat_y2j(y)
set this.map[i][j] = this.xar.shape_x
call this.xar.append(R2I(x))
call this.yar.append(R2I(y))
endmethod
method CheckCellFromPoint takes real x, real y, integer i, integer j returns boolean
local real rho
local integer k2
if(not(/*
*/ 0 <= i and i < this.map.shape_x and /*
*/ 0 <= j and j < this.map.shape_y))then
return true
endif
set k2 = this.map[i][j]
if (k2 != -1) then
set rho = math.rhoL2(x, y, I2R(this.xar[k2]),I2R(this.yar[k2]))
if (rho < this.R) then
return false
else
return true
endif
else
return true
endif
endmethod
method firststep takes nothing returns nothing
local location loc = this.GetFirst()
local real x1 = GetLocationX(loc)
local real y1 = GetLocationY(loc)
call RemoveLocation(loc)
call this.AddPointAnyWay(x1, y1)
endmethod
method generatefor takes integer k1 returns nothing
local integer k2
local location loc
local real x1 = this.xar[k1]
local real y1 = this.yar[k1]
local real x2
local real y2
local integer i
local integer j
local boolean bool
local real rho
set k2 = 0
loop
exitwhen(k2 == this.K)
set loc = GenerateLocation(x1, y1, this.R)
if(loc != null)then
set x2 = GetLocationX(loc)
set y2 = GetLocationY(loc)
set i = map.mat_x2i(x2)
set j = map.mat_y2j(y2)
if (map[i][j] == -1) then
set bool = true
if(/*
*/ not(this.CheckCellFromPoint(x2, y2, i-1, j )) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i-1, j+1)) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i, j+1)) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i+1, j+1)) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i+1, j )) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i+1, j-1)) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i, j-1)) or /*
*/ not(this.CheckCellFromPoint(x2, y2, i-1, j-1))) then
set bool = false
endif
if(bool)then
call this.AddPointAnyWay(x2, y2)
endif
endif
call RemoveLocation(loc)
endif
set k2 = k2 + 1
endloop
endmethod
method step takes integer k1 returns integer
local integer i = this.xar.shape_x
call generatefor.execute(k1)
return this.xar.shape_x - i
endmethod
static method Gen takes real R, integer K, rect rec returns thistype
local thistype this = thistype.create(R, K, rec)
local integer j = 0
call this.firststep()
loop
exitwhen(j == this.xar.shape_x)
call this.step(j)
set j = j + 1
endloop
return this
endmethod
static method onInit takes nothing returns nothing
endmethod
endstruct
struct QR
nj_I1D xar
nj_I1D yar
method SaveTest takes nothing returns nothing
local integer i = 0
local integer imax = this.xar.shape_x
call BJDebugMsg("Найдено точек " + I2S(imax))
loop
exitwhen(i == imax)
call CreateUnit(Player(0), 'hfoo', this.xar[i], this.yar[i], 0)
set i = i + 1
endloop
endmethod
method AddLocation takes integer x, integer y returns nothing
set this.xar[this.xar.shape_x] = x
set this.yar[this.yar.shape_x] = y
set this.xar.shape_x = this.xar.shape_x + 1
set this.yar.shape_x = this.yar.shape_x + 1
endmethod
method TakeLocation takes nothing returns location
local integer k
local location loc
if ( this.xar.shape_x != 0 ) then
set k = GetRandomInt(0, this.xar.shape_x-1)
set loc = Location(this.xar[k], this.yar[k])
set this.xar.shape_x = this.xar.shape_x - 1
set this.yar.shape_x = this.yar.shape_x - 1
set this.xar[k] = this.xar[this.xar.shape_x]
set this.yar[k] = this.yar[this.yar.shape_x]
return loc
else
return null
endif
endmethod
static method create takes real R, integer K, rect rec returns thistype
local thistype this = thistype.allocate()
local RB rb = RB.Gen(R, K, rec)
set this.xar = rb.xar
set this.yar = rb.yar
return this
endmethod
endstruct
endlibrary
library FrameTest initializer onInit uses MultidimensionalArray, WoodGrowMapLib
struct TextArea
private real dlm = 0
private real dh = 0.005
private static real bx = 0.01
private static real by = 0.01
framehandle backdrop
FrameHandle1D TextFrame
Real1D rx
Real1D ry
integer TextFrameCount
private method dl_refresh takes string s, real rx returns nothing
local real newdl = 0.006*I2R(StringLength(s)) - rx*(BlzFrameGetWidth(this.backdrop) - 2*this.bx)
if(this.dlm < newdl)then
set this.dlm = newdl
endif
endmethod
private method HideTextAreas takes nothing returns nothing
local integer i
set i = 0
loop
exitwhen(i == TextFrameCount)
call BlzFrameSetVisible(TextFrame[i], false)
set i = i + 1
endloop
endmethod
private method ShowTextAreas takes nothing returns nothing
local integer i
local real x
local real y
local real DX = BlzFrameGetWidth(this.backdrop)
local real DY = BlzFrameGetHeight(this.backdrop)
set i = 0
loop
exitwhen(i == TextFrameCount)
set x = (this.rx[i] - 0.5)*(DX - 2*this.bx-dlm) + dlm/2
set y = (0.5 - this.ry[i])*(DY - 2*this.by-dh) + dh/2
call BlzFrameSetPoint(TextFrame[i], FRAMEPOINT_TOPRIGHT, this.backdrop, FRAMEPOINT_CENTER, x, y)
call BlzFrameSetVisible(TextFrame[i], true)
set i = i + 1
endloop
endmethod
method setvisible takes boolean bvis returns nothing
call BlzFrameSetVisible(this.backdrop, bvis)
if(bvis)then
call this.ShowTextAreas()
else
call this.HideTextAreas()
endif
endmethod
method SetFrameText takes integer i, string s returns nothing
call BlzFrameSetVisible(TextFrame[i], false)
call BlzFrameSetText(TextFrame[i], "|cffffcc00"+ s +"|r")
call BlzFrameSetVisible(TextFrame[i], true)
endmethod
method AddText takes real rx, real ry, string s returns nothing
local framehandle frame
call dl_refresh(s, rx)
set frame = BlzCreateFrameByType("TEXT", "MyTextFrame", this.backdrop, "", 0)
call BlzFrameSetText(frame, "|cffffcc00"+ s +"|r")
call BlzFrameSetEnable(frame, false)
call BlzFrameSetScale(frame, 1)
call BlzFrameSetVisible(frame, false)
//
set this.rx[TextFrameCount] = rx
set this.ry[TextFrameCount] = ry
set TextFrame[TextFrameCount] = frame
set TextFrameCount = TextFrameCount + 1
endmethod
private static method CreateBackDrop takes real Width, real Height returns framehandle
local framehandle frame = BlzCreateFrame("QuestButtonDisabledBackdropTemplate", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0, 0)
call BlzFrameSetSize(frame, Width, Height)
call BlzFrameSetAbsPoint(frame, FRAMEPOINT_CENTER, 0.4, 0.35)
call BlzFrameSetVisible(frame, false)
return frame
endmethod
static method create takes nothing returns thistype
local thistype this = thistype.allocate()
set this.backdrop = thistype.CreateBackDrop(0.4, 0.4)
set this.TextFrame = FrameHandle2D.create()
set this.rx = Real1D.create()
set this.ry = Real1D.create()
set this.TextFrameCount = 0
return this
endmethod
endstruct
globals
private TextArea TA
private nj_I2D FT_map
endglobals
private function RefreshFrame takes nothing returns nothing
local integer i
local integer j
set i = 0
loop
exitwhen(i == FT_map.shape_x)
set j = 0
loop
exitwhen(j == FT_map.shape_y)
call TA.SetFrameText(i*FT_map.shape_y+j, I2S(FT_map[i][j]))
set j = j + 1
endloop
set i = i + 1
endloop
endfunction
private function CreateFrame takes nothing returns nothing
local integer i
local integer j
set FT_map = STML.StumpMap.map
set TA = TextArea.create()
set i = 0
loop
exitwhen(i == FT_map.shape_x)
set j = 0
loop
exitwhen(j == FT_map.shape_y)
call TA.AddText(I2R(i)/I2R(FT_map.shape_x-1), I2R(j)/I2R(FT_map.shape_y-1), I2S(FT_map[i][j]))
set j = j + 1
endloop
set i = i + 1
endloop
call TimerStart(CreateTimer(), 1.0, true, function RefreshFrame)
//call TimerStart(CreateTimer(), 0.6, true, function Refreshmap)
endfunction
private function Show takes nothing returns nothing
call TA.setvisible(true)
endfunction
private function Hide takes nothing returns nothing
call TA.setvisible(false)
endfunction
private function onInit takes nothing returns nothing
local trigger trg1 = CreateTrigger()
local trigger trg2 = CreateTrigger()
call TimerStart(CreateTimer(),1.0,false, function CreateFrame)
//
call TriggerRegisterPlayerChatEvent( trg1, Player(0), "show", true )
call TriggerAddAction(trg1, function Show)
//
call TriggerRegisterPlayerChatEvent( trg2, Player(0), "hide", true )
call TriggerAddAction(trg2, function Hide)
endfunction
endlibrary
library WoodGrowMapLib initializer onInit uses MatMapLib, numjass
struct WGM
// ====
static integer maxdens
static MatMap TreesMap
// ====
static method RemoveTree4Map takes real x, real y returns boolean
local integer i = WGM.TreesMap.mat_x2i(x)
local integer j = WGM.TreesMap.mat_y2j(y)
if(WGM.TreesMap.map[i][j] > 0) then
set WGM.TreesMap.map[i][j] = WGM.TreesMap.map[i][j] - 1
return true
else
//call BJDebugMsg("Мало дерева в " + I2S(i) + " " + I2S(j))
return false
endif
return false
endmethod
static method AddTree2MapAnyway takes real x, real y returns nothing
local integer i = WGM.TreesMap.mat_x2i(x)
local integer j = WGM.TreesMap.mat_y2j(y)
set WGM.TreesMap.map[i][j] = WGM.TreesMap.map[i][j] + 1
endmethod
static method AddTree2Map takes real x, real y returns boolean
local integer i = WGM.TreesMap.mat_x2i(x)
local integer j = WGM.TreesMap.mat_y2j(y)
if(WGM.TreesMap.map[i][j] < maxdens) then
set WGM.TreesMap.map[i][j] = WGM.TreesMap.map[i][j] + 1
return true
else
return false
endif
return false
endmethod
static method SetMaxDens takes integer value returns nothing
set thistype.maxdens = value
endmethod
private static method onInit takes nothing returns nothing
set WGM.TreesMap = MatMap.create_large()
set thistype.maxdens = 24
endmethod
endstruct
endlibrary
library StumpMapLib initializer onInit uses MatMapLib, numjass
struct STML
// ====
static integer maxdens
static MatMap StumpMap
// ====
static method RemoveStump4Map takes real x, real y returns boolean
local integer i = STML.StumpMap.mat_x2i(x)
local integer j = STML.StumpMap.mat_y2j(y)
if(STML.StumpMap.map[i][j] > 0) then
set STML.StumpMap.map[i][j] = STML.StumpMap.map[i][j] - 1
return true
else
call BJDebugMsg("Критически мало пней в " + I2S(i) + " " + I2S(j))
return false
endif
return false
endmethod
static method AddStump2MapAnyway takes real x, real y returns nothing
local integer i = STML.StumpMap.mat_x2i(x)
local integer j = STML.StumpMap.mat_y2j(y)
set STML.StumpMap.map[i][j] = STML.StumpMap.map[i][j] + 1
endmethod
static method AddStump2Map takes real x, real y returns boolean
local integer i = STML.StumpMap.mat_x2i(x)
local integer j = STML.StumpMap.mat_y2j(y)
if(STML.StumpMap.map[i][j] < maxdens) then
set STML.StumpMap.map[i][j] = STML.StumpMap.map[i][j] + 1
return true
else
return false
endif
return false
endmethod
static method GetExcess takes real x, real y returns boolean
return STML.StumpMap.map[STML.StumpMap.mat_x2i(x)][STML.StumpMap.mat_y2j(y)] > maxdens
endmethod
static method SetMaxDens takes integer value returns nothing
set thistype.maxdens = value
endmethod
private static method onInit takes nothing returns nothing
set STML.StumpMap = MatMap.create_large()
set thistype.maxdens = 1
endmethod
endstruct
endlibrary
library WoodGrowLib initializer onInit uses optional WoodGrowMapLib, numjass, optional StumpMapLib
/*
======= Добавление стороннего дерева в систему ======================================
function WGL.addOutTree takes destructable NewTree returns boolean
======= Установка времени между итрециями роста =====================================
function WGL.SetGrowTime takes real NewTime returns nothing
====== Получение времени между итерациями ===========================================
function WGL.GetGrowTime takes nothing returns real
====== Функция добавления нового типа деревьев в систему ============================
function WGL.addTreeType takes integer objectid, integer shapex, integer shapey,
integer sw, real smin, real smax, rect r returns nothing
// objectid - id типа разрушаемого объекта - дерева
// shapex - размер по x формы карты путей дерева
// shapey - размер по y формы карты путей дерева
// sw - статистический вес дерева
// smin - минимальный масштаб дерева
// smax - максимальный масштаб дерева
// r - область возможног появления дерева
*/
globals
//Хэштаблица
private hashtable hash
endglobals
private function SaveCoords takes destructable tree, integer x, integer y returns nothing
call SaveBoolean(hash, GetHandleId(tree), 0, true)
call SaveInteger(hash, GetHandleId(tree), 1, x)
call SaveInteger(hash, GetHandleId(tree), 2, y)
endfunction
private function GetX takes destructable tree returns integer
if(LoadBoolean(hash, GetHandleId(tree), 0)) then
return LoadInteger(hash, GetHandleId(tree), 1)
else
return R2I(GetDestructableX(tree))
endif
endfunction
private function GetY takes destructable tree returns integer
if(LoadBoolean(hash, GetHandleId(tree), 0)) then
return LoadInteger(hash, GetHandleId(tree), 2)
else
return R2I(GetDestructableY(tree))
endif
endfunction
private function FlushCoords takes destructable tree returns nothing
call FlushChildHashtable(hash, GetHandleId(tree))
endfunction
hook RemoveDestructable FlushCoords
private struct TreeType
integer skinID
integer rminx
integer rmaxx
integer rminy
integer rmaxy
real smin
real smax
integer shx
integer shy
integer sw
static integer swsum
static integer count
//
static method GetRandomType takes nothing returns thistype
local integer swrem = thistype.swsum
local integer statint = GetRandomInt(1, swrem)
local thistype this = 1
loop
set swrem = swrem - this.sw
exitwhen(statint > swrem)
set this = this + 1
endloop
return this
endmethod
//
// Функция получение случайной координаты x в зависимости от формы карты путей
private method GetRandomX takes nothing returns integer
local integer randi = GetRandomInt(0, 1)
if (this.shx == 1)then
if (randi == 1) then
return 16 + 64*GetRandomInt(0, this.rmaxx)
else
return -16 + 64*GetRandomInt(this.rminx, 0)
endif
elseif (this.shx == 2) then
if(randi == 1)then
return 32 + 64*GetRandomInt(0, this.rmaxx)
else
return -32 + 64*GetRandomInt(this.rminx, 0)
endif
elseif(this.shx == 3)then
if(randi == 1)then
return 48 + 64*GetRandomInt(0, this.rmaxx)
else
return -48 + 64*GetRandomInt(this.rminx, 0)
endif
elseif(this.shx == 4)then
return 64*GetRandomInt(this.rminx, this.rmaxx)
endif
return 0
endmethod
//
// Функция получение случайной координаты y в зависимости от формы карты путей
private method GetRandomY takes nothing returns integer
local integer randi = GetRandomInt(0, 1)
if (this.shy == 1)then
if (randi == 1) then
return 16 + 64*GetRandomInt(0, this.rmaxy)
else
return -16 + 64*GetRandomInt(this.rminy, 0)
endif
elseif (this.shy == 2) then
if(randi == 1)then
return 32 + 64*GetRandomInt(0, this.rmaxy)
else
return -32 + 64*GetRandomInt(this.rminy, 0)
endif
elseif(this.shy == 3)then
if(randi == 1)then
return 48 + 64*GetRandomInt(0, this.rmaxy)
else
return -48 + 64*GetRandomInt(this.rminy, 0)
endif
elseif(this.shy == 4)then
return 64*GetRandomInt(this.rminy, this.rmaxy)
endif
return 0
endmethod
//
/*Создание дерева случайного варианта
в случайном месте и возвращение указателя на него*/
static method CreateRandomTree takes nothing returns destructable
local thistype this = thistype.GetRandomType()
local integer x = this.GetRandomX()
local integer y = this.GetRandomY()
local real scale = GetRandomReal(this.smin, this.smax)
local integer skin_var = GetRandomInt(0, 9)
local real face = GetRandomReal(0, 360)
local destructable tree
static if LIBRARY_WoodGrowMapLib then
if (WGM.AddTree2Map(x, y)) then
set tree = CreateDestructable(this.skinID, I2R(x), I2R(y), face, scale, skin_var)
else
return null
endif
else
set tree = CreateDestructable(this.skinID, I2R(x), I2R(y), face, scale, skin_var)
endif
call SaveCoords(tree, x, y)
return tree
endmethod
//
// ==== Инициализация нового типа дерева
static method create takes integer objectid, integer shx, integer shy, integer sw, real smin, real smax, rect r returns thistype
local thistype this = thistype.allocate()
set this.skinID = objectid
set this.shx = shx
set this.shy = shy
set this.sw = sw
set this.smin = smin
set this.smax = smax
set this.rmaxx = R2I((GetRectMaxX(r) - shx*16.0)/64.0)
set this.rminx = R2I((GetRectMinX(r) + shx*16.0)/64.0)
set this.rmaxy = R2I((GetRectMaxY(r) - shy*16.0)/64.0)
set this.rminy = R2I((GetRectMinY(r) + shy*16.0)/64.0)
set this.swsum = this.swsum + sw
return this
endmethod
//
// ==== Инициализация структуры вариантов деревьев ====
private static method onInit takes nothing returns nothing
set thistype.swsum = 0
set thistype.count = 0
endmethod
endstruct
struct WGL extends array
// Настраевыемые параметры
static integer TreesMax // Максимальный размер массива деревьев
static integer StumpsMax // Максимальный размер массива пеньков
static integer GrowTreeNum // Число деревьев за итеррацию
private static real Grow_Time // Время между итерациями роста
// Техниеские переменные
private static timer GrowTimer // Таймер роста
private static timer SuperviseTimer // Таймер супервизии
private static real SuperviseTime // Время между супервизими
private static integer SuperviseDelta // Число проверок на супервизию
// Массивы
private static integer CurArray // Указатель на текущий массив
private static destructable array Trees1 // Массив деревьев 1
private static integer Trees1Count // Счетчик числа массива деревьев 1
private static destructable array Trees2 // Массив деревьев 2
private static integer Trees2Count // Счетчик числа массива 2 деревьев
private static destructable array Stumps // Массив пеньков
private static integer StumpsCount // Размер массива пеньков
// Указатели
private static integer StumpPoint // Указатель на положение курсора в массиве пеньков
private static integer TreePoint // Указатель на положение курсора супервизии деревьев
// Счетчики супервизии
private static integer newStumpCount // Число новых пеньков найденных при супервизии
private static integer newTreeCount // Счетчик новых деревьев в цикле между переворотом массивов
//
// ==== Добавление нового варианта деревьев ===========================
static method addTreeType takes/*
*/ integer treeID, /* objectid - id типа разрушаемого объекта - дерева
*/ integer shapex, /* shapex - размер по x формы карты путей дерева
*/ integer shapey, /* shapey - размер по y формы карты путей дерева
*/ integer sw, /* sw - статистический вес
*/ real smin, /* smin - минимальный масштаб
*/ real smax, /* smax - максимальный масштаб
*/ rect r /* r - область возможного появления дерева
*/returns nothing
call TreeType.create(treeID, shapex, shapey, sw, smin, smax, r)
endmethod
//
// ==== Функция возращающая дерево текущего массива ====================
private static method GetCurTree takes integer j returns destructable
if(WGL.CurArray == 1) then
return WGL.Trees1[j]
else
return WGL.Trees2[j]
endif
endmethod
//
// ==== Функция возвращающая дерево старого массива
private static method GetPastTree takes integer j returns destructable
if(WGL.CurArray == 1) then
return WGL.Trees2[j]
else
return WGL.Trees1[j]
endif
endmethod
//
// ==== Функция возращающая счетчик текущего массива =====
private static method GetCurCount takes nothing returns integer
if (WGL.CurArray == 1) then
return WGL.Trees1Count
elseif (WGL.CurArray == 2) then
return WGL.Trees2Count
endif
call BJDebugMsg("Ошибка теущего массива " + I2S(WGL.CurArray))
return -1
endmethod
//
//
static method GetTreesCount takes nothing returns integer
return WGL.GetPastCount() - WGL.newTreeCount
endmethod
//
// ==== Функция возращающая счетчик старого массива
private static method GetPastCount takes nothing returns integer
if (WGL.CurArray == 2) then
return WGL.Trees1Count
elseif (WGL.CurArray == 1) then
return WGL.Trees2Count
endif
call BJDebugMsg("Ошибка теущего массива " + I2S(WGL.CurArray))
return -1
endmethod
//
// ==== Фунция смены текущего и старого массива на противоположные
private static method TAStatusChange takes nothing returns nothing
if (WGL.CurArray == 1) then
set WGL.CurArray = 2
//call debug BJDebugMsg("Смена статусов. Число деревьев: " + I2S(udg_TreesCount))
set WGL.Trees2Count = 0
return
elseif (WGL.CurArray == 2) then
set WGL.CurArray = 1
//call debug BJDebugMsg("Смена статусов. Число деревьев: " + I2S(udg_Trees1Count))
set WGL.Trees1Count = 0
return
endif
call BJDebugMsg("Ошибка теущего массива " + I2S(WGL.CurArray))
endmethod
//
// ==== Функция добавления элемента в текущий массив без проверки на превышение максимума
private static method addTreeAnyWay takes destructable NewTree returns nothing
if (WGL.CurArray == 1) then
set WGL.Trees1[WGL.Trees1Count] = NewTree
set WGL.Trees1Count = WGL.Trees1Count + 1
elseif (WGL.CurArray == 2) then
set WGL.Trees2[WGL.Trees2Count] = NewTree
set WGL.Trees2Count = WGL.Trees2Count + 1
endif
endmethod
//
// ==== Добавление стороннего дерева в систему ======
static method addOutTree takes destructable NewTree returns boolean
if(WGL.TreesMax - WGL.GetPastCount() - WGL.newTreeCount + WGL.newStumpCount > 0) then
call WGL.addTreeAnyWay(NewTree)
set WGL.newTreeCount = WGL.newTreeCount + 1
static if LIBRARY_WoodGrowMapLib then
call WGM.AddTree2MapAnyway(GetX(NewTree), GetY(NewTree))
endif
return true
else
// Массив переполнен
return false
endif
endmethod
//
/*Если массив пеньков заполнен,
удаление старого пенька по указателю кругового массива пеньков и
змена его на новый пенек */
private static method addStump_FilledArray takes destructable NewStump returns nothing
/*Поверка, стал ли пенек,
который уже был в массиве ранее деревом, по указателю массива пеньков*/
local destructable PointStump = WGL.Stumps[WGL.StumpPoint]
static if LIBRARY_StumpMapLib then
call STML.RemoveStump4Map(GetX(PointStump), GetY(PointStump))
endif
if(GetDestructableLife(PointStump) > 0) then
//Если пенек стал деревом, попытка его добавить в массив деревьев
if(WGL.addOutTree(PointStump))then
call RemoveDestructable(PointStump) // удалить если не получилось
endif
else
// Если пень не ожил, то удаление пенька
call RemoveDestructable(PointStump)
endif
/* В любом случае,
запись нового пня на место по указателю */
set WGL.Stumps[WGL.StumpPoint] = NewStump
if(WGL.StumpPoint >= WGL.StumpsMax - 1) then
set WGL.StumpPoint = 0
else
set WGL.StumpPoint = WGL.StumpPoint + 1
endif
// debug call BJDebugMsg("Успешная перезапись пня")
endmethod
//
// ====== Добавление пенька в массив пней ======
static method addStump takes destructable NewStump returns nothing
static if LIBRARY_WoodGrowMapLib then
call WGM.RemoveTree4Map(GetX(NewStump), GetY(NewStump))
endif
static if LIBRARY_StumpMapLib then
call STML.AddStump2MapAnyway(GetX(NewStump), GetY(NewStump))
endif
if( WGL.StumpsCount >= WGL.StumpsMax ) then
/*Если массив пеньков заполнен*/
call WGL.addStump_FilledArray(NewStump)
else
/*Есть место в массиве пеньков, то заполнение массива пеньков*/
set WGL.Stumps[WGL.StumpsCount] = NewStump
set WGL.StumpsCount = WGL.StumpsCount + 1
endif
endmethod
//
// ====== Обновленние супервизии ======
private static method SuperviseRefresh takes nothing returns nothing
// debug call BJDebugMsg("При супервизии найденно пеньков: " + I2S(udg_newStumpCount))
call WGL.TAStatusChange()
set WGL.TreePoint = 0
set WGL.newStumpCount = 0
set WGL.newTreeCount = 0
endmethod
/* ====== Функция супервизии =========================
Функция проверки масива деревьев на появившиеся пеньки
и набора массива пеньков и его перетасовки
*/
private static method TreeSupervise takes nothing returns nothing
local integer TP = WGL.TreePoint
local integer PastCount = WGL.GetPastCount()
local destructable Tree
loop
exitwhen( (TP == PastCount) or (TP - WGL.TreePoint == WGL.SuperviseDelta) )
set Tree = WGL.GetPastTree(TP)
if (GetDestructableLife(Tree) <= 0) then
call WGL.addStump(Tree)
set WGL.newStumpCount = WGL.newStumpCount + 1
else
call WGL.addTreeAnyWay(Tree)
endif
set TP = TP + 1
endloop
if(TP == PastCount)then
call WGL.SuperviseRefresh()
else
set WGL.TreePoint = TP
endif
endmethod
static if LIBRARY_StumpMapLib then
private static method StumpSupervise takes nothing returns nothing
local integer i = GetRandomInt(1, WGL.StumpsCount) - 1
local destructable Stump = Stumps[i]
if(GetDestructableLife(Stump) <= 0 and Stump != null) then
if(STML.GetExcess(GetX(Stump), GetY(Stump)))then
call STML.RemoveStump4Map(GetX(Stump), GetY(Stump))
set WGL.StumpsCount = WGL.StumpsCount - 1
if(WGL.StumpsCount != i)then
set Stumps[i] = Stumps[WGL.StumpsCount]
endif
call RemoveDestructable(Stump)
endif
endif
endmethod
endif
//
// ====== Функция внедряющая дерево в систему ===========
private static method SystemTreeCreate takes nothing returns nothing
local destructable Tree
if ( WGL.TreesMax - WGL.GetPastCount() - WGL.newTreeCount + WGL.newStumpCount > 0 ) then
//Создание нового дерева и запись его в текущий массив
set Tree = TreeType.CreateRandomTree()
if (Tree != null) then
call WGL.addTreeAnyWay(Tree)
set WGL.newTreeCount = WGL.newTreeCount + 1
set Tree = null
endif
endif
endmethod
//
// ====== Инициализация супервизии =====================
private static method SuperviseStart takes nothing returns nothing
set WGL.SuperviseTimer = CreateTimer()
//debug call BJDebugMsg("Инициализация супервизии")
set WGL.TreePoint = 0
set WGL.newStumpCount = 0
set WGL.newTreeCount = 0
call TimerStart(WGL.SuperviseTimer, WGL.SuperviseTime , true, function WGL.TreeSupervise)
static if LIBRARY_StumpMapLib then
call TimerStart(CreateTimer(), 0.05, true, function WGL.StumpSupervise)
endif
endmethod
//
// ====== Переодическая функция создания деревьев ==============
private static method PereodicTreeCreate takes nothing returns nothing
local integer i = 0
loop
exitwhen(i == WGL.GrowTreeNum)
call WGL.SystemTreeCreate()
set i = i + 1
endloop
endmethod
//
//
static method operator GrowTime takes nothing returns real
return WGL.Grow_Time
endmethod
//
// ====== Изменение времени между итрециями роста =============
static method operator GrowTime= takes real NewTime returns nothing
if(WGL.GrowTimer != null) then
call DestroyTimer(WGL.GrowTimer)
set WGL.Grow_Time = NewTime
set WGL.GrowTimer = CreateTimer()
call TimerStart(WGL.GrowTimer, WGL.Grow_Time ,true,function WGL.PereodicTreeCreate)
else
set WGL.Grow_Time = NewTime
endif
endmethod
//
// ====== Функция, которая начинает рост деревьев ==============
static method GrowStart takes nothing returns nothing
set WGL.GrowTimer = CreateTimer()
call TimerStart(WGL.GrowTimer, WGL.Grow_Time , true, function WGL.PereodicTreeCreate)
call WGL.SuperviseStart()
endmethod
//
// ==== Инициализция системы ====
private static method onInit takes nothing returns nothing
set WGL.TreesMax = 30000 // Установка максимального числа деревьев
set WGL.StumpsMax = 5000 // Установка максимального кол-ва пеньков
set WGL.Grow_Time = 0.05 // Время между итерациями роста
set WGL.GrowTreeNum = 1
//
set WGL.GrowTimer = null
set WGL.SuperviseTime = 0.1
set WGL.SuperviseDelta = 100
//
set WGL.Trees1Count = 0
set WGL.Trees2Count = 0
set WGL.CurArray = 1
set WGL.StumpsCount = 0
//
set WGL.StumpPoint = 0
set WGL.TreePoint = 0
//
set WGL.newStumpCount = 0
set WGL.newTreeCount = 0
//
set hash = InitHashtable()
endmethod
endstruct
endlibrary
library MultidimensionalArray /* v1.2b
*/uses /*
*/Table /* http://www.hiveworkshop.com/threads/snippet-new-table.188084/
[Resource Link] - http://www.hiveworkshop.com/threads/snippet-multidimensional-array.289785/
*///! novjass
/* This snippet allows you to have array storage. Unlike default arrays, you can use an index beyond 8190
since this snippet uses Tables which uses hashtable. Therefore, saving data with a really large index
such as using GetHandleId(handle) as the index would not be a problem.
But you may ask, why would we want to use this when there is already the Table library which can support
any type that we want to store? First, this has a feature which supports multidimensions that allows you
to have up to 5-dimensional array. Table already allows you to create multidimensional storage if you do
proper nesting but this library removes the need for users to do it on their own and this also helps set
a standard instead of having redundant scripts that work for the same puspose. Secondly, unlike Table,
this implements a type specific storage i.e., you can create an array storage that is only exclusive for
a specific type but of course, this also provides a generic storage like Table but with a nicer API.
Furthermore, this includes some safety precautions such as compile time safety which throws an error if
you're using an incorrect number of dimensions, as well as preventing the use of an Array instance which
isn't allocated in DEBUG_MODE. lastly, this gives users a nice and intuitive syntax which resembles that
of the original vanilla Jass arrays (call KillUnit(u[1][3])) without having a need for an ugly keyword
at the end (ex: call KillUnit(u[1].unit[3])). */
|=========|
| Credits |
|=========|
/* AGD : Author
Bribe : For the Table library, and for the algorithm of making n-dimensional storage by nesting Tables */
|-----|
| API |
|-----|
Creating an Array:
/* Creates a new array for a specific type */
local Unit1D u = Array.create()
local Unit3D u3 = Unit3D.create()
local Unit5D u5 = Timer4D.create() //You could actually use any of the dimensional array creator
local Array4D a4 = Array.create()
Storing inside an Array:
/* Stores data inside an array */
set u[GetHandleId(timer)] = GetTriggerUnit()
set u3[0x2000]['AAAA'] = GetTriggerUnit() //Syntax error: number of indexes does not match with the number of dimensions
set u5[1][2][3][4][5] = GetTriggerUnit()
set a4[1][2][3][4].unit = GetTriggerUnit()
Retrieving from an Array:
/* Retrieves data from an array */
call KillUnit(u[1234567])
call KillUnit(u3['A']['B']['C'])
call KillUnit(u5[1][2][3][4]) //Syntax error: number of indexes does not match with the number of dimensions
call KillUnit(a4[1][2][3][4].unit)
Checking storage vacancy:
/* Checks if there is data stored inside an array index */
return u.has(index) //Similar to Table(u).unit.has(index)
return u3[1][2].has(3)
return u5[1].has(2) //Checks if the fourth dimension has index 2
return a4[1][2][3].hasHandle(4)
Removing an Array index:
/* Destroys the table instance of an index and clears all its child nodes if there are any */
call u.remove(1)
call u3[1].remove(2)
call u5[1][2][3][4][5].remove(6) //Syntax error: cannot use remove() on a node which has no children
call a4[1][2][3].removeHandle(4)
Flushing an Array Index:
/* Flushes all child nodes attached to the specific index */
call u.flush() //Flushes all data inside the array, analogous to flushing a parent hashtable
call u3[1][2][3].flush() //Syntax error: cannot clear a node which has no children, use u3[1][2].remove(3) instead
call u5[1][2].flush() //Flushes all child nodes attached to the index "2" of the second dimension
call a4[1][2].flush()
Destroying an Array:
/* Destroys an array instance, flushing all data inside it */
call u.destroy()
call u3.destroy()
call u5[1].destroy() //If destroy() is called upon a node which is not a root node, it will work like clear() instead
call a4.destroy()
//! endnovjass
static if DEBUG_MODE then
private struct S extends array
static key allocated
endstruct
private function Debug takes string msg returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "|CFFFFCC00[MultidimensionalArray] |R" + msg)
endfunction
endif
private function AllocateIndex takes integer this, integer index returns integer
debug if not Table(S.allocated).boolean[this] then
debug return 0
debug endif
debug set Table(S.allocated).boolean[HashTable(this)[index]] = true
return HashTable(this)[index]
endfunction
/*============= For a uniform allocator syntax =) ==============*/
struct Array extends array
static method create takes nothing returns thistype
static if DEBUG_MODE then
local Table t = Table.create()
set Table(S.allocated).boolean[t] = true
return t
else
return Table.create()
endif
endmethod
endstruct
/*==============================================================*/
/*====================== Struct methods ========================*/
private module Methods
static method create takes nothing returns thistype
return Array.create()
endmethod
static if not thistype.remove.exists then
method remove takes integer index returns nothing
call HashTable(this).remove(index)
endmethod
endif
static if not thistype.has.exists then
method has takes integer index returns boolean
return HashTable(this).has(index)
endmethod
endif
method flush takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
debug set Table(S.allocated).boolean[this] = false
endmethod
endmodule
/*==============================================================*/
/*================= Generic Type Array Storage =================*/
private struct Type extends array
static key index
method operator agent= takes agent value returns nothing
debug if not Table(S.allocated).boolean[this] then
debug call Debug("|CFFFF0000[Operator agent= ERROR] : Attempted to use a non-allocated array instance|R")
debug return
debug endif
set Table(this).agent[Table(this)[index]] = value
endmethod
//! textmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS takes TYPE
method operator $TYPE$ takes nothing returns $TYPE$
return Table(this).$TYPE$[Table(this)[index]]
endmethod
method operator $TYPE$= takes $TYPE$ value returns nothing
debug if not Table(S.allocated).boolean[this] then
debug call Debug("|CFFFF0000[Operator $TYPE$= ERROR] : Attempted to use a non-allocated array instance|R")
debug return
debug endif
set Table(this).$TYPE$[Table(this)[index]] = value
endmethod
//! endtextmacro
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("integer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("real")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("string")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("boolean")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("player")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("widget")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("destructable")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("item")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("unit")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("ability")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("timer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("trigger")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("triggercondition")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("triggeraction")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("event")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("force")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("group")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("location")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("rect")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("boolexpr")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("sound")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("effect")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("unitpool")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("itempool")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("quest")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("questitem")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("defeatcondition")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("timerdialog")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("leaderboard")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("multiboard")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("multiboarditem")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("trackable")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("dialog")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("button")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("texttag")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("lightning")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("image")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("ubersplat")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("region")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("fogstate")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("fogmodifier")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_OPERATORS("hashtable")
endstruct
struct Array1D
//! textmacro GENERIC_DIMENSIONAL_ARRAY_METHODS takes NAME, TYPE
method has$NAME$ takes integer index returns boolean
return Table(this).$TYPE$.has(index)
endmethod
method remove$NAME$ takes integer index returns nothing
call Table(this).$TYPE$.remove(index)
endmethod
//! endtextmacro
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Integer", "integer")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Real", "real")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("String", "string")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Boolean", "boolean")
//! runtextmacro GENERIC_DIMENSIONAL_ARRAY_METHODS("Handle", "handle")
method has takes integer index returns boolean
return .hasInteger(index) /*
*/or .hasReal(index) /*
*/or .hasString(index) /*
*/or .hasBoolean(index) /*
*/or .hasHandle(index)
endmethod
method remove takes integer index returns nothing
call .removeInteger(index)
call .removeReal(index)
call .removeString(index)
call .removeBoolean(index)
call .removeHandle(index)
endmethod
implement Methods
method operator [] takes integer index returns Type
debug if not Table(S.allocated).boolean[this] then
debug return 0
debug endif
set Table(this)[Type.index] = index
return this
endmethod
endstruct
//! textmacro NEW_DIMENSIONAL_ARRAY_STRUCT takes DIM, RETURNED
struct Array$DIM$D extends array
implement Methods
method operator [] takes integer index returns Array$RETURNED$D
return AllocateIndex(this, index)
endmethod
endstruct
//! endtextmacro
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("2", "1")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("3", "2")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("4", "3")
//! runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("5", "4")
// If you want to increase the maximum number of available
// dimensions, just run the textmacros above once again like:
// runtextmacro NEW_DIMENSIONAL_ARRAY_STRUCT("LAST_MAX_DIM + 1", "LAST_MAX_DIM")
/*==============================================================*/
/*================ Type Specific Array Storage =================*/
//! textmacro NEW_DIMENSIONAL_ARRAY takes NAME, TYPE
struct $NAME$1D
method remove takes integer index returns nothing
call Table(this).$TYPE$.remove(index)
endmethod
method has takes integer index returns boolean
return Table(this).$TYPE$.has(index)
endmethod
implement Methods
method operator [] takes integer index returns $TYPE$
return Table(this).$TYPE$[index]
endmethod
stub method operator []= takes integer index, $TYPE$ value returns nothing
//debug if not Table(S.allocated).boolean[this] then
// debug call Debug("|CFFFFCC00[ArrayType: $NAME$]|R |CFFFF0000[Operator []= ERROR] : Attempted to use a non-allocated array instance|R")
// debug return
//debug endif
set Table(this).$TYPE$[index] = value
endmethod
endstruct
struct $NAME$2D
implement Methods
method operator [] takes integer index returns $NAME$1D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$3D
implement Methods
method operator [] takes integer index returns $NAME$2D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$4D
implement Methods
method operator [] takes integer index returns $NAME$3D
return AllocateIndex(this, index)
endmethod
endstruct
struct $NAME$5D
implement Methods
method operator [] takes integer index returns $NAME$4D
return AllocateIndex(this, index)
endmethod
endstruct
//! endtextmacro
// If you want to increase the maximum number of available
// dimensions, just copy the last struct above and increase the
// number of dimension in the struct name and the returned struct
// of the operator [] by 1.
/*==============================================================*/
/*======== Implement textmacros for every storage type =========*/
//! runtextmacro NEW_DIMENSIONAL_ARRAY("FrameHandle", "framehandle")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Integer", "integer")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Real", "real")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Str", "string")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Boolean", "boolean")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Player", "player")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Widget", "widget")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Item", "item")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Unit", "unit")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Ability", "ability")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Timer", "timer")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Force", "force")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Group", "group")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Location", "location")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Rect", "rect")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Sound", "sound")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Effect", "effect")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Quest", "quest")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Button", "button")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Image", "image")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Region", "region")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_DIMENSIONAL_ARRAY("Hashtable", "hashtable")
/*==============================================================*/
endlibrary
library Table /* made by Bribe, special thanks to Vexorian & Nestharus, version 6
One map, one hashtable, one Table struct.
Version 6 combines multi-dimensional Tables, TableArray, HandleTable and StringTable into...
...Table.
What's changed? What does the API look like now? Read on to find out:
Universal Table operations:
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| flush and destroy the Table.
|
| NOTE: this method incorporates the former TableArray.flush() method.
|
| method flush takes nothing returns nothing
| Erase all saved values inside of the Table
|
| NOTE: This does not flush all parallel instances in a forked Table.
| It only flushes the current Table instance.
|
| static method createFork takes integer width returns Table
| creates a Table that is a negative integer rather than positive one.
|
| NOTE: formerly, this was `static method operator []` on TableArray.
|
| method switch takes integer offset returns Table
| switches from the current Table to any offset between 0 and 'width - 1'
|
| NOTE: formerly, this was `method operator []` on TableArray.
|
| NOTE: Only works with Tables created as forks.
|
| method measureFork takes nothing returns integer
| returns the number passed to `createFork`.
| formerly, this was `method size` on TableArray.
|
| method getKeys takes nothing returns Table
| returns a readonly Table containing:
| [0] - the number of tracked keys in the Table
| [1->number of keys] - contiguous list of keys found inside of the Table.
| Effectively combines Object.keys(obj) from JavaScript with 1-based arrays of Lua.
|
| -> How to iterate to access values:
|
| local Table keys = myTable.getKeys()
| local integer i = keys[0]
| loop
| exitwhen i == 0
| call BJDebugMsg("My value is: " + I2S(myTable[keys[i]]))
| set i = i - 1
| endloop
|
Standard Table operations (store Tables or integers against integer keys):
| method operator [] takes integer key returns Table
| load the value at index `key`
|
| method operator []= takes integer key, Table value returns nothing
| assign "value" to index `key` without tracking it. Like `rawset` in Lua.
|
| method remove takes integer key returns nothing
| remove the value at index `key`
|
| method has takes integer key returns boolean
| whether or not `key` has been assigned
|
| method save takes integer key, Table value returns Table
| a new method to not just add the value to the Table, but to also track it.
| Returns `this` Table, so `save` calls can be daisy-chained.
|
Multi-Dimensional Table operations (store nested Tables against integer keys):
| method link takes integer key returns Table
| Checks if a Table already exists at the key, and creates one if not.
|
| Note: Formerly, you needed to create a Table2/3/4/5D/T to access this method.
| Note: Can be substituted for `[]` if you are certain that the key is set.
|
| Note: Links are all tracked by default. To avoid the extra tracking behavior,
| you can either use a static Table (`struct.typeid` or `key`) or you can
| use Table.createFork(1) instead of Table.create() or
| myTable.forkLink(1, key) instead of myTable.link(key)
|
| method forkLink takes integer width, integer key returns Table
| Checks if a Fork already exists at the key, and creates one with the chosen size if not.
HandleTable operations (store Tables against handle keys):
| method operator get takes handle key returns Tables
| Alias for `[]`
|
| method operator store takes handle key, Table value returns Table
| Alias for `save`
|
| method forget takes handle key returns nothing
| Alias for `remove`
|
| method stores takes handle key returns boolean
| Alias for `has`
|
| method bind takes handle key returns Table
| Alias for `link`
|
| method forkBind takes handle key returns Table
| Alias for `forkLink`
StringTable operations (store Tables against string keys):
| method operator read takes string key returns Table
| Alias for `[]`
|
| method operator write takes string key, Table value returns Table
| Alias for `save`
|
| method delete takes string key returns nothing
| Alias for `remove`
|
| method written takes string key returns boolean
| Alias for `has`
|
| method join takes string key returns Table
| Alias for `link`
|
| method forkJoin takes string key returns Table
| Alias for `forkLink`
Tables that store non-integer/Table values can access the `standard` Table API just by using .type syntax:
| myTable.unit[5] = GetTriggerUnit()
| myTable.unit.save(10, GetTriggerUnit())
| myTable.unit.store(GetAttacker(), GetTriggerUnit())
| myTable.unit.write("whatever you want", GetTriggerUnit())
|
| myTable.handle.remove(10)
| myTable.handle.forget(GetAttacker())
| myTable.handle.delete("whatever you want")
|
| local string s = myTable.string[15]
| local string t = myTable.string.get(GetSpellTargetUnit())
| local string u = myTable.string.read("something you want")
|
| local boolean b = myTable.string.has(15)
| local boolean c = myTable.string.stores(GetSpellTargetUnit())
| local boolean d = myTable.string.written("something you want")
*/ requires optional Table5BC, optional TableVBC
globals
private integer tableKeyGen = 8190 //Index generation for Tables starts from here. Configure it if your map contains more than this many structs or 'key' objects.
private hashtable hashTable = InitHashtable() // The last hashtable.
private constant boolean TEST = false // set to `true` to enable error messages and `print`/`toString` API.
private constant boolean DEEP_TEST = false // set to `true` to enable informational messages.
private keyword addKey
private keyword addTypedKey
private keyword IntegerModule
private keyword RealModule
private keyword BooleanModule
private keyword StringModule
private keyword PlayerModule
private keyword WidgetModule
private keyword DestructableModule
private keyword ItemModule
private keyword UnitModule
private keyword AbilityModule
private keyword TimerModule
private keyword TriggerModule
private keyword TriggerConditionModule
private keyword TriggerActionModule
private keyword TriggerEventModule
private keyword ForceModule
private keyword GroupModule
private keyword LocationModule
private keyword RectModule
private keyword BooleanExprModule
private keyword SoundModule
private keyword EffectModule
private keyword UnitPoolModule
private keyword ItemPoolModule
private keyword QuestModule
private keyword QuestItemModule
private keyword DefeatConditionModule
private keyword TimerDialogModule
private keyword LeaderboardModule
private keyword MultiboardModule
private keyword MultiboardItemModule
private keyword TrackableModule
private keyword DialogModule
private keyword ButtonModule
private keyword TextTagModule
private keyword LightningModule
private keyword ImageModule
private keyword UbersplatModule
private keyword RegionModule
private keyword FogStateModule
private keyword FogModifierModule
private keyword HashtableModule
private keyword FrameModule
private keyword AgentStruct
private keyword HandleStruct
private keyword IntegerStruct
private keyword RealStruct
private keyword BooleanStruct
private keyword StringStruct
private keyword PlayerStruct
private keyword WidgetStruct
private keyword DestructableStruct
private keyword ItemStruct
private keyword UnitStruct
private keyword AbilityStruct
private keyword TimerStruct
private keyword TriggerStruct
private keyword TriggerConditionStruct
private keyword TriggerActionStruct
private keyword TriggerEventStruct
private keyword ForceStruct
private keyword GroupStruct
private keyword LocationStruct
private keyword RectStruct
private keyword BooleanExprStruct
private keyword SoundStruct
private keyword EffectStruct
private keyword UnitPoolStruct
private keyword ItemPoolStruct
private keyword QuestStruct
private keyword QuestItemStruct
private keyword DefeatConditionStruct
private keyword TimerDialogStruct
private keyword LeaderboardStruct
private keyword MultiboardStruct
private keyword MultiboardItemStruct
private keyword TrackableStruct
private keyword DialogStruct
private keyword ButtonStruct
private keyword TextTagStruct
private keyword LightningStruct
private keyword ImageStruct
private keyword UbersplatStruct
private keyword RegionStruct
private keyword FogStateStruct
private keyword FogModifierStruct
private keyword HashtableStruct
private keyword FrameStruct
endglobals
struct Table extends array
private static method operator shadowTable takes nothing returns Table
// Table:Table:integer|real|string
return HashtableStruct.typeid
endmethod
private static method operator parentTable takes nothing returns Table
// Table:Table
return RealStruct.typeid
endmethod
private static method operator hasChildTables takes nothing returns Table
// Table:boolean
return BooleanStruct.typeid
endmethod
private static method operator seenTables takes nothing returns Table
// Table:boolean
return StringStruct.typeid
endmethod
private static method operator instanceData takes nothing returns Table
// Table:integer
return Table.typeid
endmethod
private static method operator widths takes nothing returns Table
// Table:integer
return HandleStruct.typeid
endmethod
private static method operator recycledArrays takes nothing returns Table
// The same table, but with a better name for its purpose.
return HandleStruct.typeid
endmethod
private static integer forkKeyGen = 0
private static boolean isShadow = false
private static integer cleanUntil
private static Table tableToClean
method operator [] takes integer key returns Table
return LoadInteger(hashTable, this, key)
endmethod
method read takes string key returns Table
return this[StringHash(key)]
endmethod
method get takes handle key returns Table
return this[GetHandleId(key)]
endmethod
method operator []= takes integer key, Table value returns nothing
call SaveInteger(hashTable, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSavedInteger(hashTable, this, key)
endmethod
method written takes string key returns boolean
return this.has(StringHash(key))
endmethod
method stores takes handle key returns boolean
return this.has(GetHandleId(key))
endmethod
// Remove all keys and values from a Table instance
method flush takes nothing returns nothing
local Table shadow = shadowTable[this]
call FlushChildHashtable(hashTable, this)
if this > 0 and shadow > 0 then
call FlushChildHashtable(hashTable, shadow)
endif
call RemoveSavedBoolean(hashTable, hasChildTables, this)
endmethod
// This method enables quick table[parentIndex][childIndex].
//
// local Table table = Table.createFork(3)
// set table[15] = 40 // index 0 remains on the same table, so there is no need to switch to one of the parallel tables.
// set table.switch(1).unit[5] = GetTriggerUnit()
// set table.switch(2)[10] = 20
//
// Inline-friendly when not running in `TEST` mode
//
method switch takes integer key returns Table
static if TEST then
local integer i = widths[this]
if i == 0 then
call BJDebugMsg("Table.switch Error: Tried to invoke 'switch' method on invalid Table: " + I2S(this))
elseif key < 0 or key >= i then
call BJDebugMsg("Table.switch Error: Tried to get key [" + I2S(key) + "] from outside bounds: " + I2S(i))
endif
endif
return this + key
endmethod
// Returns a new Table instance that can save/load any hashtable-compatible data type.
static method create takes nothing returns Table
local Table table = instanceData[0]
if table == 0 then
set table = tableKeyGen + 1
set tableKeyGen = table
static if DEEP_TEST then
call BJDebugMsg("Table.create getting new index: " + I2S(table))
endif
else
set instanceData[0] = instanceData[table]
static if DEEP_TEST then
call BJDebugMsg("Table.create recycling index: " + I2S(table))
endif
endif
set instanceData[table] = -1
if isShadow then
set isShadow = false
else
set isShadow = true
set shadowTable[table] = Table.create()
endif
return table
endmethod
private method recycle takes nothing returns nothing
call this.flush()
if instanceData[this] != -1 then
static if TEST then
call BJDebugMsg("Table.recycle Error: " + I2S(this) + " is already inactive!")
endif
return
endif
set instanceData[this] = instanceData[0]
set instanceData[0] = this
endmethod
private method setInactive takes nothing returns nothing
local Table shadow = shadowTable[this]
call this.recycle()
if shadow > 0 then
static if DEEP_TEST then
call BJDebugMsg("Setting " + I2S(this) + " and its shadow " + I2S(shadow) + " to inactive state.")
endif
call shadow.recycle()
call RemoveSavedInteger(hashTable, shadowTable, this)
call RemoveSavedInteger(hashTable, parentTable, this)
else
static if DEEP_TEST then
call BJDebugMsg("Setting Table: " + I2S(this) + " to inactive state.")
endif
endif
endmethod
// Returns:
// -1: invalid Table for this operation (key/typeid/fork Table, or simply a destroyed/incorrect reference to a Table).
// 0: key does not exist yet in the Table
// >0: key exists in the Table.
method getKeyIndex takes integer key returns integer
local Table shadow = shadowTable[this]
if this <= 0 or shadow == 0 then
return -1
endif
return R2I(LoadReal(hashTable, shadow, key))
endmethod
method addKey takes integer key returns nothing
local Table shadow
local integer i = this.getKeyIndex(key)
if i == 0 then
set shadow = shadowTable[this]
set i = shadow[0] + 1
set shadow[0] = i
set shadow[i] = key
call SaveReal(hashTable, shadow, key, i)
static if DEEP_TEST then
call BJDebugMsg("Increasing table " + I2S(this) + "'s' key size to " + I2S(i))
endif
endif
endmethod
static if TEST then
method addTypedKey takes integer key, string whichType returns nothing
local Table shadow = shadowTable[this]
local string oldType = LoadStr(hashTable, shadow, key)
if oldType != null and oldType != whichType then
call BJDebugMsg("Table.addKey Error: Type " + whichType + " and " + oldType + " saved at key: " + I2S(key))
endif
call SaveStr(hashTable, shadow, key, whichType)
call this.addKey(key)
endmethod
endif
private method nestTable takes integer key, Table table returns nothing
set this[key] = table
static if TEST then
call this.addTypedKey(key, "Table")
else
call this.addKey(key)
endif
set parentTable[table] = this
call SaveBoolean(hashTable, hasChildTables, this, true)
endmethod
method link takes integer key returns Table
local Table table = this[key]
if table == 0 then
set table = Table.create()
static if DEEP_TEST then
call BJDebugMsg("Table(" + I2S(this) + ")[" + I2S(key) + "] => Table(" + I2S(table) + ")")
endif
elseif instanceData[table] != -1 then
static if TEST then
call BJDebugMsg("Table.link Error: Invalid Table " + I2S(table) + " found at key " + I2S(key))
endif
return 0
endif
call this.nestTable(key, table)
return table
endmethod
method save takes integer key, Table value returns Table
static if TEST then
call Table(this).addTypedKey(key, "Table")
else
call Table(this).addKey(key)
endif
set this[key] = value
return this
endmethod
method write takes string key, Table value returns Table
return this.save(StringHash(key), value)
endmethod
method store takes handle key, Table value returns Table
return this.save(GetHandleId(key), value)
endmethod
method join takes string key returns Table
return this.link(StringHash(key))
endmethod
method bind takes handle key returns Table
return this.link(GetHandleId(key))
endmethod
private static method cleanFork takes nothing returns nothing
local Table table = tableToClean
local integer exitWhen = table + 0x1000
if exitWhen < cleanUntil then
set tableToClean = exitWhen
//Avoids hitting the op limit
call ForForce(bj_FORCE_PLAYER[0], function Table.cleanFork)
else
set exitWhen = cleanUntil
endif
loop
exitwhen table == exitWhen
call table.flush()
set table = table + 1
endloop
endmethod
private method destroyFork takes nothing returns boolean
local integer width = widths[this]
local Table recycled
local integer i = width
if this >= 0 or width == 0 then
return false
endif
set tableToClean = this
set cleanUntil = this + widths[this]
call Table.cleanFork()
call RemoveSavedInteger(hashTable, widths, this) //Clear the array size from hash memory
set recycled = recycledArrays.link(width)
set recycled[this] = recycled[0]
set recycled[0] = this
return true
endmethod
// Returns a special type of Table with `width` parallel indices.
//
// local Table fork = Table.fork(width)
//
static method createFork takes integer width returns Table
local Table recycled = recycledArrays.link(width) //Get the unique recycle list for this array size
local Table fork = recycled[0] //The last-destroyed fork that had this array size
if width <= 0 then
static if TEST then
call BJDebugMsg("Table.createFork Error: Invalid specified width: " + I2S(width))
endif
return 0
endif
if fork == 0 then
set fork = forkKeyGen - width // If we start with 8190, the first fork index will be -8190
set forkKeyGen = fork
else
set recycled[0] = recycled[fork] //Set the last destroyed to the last-last destroyed
call RemoveSavedInteger(hashTable, recycled, fork)
endif
set widths[fork] = width
return fork
endmethod
method forkLink takes integer width, integer key returns Table
local Table table = this[key]
if table == 0 then
set table = Table.createFork(width)
elseif widths[this] == 0 then
static if TEST then
call BJDebugMsg("Table.forkLink Error: Invalid Table " + I2S(table) + " found at key " + I2S(key))
endif
return 0
endif
call this.nestTable(key, table)
return table
endmethod
method forkJoin takes integer width, string key returns Table
return this.forkLink(width, StringHash(key))
endmethod
method forkBind takes integer width, handle key returns Table
return this.forkLink(width, GetHandleId(key))
endmethod
method getKeys takes nothing returns integer
local Table shadow = shadowTable[this]
if this <= 0 or shadow == 0 then
static if TEST then
call BJDebugMsg("Table.getKeys Error: Called on invalid Table " + I2S(this))
endif
return 0
endif
return shadow
endmethod
method measureFork takes nothing returns integer
return widths[this]
endmethod
private method destroyDeep takes nothing returns nothing
local Table shadow = shadowTable[this]
local integer i = shadow[0] //get the number of tracked indices
local Table table
static if DEEP_TEST then
call BJDebugMsg("Destroying Table: " + I2S(this) + " and all of its child tables.")
endif
// Mark this table as seen to avoid potentially-infinite recursion
call SaveBoolean(hashTable, seenTables, this, true)
loop
exitwhen i == 0
// Get the actual table using the index from shadow
set table = this[shadow[i]]
if table > 0 then
if instanceData[table] == -1 and /*
*/ parentTable[table] == this and /*
*/ not LoadBoolean(hashTable, seenTables, table) /*
*/ then
if LoadBoolean(hashTable, hasChildTables, table) then
call table.destroyDeep()
else
call table.setInactive()
endif
endif
elseif table < 0 then
call this.destroyFork()
endif
set i = i - 1
endloop
call this.setInactive()
endmethod
// Removes all data from a Table instance and recycles its index.
method destroy takes nothing returns nothing
if instanceData[this] != -1 then
if not this.destroyFork() then
static if TEST then
call BJDebugMsg("Table.destroy Error: Inactive Table: " + I2S(this))
endif
endif
else
if LoadBoolean(hashTable, hasChildTables, this) then
call this.destroyDeep()
call FlushChildHashtable(hashTable, seenTables)
else
call this.setInactive()
endif
endif
endmethod
method removeKey takes integer key returns nothing
local Table shadow
local Table child = this[key]
local integer i = this.getKeyIndex(key)
local integer top
if i > 0 then
set shadow = shadowTable[this]
static if TEST then
call RemoveSavedString(hashTable, shadow, key)
endif
set top = shadow[0]
if top == 1 then
call FlushChildHashtable(hashTable, shadow)
else
call RemoveSavedReal(hashTable, shadow, key)
set shadow[0] = top - 1
if top != i then
set key = shadow[top]
set shadow[i] = key
call SaveReal(hashTable, shadow, key, i)
endif
call RemoveSavedInteger(hashTable, shadow, top)
endif
endif
if child > 0 and /*
*/ instanceData[child] == -1 and /*
*/ parentTable[child] == this /*
*/ then
call child.destroy()
endif
endmethod
method remove takes integer key returns nothing
call this.removeKey(key)
call RemoveSavedInteger(hashTable, this, key)
endmethod
method delete takes string key returns nothing
call this.remove(StringHash(key))
endmethod
method forget takes handle key returns nothing
call this.remove(GetHandleId(key))
endmethod
method operator handle takes nothing returns HandleStruct
return this
endmethod
method operator agent takes nothing returns AgentStruct
return this
endmethod
// Implement modules for handle/agent/integer/real/boolean/string/etc syntax.
implement IntegerModule
implement RealModule
implement BooleanModule
implement StringModule
implement PlayerModule
implement WidgetModule
implement DestructableModule
implement ItemModule
implement UnitModule
implement AbilityModule
implement TimerModule
implement TriggerModule
implement TriggerConditionModule
implement TriggerActionModule
implement TriggerEventModule
implement ForceModule
implement GroupModule
implement LocationModule
implement RectModule
implement BooleanExprModule
implement SoundModule
implement EffectModule
implement UnitPoolModule
implement ItemPoolModule
implement QuestModule
implement QuestItemModule
implement DefeatConditionModule
implement TimerDialogModule
implement LeaderboardModule
implement MultiboardModule
implement MultiboardItemModule
implement TrackableModule
implement DialogModule
implement ButtonModule
implement TextTagModule
implement LightningModule
implement ImageModule
implement UbersplatModule
implement RegionModule
implement FogStateModule
implement FogModifierModule
implement HashtableModule
implement FrameModule
static if TEST then
private method toStringFn takes integer depth returns string
local Table shadow = shadowTable[this]
local integer i = shadow[0]
local string indent = ""
local integer k = 0
local string output
local Table table
local string typeOf
local string value
local integer keyOf
local string parsedKey
// Determine if this is a tracked table and if it's already been seen
if this > 0 and shadow > 0 then
if HaveSavedBoolean(hashTable, seenTables, this) then
// Show already-referenced Table:
return "Seen Table(" + I2S(this) + ")"
endif
call SaveBoolean(hashTable, seenTables, this, true)
if i == 0 then
// Show empty Table:
return "Table(" + I2S(this) + ")[]"
endif
set output = "Table(" + I2S(this) + ")["
elseif instanceData[this] > 0 then
return "Destroyed Table(" + I2S(this) + ")"
elseif widths[this] > 0 then
return "Tables " + I2S(this) + " through " + I2S(this + widths[this] - 1)
elseif instanceData[this] == 0 then
return "Invalid Table(" + I2S(this) + ")"
endif
loop
exitwhen k == depth
set indent = indent + " "
set k = k + 1
endloop
loop
exitwhen i == 0
set keyOf = shadow[i]
set typeOf = LoadStr(hashTable, shadow, keyOf)
set parsedKey = I2S(keyOf)
if typeOf == "Table" then
set table = this[keyOf]
set typeOf = ""
if instanceData[keyOf] == -1 or widths[keyOf] > 0 then
set parsedKey = Table(keyOf).toStringFn(depth)
endif
if instanceData[table] == -1 or widths[table] > 0 then
set value = table.toStringFn(depth + 1)
else
set value = I2S(table) // simple integer
endif
elseif typeOf == "integer" then
set typeOf = ""
set value = I2S(this[keyOf])
elseif typeOf == "string" then
set typeOf = ""
set value = "\"" + LoadStr(hashTable, this, keyOf) + "\""
elseif typeOf == "real" then
set typeOf = ""
set value = R2S(LoadReal(hashTable, this, keyOf))
elseif typeOf == "boolean" then
set typeOf = ""
if LoadBoolean(hashTable, this, keyOf) then
set value = "true"
else
set value = "false"
endif
elseif typeOf == null then
set typeOf = ""
set value = "untracked value"
else
set value = ""
endif
set output = output + "\n" + indent + " [" + parsedKey + "] = " + typeOf + value
set i = i - 1
endloop
return output + "\n" + indent + "]"
endmethod
method toString takes nothing returns string
local string result = this.toStringFn(0)
call seenTables.flush()
return result
endmethod
method print takes nothing returns nothing
call BJDebugMsg(toString())
endmethod
endif
//! runtextmacro optional TABLE_VBC_METHODS()
endstruct
/*
Create API for stuff like:
set table.unit[key] = GetTriggerUnit()
local boolean b = table.handle.has(key)
local unit u = table.unit[key]
set table.handle.remove(key)
These structs include the entire hashtable API as wrappers.
Feel free to remove any types that you don't use.
*/
struct HandleStruct extends array
method remove takes integer key returns nothing
call Table(this).removeKey(key)
call RemoveSavedHandle(hashTable, this, key)
endmethod
method delete takes string key returns nothing
call this.remove(StringHash(key))
endmethod
method forget takes handle key returns nothing
call this.remove(GetHandleId(key))
endmethod
method operator []= takes integer key, handle h returns nothing
if h != null then
// "But I need hashtables to typecast generic handles into ..." - say no more. I got u fam.
call SaveFogStateHandle(hashTable, this, key, ConvertFogState(GetHandleId(h)))
else
call this.remove(key)
endif
endmethod
method save takes integer key, agent value returns Table
static if TEST then
call Table(this).addTypedKey(key, "handle")
else
call Table(this).addKey(key)
endif
set this[key] = value
return this
endmethod
method write takes string key, agent value returns Table
return this.save(StringHash(key), value)
endmethod
method store takes handle key, agent value returns Table
return this.save(GetHandleId(key), value)
endmethod
method has takes integer key returns boolean
return HaveSavedHandle(hashTable, this, key)
endmethod
method written takes string key returns boolean
return this.has(StringHash(key))
endmethod
method stores takes handle key returns boolean
return this.has(GetHandleId(key))
endmethod
endstruct
struct AgentStruct extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(hashTable, this, key, value)
endmethod
method save takes integer key, agent value returns Table
static if TEST then
call Table(this).addTypedKey(key, "agent")
else
call Table(this).addKey(key)
endif
set this[key] = value
return this
endmethod
method write takes string key, agent value returns Table
return this.save(StringHash(key), value)
endmethod
method store takes handle key, agent value returns Table
return this.save(GetHandleId(key), value)
endmethod
endstruct
//! textmacro BASIC_VALUE_TABLE takes SUPER, FUNC, TYPE
struct $SUPER$Struct extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(hashTable, this, key)
endmethod
method get takes handle key returns $TYPE$
return this[GetHandleId(key)]
endmethod
method read takes string key returns $TYPE$
return this[StringHash(key)]
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(hashTable, this, key, value)
endmethod
method save takes integer key, $TYPE$ value returns Table
static if TEST then
call Table(this).addTypedKey(key, "$TYPE$")
else
call Table(this).addKey(key)
endif
set this[key] = value
return this
endmethod
method store takes handle key, $TYPE$ value returns Table
return this.save(GetHandleId(key), value)
endmethod
method write takes string key, $TYPE$ value returns Table
return this.save(StringHash(key), value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(hashTable, this, key)
endmethod
method written takes string key returns boolean
return this.has(StringHash(key))
endmethod
method stores takes handle key returns boolean
return this.has(GetHandleId(key))
endmethod
method remove takes integer key returns nothing
call Table(this).removeKey(key)
call RemoveSaved$SUPER$(hashTable, this, key)
endmethod
method delete takes string key returns nothing
call this.remove(StringHash(key))
endmethod
method forget takes handle key returns nothing
call this.remove(GetHandleId(key))
endmethod
endstruct
module $SUPER$Module
method operator $TYPE$ takes nothing returns $SUPER$Struct
return this
endmethod
endmodule
//! endtextmacro
//! runtextmacro BASIC_VALUE_TABLE("Real", "Real", "real")
//! runtextmacro BASIC_VALUE_TABLE("Boolean", "Boolean", "boolean")
//! runtextmacro BASIC_VALUE_TABLE("String", "Str", "string")
//! runtextmacro BASIC_VALUE_TABLE("Integer", "Integer", "integer")
//! textmacro HANDLE_VALUE_TABLE takes FUNC, TYPE
struct $FUNC$Struct extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(hashTable, this, key)
endmethod
method get takes handle key returns $TYPE$
return this[GetHandleId(key)]
endmethod
method read takes string key returns $TYPE$
return this[StringHash(key)]
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(hashTable, this, key, value)
endmethod
method save takes integer key, $TYPE$ value returns Table
static if TEST then
call Table(this).addTypedKey(key, "$TYPE$")
else
call Table(this).addKey(key)
endif
set this[key] = value
return this
endmethod
method store takes handle key, $TYPE$ value returns Table
return this.save(GetHandleId(key), value)
endmethod
method write takes string key, $TYPE$ value returns Table
return this.save(StringHash(key), value)
endmethod
// deprecated; use handle.has/stores/written
method has takes integer key returns boolean
return HaveSavedHandle(hashTable, this, key)
endmethod
// deprecated; use handle.remove/forget/delete
method remove takes integer key returns nothing
call HandleStruct(this).remove(key)
endmethod
endstruct
module $FUNC$Module
method operator $TYPE$ takes nothing returns $FUNC$Struct
return this
endmethod
endmodule
//! endtextmacro
//! runtextmacro HANDLE_VALUE_TABLE("Player", "player")
//! runtextmacro HANDLE_VALUE_TABLE("Widget", "widget")
//! runtextmacro HANDLE_VALUE_TABLE("Destructable", "destructable")
//! runtextmacro HANDLE_VALUE_TABLE("Item", "item")
//! runtextmacro HANDLE_VALUE_TABLE("Unit", "unit")
//! runtextmacro HANDLE_VALUE_TABLE("Ability", "ability")
//! runtextmacro HANDLE_VALUE_TABLE("Timer", "timer")
//! runtextmacro HANDLE_VALUE_TABLE("Trigger", "trigger")
//! runtextmacro HANDLE_VALUE_TABLE("TriggerCondition", "triggercondition")
//! runtextmacro HANDLE_VALUE_TABLE("TriggerAction", "triggeraction")
//! runtextmacro HANDLE_VALUE_TABLE("TriggerEvent", "event")
//! runtextmacro HANDLE_VALUE_TABLE("Force", "force")
//! runtextmacro HANDLE_VALUE_TABLE("Group", "group")
//! runtextmacro HANDLE_VALUE_TABLE("Location", "location")
//! runtextmacro HANDLE_VALUE_TABLE("Rect", "rect")
//! runtextmacro HANDLE_VALUE_TABLE("BooleanExpr", "boolexpr")
//! runtextmacro HANDLE_VALUE_TABLE("Sound", "sound")
//! runtextmacro HANDLE_VALUE_TABLE("Effect", "effect")
//! runtextmacro HANDLE_VALUE_TABLE("UnitPool", "unitpool")
//! runtextmacro HANDLE_VALUE_TABLE("ItemPool", "itempool")
//! runtextmacro HANDLE_VALUE_TABLE("Quest", "quest")
//! runtextmacro HANDLE_VALUE_TABLE("QuestItem", "questitem")
//! runtextmacro HANDLE_VALUE_TABLE("DefeatCondition", "defeatcondition")
//! runtextmacro HANDLE_VALUE_TABLE("TimerDialog", "timerdialog")
//! runtextmacro HANDLE_VALUE_TABLE("Leaderboard", "leaderboard")
//! runtextmacro HANDLE_VALUE_TABLE("Multiboard", "multiboard")
//! runtextmacro HANDLE_VALUE_TABLE("MultiboardItem", "multiboarditem")
//! runtextmacro HANDLE_VALUE_TABLE("Trackable", "trackable")
//! runtextmacro HANDLE_VALUE_TABLE("Dialog", "dialog")
//! runtextmacro HANDLE_VALUE_TABLE("Button", "button")
//! runtextmacro HANDLE_VALUE_TABLE("TextTag", "texttag")
//! runtextmacro HANDLE_VALUE_TABLE("Lightning", "lightning")
//! runtextmacro HANDLE_VALUE_TABLE("Image", "image")
//! runtextmacro HANDLE_VALUE_TABLE("Ubersplat", "ubersplat")
//! runtextmacro HANDLE_VALUE_TABLE("Region", "region")
//! runtextmacro HANDLE_VALUE_TABLE("FogState", "fogstate")
//! runtextmacro HANDLE_VALUE_TABLE("FogModifier", "fogmodifier")
//! runtextmacro HANDLE_VALUE_TABLE("Hashtable", "hashtable")
//! runtextmacro HANDLE_VALUE_TABLE("Frame", "framehandle")
//! runtextmacro optional TABLE_VBC_STRUCTS()
// Run these only to support backwards-compatibility.
// If you want to use them, include the Table5BC library in your script.
//! runtextmacro optional TABLE_ARRAY_BC()
//! runtextmacro optional TableXD("Table2D", "Table", "createFork(1)")
//! runtextmacro optional TableXD("Table3D", "Table2D", "createFork(1)")
//! runtextmacro optional TableXD("Table4D", "Table3D", "createFork(1)")
//! runtextmacro optional TableXD("Table5D", "Table4D", "createFork(1)")
//! runtextmacro optional TableXD("Table2DT", "Table", "create()")
//! runtextmacro optional TableXD("Table3DT", "Table2DT", "create()")
//! runtextmacro optional TableXD("Table4DT", "Table3DT", "create()")
//! runtextmacro optional TableXD("Table5DT", "Table4DT", "create()")
//! runtextmacro optional TableXD("HashTable", "Table", "createFork(1)")
//! runtextmacro optional TableXD("HashTableEx", "Table", "create()")
endlibrary
library TableVBC
/*
Backwards-compatibility add-on for scripts employing Vexorian's Table.
Compatible with Table version 6+
Disclaimer:
The this.flush(key) method from the original Table cannot be parsed with
the new Table. For the scripts that use this method, they need to be up-
dated to use the more hashtable-API-fitting this.remove(key) method. The
`flush` method was retained by Vexorian's Table because of the matching
gamecache API.
Note: This issue does not occur with HandleTables & StringTables; only
with the standard, integer-keyed Table, so you do not need to make any
changes to StringTable/HandleTable-employing scripts.
If you want to use StringTables/HandleTables with features exclusive
to the new Table, you'll want to use the new wrapper methods introduced
in Table version 6 and switch away from StringTable/HandleTable types.
*/
//! textmacro TABLE_VBC_METHODS
method reset takes nothing returns nothing
call this.flush()
endmethod
method exists takes integer key returns boolean
return this.has(key)
endmethod
static method operator [] takes string key returns Table
return Table(StringTable.typeid).join(key)
endmethod
static method flush2D takes string key returns nothing
call Table(StringTable.typeid).delete(key)
endmethod
//! endtextmacro
//! textmacro TABLE_VBC_STRUCTS
struct HandleTable extends array
static method operator [] takes string key returns thistype
return Table[key]
endmethod
static method flush2D takes string key returns nothing
call Table.flush2D(key)
endmethod
method operator [] takes handle key returns integer
return Table(this).get(key)
endmethod
method operator []= takes handle key, integer value returns nothing
call Table(this).store(key, value)
endmethod
method flush takes handle key returns nothing
call Table(this).forget(key)
endmethod
method exists takes handle key returns boolean
return Table(this).stores(key)
endmethod
method reset takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
struct StringTable extends array
static method operator [] takes string key returns thistype
return Table[key]
endmethod
static method flush2D takes string key returns nothing
call Table.flush2D(key)
endmethod
method operator [] takes string key returns integer
return Table(this).read(key)
endmethod
method operator []= takes string key, integer value returns nothing
call Table(this).write(key, value)
endmethod
method flush takes string key returns nothing
call Table(this).delete(key)
endmethod
method exists takes string key returns boolean
return Table(this).written(key)
endmethod
method reset takes nothing returns nothing
call Table(this).flush()
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
static method create takes nothing returns thistype
return Table.create()
endmethod
endstruct
//! endtextmacro
endlibrary
library Table5BC
//! textmacro TABLE_ARRAY_BC
struct TableArray extends array
static method operator [] takes integer width returns TableArray
return Table.createFork(width)
endmethod
method operator size takes nothing returns integer
return Table(this).measureFork()
endmethod
method operator [] takes integer key returns Table
return Table(this).switch(key)
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
method flush takes nothing returns nothing
call Table(this).destroy()
endmethod
endstruct
//! endtextmacro
//! textmacro TableXD takes NAME, MAP_TO_WHAT, CREATE
struct $NAME$ extends array
method operator [] takes integer key returns $MAP_TO_WHAT$
return Table(this).link(key)
endmethod
method remove takes integer key returns nothing
call Table(this).remove(key)
endmethod
method has takes integer key returns boolean
return Table(this).has(key)
endmethod
method destroy takes nothing returns nothing
call Table(this).destroy()
endmethod
static method create takes nothing returns $NAME$
return Table.$CREATE$
endmethod
endstruct
//! endtextmacro
endlibrary
library MathLib initializer onInit
struct math
static method ln takes real x returns real
local real y
local real dy
local integer n = 1
set x = x - 1
set dy = x
set y = dy
loop
set n = n + 1
set dy = -1*dy*x/I2R(n*(n-1))
set y = y + dy
exitwhen (RAbsBJ(dy) < 0.0001)
endloop
return y
endmethod
static method floor takes real r returns integer
if( r >= 0) then
return R2I(r)
else
return R2I(r - 1)
endif
endmethod
static method rabs takes real a returns real
if (a >= 0) then
return a
else
return -a
endif
endmethod
static method exp takes real x returns real
local integer k = 1
local real Ox = 1
local real y = Ox
loop
set Ox = Ox*x/k
set y = y + Ox
set k = k + 1
exitwhen(math.rabs(Ox) < 0.001)
endloop
return y
endmethod
static method factorial takes integer k returns integer
local integer i = 0
local integer m = 1
loop
set i = i + 1
set m = m*i
exitwhen (i == k)
endloop
return m
endmethod
static method isgn takes integer x returns integer
if (x > 0) then
return 1
else
return -1
endif
endmethod
static method rsgn takes real x returns real
if (x > 0) then
return 1.
else
return -1.
endif
endmethod
static method rmax takes real x1, real x2 returns real
if(x1 > x2)then
return x1
else
return x2
endif
endmethod
static method rhoL2 takes real x1, real y1, real x2, real y2 returns real
local real x = x1 - x2
local real y = y1 - y2
return SquareRoot(x*x + y*y)
endmethod
static method rhoL1 takes real x1, real y1, real x2, real y2 returns real
return math.rabs(x1 - x2) + math.rabs(y1 - y2)
endmethod
static method rhoL0 takes real x1, real y1, real x2, real y2 returns real
return math.rmax(math.rabs(x1 - x2), math.rabs(y1 - y2))
endmethod
private static method onInit takes nothing returns nothing
//Заглушка
endmethod
endstruct
endlibrary
library StatisticLib initializer onInit requires MathLib
struct stat
static method poisson takes integer k, real lambda returns real
local integer i = 0
local real P = 1
loop
exitwhen (i >= k)
set P = P*lambda/(i + 1)
set i = i + 1
endloop
return P * math.exp(-lambda)
endmethod
endstruct
private function onInit takes nothing returns nothing
//call BJDebugMsg(R2S(poisson(4,4)))
endfunction
endlibrary
library numjass initializer onInit uses MultidimensionalArray
globals
//private hashtable hash
endglobals
struct nj_I1D
integer shape_x
private Integer1D ar
method operator []= takes integer idx, integer value returns nothing
set this.ar[idx] = value
endmethod
method operator [] takes integer idx returns integer
return this.ar[idx]
endmethod
method append takes integer value returns nothing
set this[shape_x] = value
set this.shape_x = this.shape_x + 1
endmethod
// Алгоритм случайного тасования Ричарда Дурштенфельда (Richard Durstenfeld)
method shuffle takes nothing returns nothing
local integer max = this.shape_x
local integer k
local integer sh_int
loop
exitwhen max <= 1
set k = GetRandomInt(0, max)
set sh_int = this[max]
set this[max] = this[k]
set this[k] = sh_int
set max = max - 1
endloop
endmethod
method destroy takes nothing returns nothing
call this.ar.destroy()
call this.destroy()
endmethod
static method create takes integer shape_x returns nj_I1D
local nj_I1D this = thistype.allocate()
set this.ar = Integer1D.create()
set this.shape_x = shape_x
return this
endmethod
endstruct
struct nj_I2D extends Integer2D
integer shape_x
integer shape_y
method fill takes integer value returns nothing
local integer i
local integer j
set i = 0
loop
exitwhen(i == this.shape_x)
set j = 0
loop
exitwhen(j == this.shape_y)
set this[i][j] = value
set j = j + 1
endloop
set i = i + 1
endloop
endmethod
method print takes nothing returns nothing
local string s_col = ""
local integer i
local integer j
local texttag loc_tt = CreateTextTag()
set i = 0
loop
exitwhen(i == shape_x)
set j = 0
loop
exitwhen(j == shape_y)
set s_col = s_col + I2S(this[i][j]) + " "
set j = j + 1
endloop
call BJDebugMsg(s_col)
set s_col = ""
set i = i + 1
endloop
endmethod
static method create takes integer shape_x, integer shape_y returns nj_I2D
local nj_I2D this = Integer2D.create()
set this.shape_x = shape_x
set this.shape_y = shape_y
return this
endmethod
endstruct
struct nj
static method empty_I2D takes integer shape_x, integer shape_y returns nj_I2D
return nj_I2D.create(shape_x, shape_y)
endmethod
static method fill_I2D takes integer shape_x, integer shape_y, integer value returns nj_I2D
local nj_I2D this = nj_I2D.create(shape_x, shape_y)
call this.fill.execute(value)
return this
endmethod
static method zeros_I2D takes integer shape_x, integer shape_y returns nj_I2D
return nj.fill_I2D(shape_x, shape_y, 0)
endmethod
static method arrange takes integer start, integer step, integer end returns nj_I1D
local nj_I1D this = nj_I1D.create(0)
local integer i = 1
set end = end - 1
set this[0] = start
loop
exitwhen((this[i-1] >= end))
set this[i] = this[i-1] + step
set i = i + 1
endloop
set this.shape_x = i
return this
endmethod
endstruct
private function onInit takes nothing returns nothing
//local nj_I2D A = nj.zeros_I2D(255,255)
//call BJDebugMsg("Все")
endfunction
endlibrary
library MatMapLib initializer onInit uses numjass, MathLib, MultidimensionalArray
struct MatMap
integer DX
integer DY
nj_I2D map
method operator [] takes integer i returns Integer1D
return this.map[i]
endmethod
// ==== Свойства ====
method operator shape_x takes nothing returns integer
return this.map.shape_x
endmethod
method operator shape_y takes nothing returns integer
return this.map.shape_y
endmethod
static method operator maxX takes nothing returns integer
return R2I(GetRectMaxX(GetWorldBounds()))
endmethod
static method operator minX takes nothing returns integer
return R2I(GetRectMinX(GetWorldBounds()))
endmethod
static method operator maxY takes nothing returns integer
return R2I(GetRectMaxY(GetWorldBounds()))
endmethod
static method operator minY takes nothing returns integer
return R2I(GetRectMinY(GetWorldBounds()))
endmethod
//
method mat_i2x takes integer i returns real
return I2R((2*i+1)*this.DX/2 + thistype.minX)
endmethod
method mat_j2y takes integer j returns real
return thistype.maxY - I2R(2*j+1)*this.DY/2
endmethod
method mat_x2i takes real x returns integer
return math.floor((x - thistype.minX)/this.DX)
endmethod
method mat_y2j takes real y returns integer
return math.floor((thistype.maxY - y)/this.DY)
endmethod
static method create takes integer shape_x, integer shape_y returns thistype
local thistype this = thistype.allocate()
set this.DX = (thistype.maxX - thistype.minX)/shape_x
set this.DY = (thistype.maxY - thistype.minY)/shape_y
set this.map = nj.zeros_I2D(shape_x, shape_y)
return this
endmethod
static method create_fill takes integer shape_x, integer shape_y, integer value returns thistype
local thistype this = thistype.allocate()
set this.DX = (thistype.maxX - thistype.minX)/shape_x
set this.DY = (thistype.maxY - thistype.minY)/shape_y
set this.map = nj.fill_I2D(shape_x, shape_y, value)
return this
endmethod
static method create_grid takes integer dx, integer dy returns thistype
local thistype this = thistype.allocate()
local integer shape_x = (thistype.maxX - thistype.minX)/dx
local integer shape_y = (thistype.maxY - thistype.minY)/dy
set this.DX = dx
set this.DY = dy
set this.map = nj.zeros_I2D(shape_x, shape_y)
return this
endmethod
static method create_small takes nothing returns thistype
return thistype.create_grid(128,128)
endmethod
static method create_medium takes nothing returns thistype
return thistype.create_grid(256,256)
endmethod
static method create_large takes nothing returns thistype
return thistype.create_grid(512,512)
endmethod
static method onInit takes nothing returns nothing
//Заглушка
endmethod
endstruct
endlibrary
library HandlerLib initializer onInit
globals
private key key_integer
endglobals
//
// ==== Макрос для публичного свойства ====
//! textmacro OperatorProprety takes NAME, DTYPE, dtype, CHILDKEY
method operator $NAME$ takes nothing returns $dtype$
return Lib_Load$DTYPE$(this.hash, this, $CHILDKEY$)
endmethod
method operator $NAME$= takes $dtype$ value returns nothing
call Lib_Save$DTYPE$(this.hash, this, $CHILDKEY$, value)
endmethod
//! endtextmacro
//
// ==== Макрос для приватного свойства ====
//! textmacro PrivateOperatorProprety takes NAME, DTYPE, dtype, CHILDKEY
private method operator $NAME$ takes nothing returns $dtype$
return Lib_Load$DTYPE$(this.hash, this, $CHILDKEY$)
endmethod
private method operator $NAME$= takes $dtype$ value returns nothing
call Lib_Save$DTYPE$(this.hash, this, $CHILDKEY$, value)
endmethod
//! endtextmacro
//
// ==== Макрос для свойства только для чтения ====
//! textmacro ReadonlyOperatorProprety takes NAME, DTYPE, dtype, CHILDKEY
method operator $NAME$ takes nothing returns $dtype$
return Lib_Load$DTYPE$(thistype.hash, this, $CHILDKEY$)
endmethod
private method operator $NAME$= takes $dtype$ value returns nothing
call Lib_Save$DTYPE$(thistype.hash, this, $CHILDKEY$, value)
endmethod
//! endtextmacro
//
//
// ==== Переименование нативных функций ====
private function Lib_SetUnitPosition takes unit whichUnit, real newX, real newY returns nothing
call SetUnitPosition(whichUnit,newX,newY)
endfunction
private function Lib_GetResourceAmount takes unit whichUnit returns integer
return GetResourceAmount(whichUnit)
endfunction
private function Lib_GetUnitX takes unit whichUnit returns real
return GetUnitX(whichUnit)
endfunction
private function Lib_GetUnitY takes unit whichUnit returns real
return GetUnitY(whichUnit)
endfunction
//
// ==== перемеиннование Save/Load Hashtable value
//! textmacro RenameHashtableFunc takes DTYPE, dtype
private function Lib_Save$DTYPE$ takes hashtable table, integer parentKey, integer childKey, $dtype$ value returns nothing
call Save$DTYPE$(table,parentKey,childKey,value)
endfunction
private function Lib_Load$DTYPE$ takes hashtable table, integer parentKey, integer childKey returns $dtype$
return Load$DTYPE$(table,parentKey,childKey)
endfunction
//! endtextmacro
//! runtextmacro RenameHashtableFunc("Integer", "integer")
//! runtextmacro RenameHashtableFunc("Real", "real")
//! runtextmacro RenameHashtableFunc("Boolean", "boolean")
//! runtextmacro RenameHashtableFunc("UnitHandle", "unit")
//! runtextmacro RenameHashtableFunc("TimerHandle", "timer")
// =========================================
//
struct UNIT
private static hashtable hash
//! novjass
private unit unit // Получение хэндла юнита
private integer isin //свойство нахождения юнита в системе
integer thishandler
//! endnovjass
//! runtextmacro ReadonlyOperatorProprety("isin", "Boolean", "boolean", "0")
//! runtextmacro ReadonlyOperatorProprety("unit", "UnitHandle", "unit", "1")
//! runtextmacro OperatorProprety("thishandler", "Integer", "HandlerUnit", "2")
//
//
method SetUnitPosition takes real newX,real newY returns nothing
call Lib_SetUnitPosition(this.unit, newX, newY)
endmethod
//
method GetResourceAmount takes nothing returns integer
return Lib_GetResourceAmount(this.unit)
endmethod
//
//method GetUnitX takes nothing returns real
//return Lib_GetUnitX(this.unit)
//endmethod
//
//method GetUnitY takes nothing returns real
//return Lib_GetUnitY(this.unit)
//endmethod
// Макросы для загрузки и сохранения
//! textmacro SaveLoadHashtableMethod takes DTYPE, dtype
method Load$DTYPE$ takes integer childKey returns $dtype$
return Lib_Load$DTYPE$(thistype.hash, this, childKey)
endmethod
method Save$DTYPE$ takes integer childKey, $dtype$ value returns nothing
call Lib_Save$DTYPE$(thistype.hash,this, childKey, value)
endmethod
//! endtextmacro
// ==== Загрузка/Сохранение целочисленного принадлежащего юниту ================
//! runtextmacro SaveLoadHashtableMethod("Integer", "integer")
// ==== Загрузка/Сохранение логического принадлежащего юниту ===================
//! runtextmacro SaveLoadHashtableMethod("Boolean", "boolean")
// ==== Загрузка/Сохранение числа с плавающей точкой принадлежащего юниту ======
//! runtextmacro SaveLoadHashtableMethod("Real", "real")
// ==== Загрузка/Сохранение таймера принадлежащего юниту =======================
//! runtextmacro SaveLoadHashtableMethod("TimerHandle", "timer")
//
// ==== Констуркор ========================================
static method create takes unit un returns thistype
local thistype this = GetHandleId(un)
set this.unit = un
set this.isin = true
return this
endmethod
//
// ==== Деструктор ========================================
stub method flush takes nothing returns nothing
call FlushChildHashtable(thistype.hash, this)
endmethod
//
// ==== Инициализация =====================================
private static method onInit takes nothing returns nothing
set hash = InitHashtable()
endmethod
endstruct
//
//
private function interface UnitExe takes unit un returns nothing
private function interface UNITExe takes UNIT UN returns nothing
//
//
struct GetUNIT
stub method operator[] takes integer HandleID returns UNIT
return HandleID
endmethod
endstruct
//
//
struct HandlerUnit
private static hashtable hash
private static integer GroupCount
//! novjass
integer Count
integer np //Число свойств юнита в группе
private integer pp //указатель на первое свсвойство юнита
integer p //указатель на первое доступное свсвойство юнита
private integer PatchPointer
//! endnovjass
//! runtextmacro ReadonlyOperatorProprety("Count", "Integer", "integer", "0")
//! runtextmacro ReadonlyOperatorProprety("np", "Integer", "integer", "1")
//! runtextmacro ReadonlyOperatorProprety("p", "Integer", "integer", "2")
//! runtextmacro PrivateOperatorProprety("pp", "Integer", "integer", "3")
//! runtextmacro PrivateOperatorProprety("PatchPointer", "Integer", "integer", "4")
private static constant integer pn = 5 // Число свойств класса
private static constant integer ppu = 2 // Число приватных свойств юнита в группе
//
// ==== Конвертация номера юнита в масиве номер childID
private method conv_idx2hashidx takes integer idx returns integer
return idx + thistype.pn
endmethod
//
// ==== Получение индекса по юниту
method get_idx_unit takes unit un returns integer
local UNIT UN = GetHandleId(un)
return UN.LoadInteger(this.pp+1)
endmethod
//
//
// ==== Получение индекса по юниту
method get_idx_UNIT takes UNIT UN returns integer
return UN.LoadInteger(this.pp+1)
endmethod
//
//
method get_prop_key takes integer nk returns integer
//nk - номер ключа переменной
return LoadInteger(this.hash,this.getid,thistype.pn + nk)
endmethod
//
//
stub method operator getUnit takes nothing returns GetUNIT
return this
endmethod
//
//
private method operator []= takes integer idx, UNIT UN returns nothing
call SaveInteger(thistype.hash, this, this.conv_idx2hashidx(idx), UN)
call UN.SaveInteger(this.pp+1, idx)
call UN.SaveBoolean(this.pp, true)
endmethod
//
// ============================================================================
method operator [] takes integer idx returns UNIT
local UNIT UN = LoadInteger(thistype.hash, this, this.conv_idx2hashidx(idx))
set UN.thishandler = this
return UN
endmethod
//
// ============================================================================
method get_UNIT_idx takes integer idx returns UNIT
local UNIT UN = LoadInteger(thistype.hash, this, this.conv_idx2hashidx(idx))
set UN.thishandler = this
return UN
endmethod
//
// ====
method operator getid takes nothing returns integer
return this
endmethod
//
// ==== Проверка входит ли юнит в группу ===========================
method isUnitInGroup takes UNIT UN returns boolean
return UN.LoadBoolean(this.pp)
endmethod
//
// ==== Проверка входит ли юнит в систему ===========================
static method isUnitIn takes unit un returns boolean
local UNIT UN = GetHandleId(un)
return UN.isin
endmethod
//
//
method forPatch takes UnitExe F returns nothing
local integer i = 0
local UNIT UN
loop
exitwhen ( (i > 6) or (this.Count == 0) )
if (this.PatchPointer < 0) then
set this.PatchPointer = this.Count - 1
endif
call F.execute(this[this.PatchPointer].unit)
set this.PatchPointer = this.PatchPointer - 1
set i = i + 1
endloop
endmethod
//
// ==== Выполнить функцию для каждого юнита ==========================
method forAll takes UnitExe F returns nothing
local integer i = this.Count - 1
local UNIT UN
loop
exitwhen (i < 0)
set UN = get_UNIT_idx(i)
call F.execute(UN.unit)
set i = i - 1
endloop
endmethod
// ==== Выполнить функцию для каждого юнита ==========================
method forAllUNIT takes UNITExe F returns nothing
local integer i = this.Count - 1
local UNIT UN
loop
exitwhen (i < 0)
set UN = get_UNIT_idx(i)
call F.execute(UN)
set i = i - 1
endloop
endmethod
// ==== Debug тест на повторы юнита ====================
method TestRepCount takes nothing returns boolean
local integer i
local integer j
local integer k
local UNIT UN1
local UNIT UN2
local boolean bool_rep = false
set i = 0
loop
exitwhen (i == this.Count)
set UN1 = get_UNIT_idx(i)
set j = 0
set k = 0
loop
exitwhen (j == this.Count)
set UN2 = get_UNIT_idx(j)
if(UN1 == UN2)then
set k = k + 1
endif
set j = j + 1
endloop
if(k >= 2)then
call BJDebugMsg("Найден повтор: " + I2S(k) + " для " + I2S(UN1))
set bool_rep = true
endif
set i = i + 1
endloop
return bool_rep
endmethod
//
// ==== Добавить юнит в группу =======================================
method Add takes UNIT UN returns UNIT
debug if(not this.isUnitInGroup(UN))then
call UN.SaveInteger(this.pp+1, this.Count)
call UN.SaveBoolean(this.pp, true)
call SaveInteger(thistype.hash, this, this.conv_idx2hashidx(this.Count), UN)
set this.Count = this.Count + 1
set UN.thishandler = this
debug else
debug call BJDebugMsg("Юнит " + GetUnitName(UN.unit) + " уже в группе")
debug endif
return UN
endmethod
//
// ==== Удалить юнита из группы по индексу ==============
method IDRemove takes integer idx returns nothing
local UNIT UN = get_UNIT_idx(idx)
call UN.SaveBoolean(this.pp, false)
set this.Count = this.Count - 1
set this[idx] = get_UNIT_idx(this.Count)
endmethod
//
// ==== Удалить юнита =================================================
method Remove takes UNIT UN returns nothing
set this.Count = this.Count - 1
if(this.get_idx_UNIT(UN) != this.Count)then
set this[this.get_idx_UNIT(UN)] = this[this.Count]
endif
call UN.SaveBoolean(this.pp, false)
endmethod
//
// ==== Получить указатель на параметры юнита в новой группе
private static method get_new_pp takes nothing returns integer
local thistype this
if(thistype.GroupCount == 1)then
return 3
else
set this = thistype.GroupCount - 1
return this.pp + this.np
endif
endmethod
//
// ==== Конструктор ===================================================
static method create takes integer np returns HandlerUnit
local HandlerUnit this = HandlerUnit.allocate()
set thistype.GroupCount = thistype.GroupCount + 1
set this.Count = 0
set this.np = np + this.ppu
set this.pp = thistype.get_new_pp()
set this.p = this.pp + this.ppu
set this.PatchPointer = -1
return this
endmethod
//
//
private static method onInit takes nothing returns nothing
set thistype.hash = InitHashtable()
set thistype.GroupCount = 0
endmethod
endstruct
private function Test takes nothing returns nothing
endfunction
private function onInit takes nothing returns nothing
//call Test()
endfunction
endlibrary
library TimerHandlerLib initializer onInit
globals
private hashtable hash
endglobals
private function RemoveEffect takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyEffect(LoadEffectHandle(hash, GetHandleId(t), 0))
call FlushChildHashtable(hash, GetHandleId(t))
call DestroyTimer(t)
endfunction
function addEffectTimer takes effect ef, real time returns nothing
local timer t = CreateTimer()
call TimerStart(t, time, false, function RemoveEffect)
call SaveEffectHandle(hash, GetHandleId(t), 0, ef)
endfunction
private function RemoveLightning takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyLightning(LoadLightningHandle(hash, GetHandleId(t), 0))
call FlushChildHashtable(hash, GetHandleId(t))
call DestroyTimer(t)
endfunction
private function RemoveTextTag takes nothing returns nothing
local timer t = GetExpiredTimer()
call DestroyTextTag(LoadTextTagHandle(hash, GetHandleId(t), 0))
call FlushChildHashtable(hash, GetHandleId(t))
call DestroyTimer(t)
endfunction
function addLightningTimer takes lightning li, real time returns nothing
local timer t = CreateTimer()
call TimerStart(t, time, false, function RemoveLightning)
call SaveLightningHandle(hash, GetHandleId(t), 0, li)
endfunction
struct TMR
static method GetTimer takes integer TimerId returns timer
return LoadTimerHandle(hash, TimerId, 0)
endmethod
// ====
method operator integer takes nothing returns integer
return LoadInteger(hash, this, 1)
endmethod
method operator timer takes nothing returns timer
return LoadTimerHandle(hash, this, 0)
endmethod
method flush takes nothing returns nothing
call DestroyTimer(this.timer)
call FlushChildHashtable(hash, this)
endmethod
// ====
static method StartInteger takes real timeout, boolean periodic, code func, integer value returns integer
local timer t = CreateTimer()
local integer objectid = GetHandleId(t)
call TimerStart(t, timeout, periodic, func)
call SaveTimerHandle(hash, objectid, 0, t)
call SaveInteger(hash, objectid, 1, value)
return objectid
endmethod
static method addTextTagTimer takes texttag tt, real time returns nothing
local timer t = CreateTimer()
call TimerStart(t, time, false, function RemoveTextTag)
call SaveTextTagHandle(hash, GetHandleId(t), 0, tt)
endmethod
private static method onInit takes nothing returns nothing
set hash = InitHashtable()
endmethod
endstruct
endlibrary
library Handler
// ===== Получить ID-группы типа юнита =============
function GetUnitID takes hashtable hash, unit un returns integer
return LoadInteger(hash, GetHandleId(un), 0)
endfunction
function interface UnitExeFunc takes unit un returns nothing
//! textmacro UnitHashHandler takes TYPE, TYPENUMBER, CHILDKEY
globals
private unit array udg_$TYPE$
private integer udg_$TYPE$_Count = 0
private integer udg_$TYPE$_ForAllPointer = 0
endglobals
// ===== Добавить юниту тип ===========================
private function $TYPE$Add takes unit un returns nothing
call SaveInteger(udg_HashTable, GetHandleId(un), 0, $TYPENUMBER$)
call SaveInteger(udg_HashTable, GetHandleId(un), $CHILDKEY$, udg_$TYPE$_Count)
set udg_$TYPE$[udg_$TYPE$_Count] = un
set udg_$TYPE$_Count = udg_$TYPE$_Count + 1
endfunction
// ==== Удалить у i-го юнита тип ============================================
private function $TYPE$Remove takes integer i returns nothing
set udg_$TYPE$_Count = udg_$TYPE$_Count - 1
call SaveInteger(udg_HashTable, GetHandleId(udg_$TYPE$[udg_$TYPE$_Count]), $CHILDKEY$, i)
call FlushChildHashtable(udg_HashTable, GetHandleId(udg_$TYPE$[i]))
set udg_$TYPE$[i] = udg_$TYPE$[udg_$TYPE$_Count]
endfunction
// ==== Удалить у i-го юнита тип c схранинеим таблицы ======================
private function $TYPE$Remove_HS takes integer i returns nothing
set udg_$TYPE$_Count = udg_$TYPE$_Count - 1
call SaveInteger(udg_HashTable, GetHandleId(udg_$TYPE$[udg_$TYPE$_Count]), $CHILDKEY$, i)
set udg_$TYPE$[i] = udg_$TYPE$[udg_$TYPE$_Count]
endfunction
//
// ==== Удалить юнита =======================================================
private function $TYPE$IDRemove takes unit un returns nothing
call $TYPE$Remove(LoadInteger(udg_HashTable, GetHandleId(un), $CHILDKEY$))
endfunction
//
// ==== Удалить юнита c схранинеим таблицы ===================================
private function $TYPE$IDRemove_HS takes unit un returns nothing
call $TYPE$Remove_HS(LoadInteger(udg_HashTable, GetHandleId(un), $CHILDKEY$))
endfunction
// ====
private function ForAll_$TYPE$ takes UnitExeFunc Func returns nothing
local integer udg_$TYPE$_ForAllPointer = udg_$TYPE$_Count - 1
local unit loc_un
loop
exitwhen(udg_$TYPE$_ForAllPointer < 0)
set loc_un = udg_$TYPE$[udg_$TYPE$_ForAllPointer]
call Func.execute(loc_un)
set udg_$TYPE$_ForAllPointer = udg_$TYPE$_ForAllPointer - 1
endloop
endfunction
//! endtextmacro
endlibrary
library RectSearcher
private function interface ExeFunc takes integer ik, integer jk returns boolean
function runrect takes integer r, ExeFunc F returns boolean
local integer ik
local integer jk
local integer l = 2*r+1 // длинна стороны квадрата
local integer i
local boolean loc_bool
//Верх
set i = 1
set ik = -r+1
set jk = r
loop
if(F.evaluate(ik,jk)) then
return true
endif
set ik = ik + 1
set i = i + 1
exitwhen (i > 2*r)
endloop
//Право
set i = 1
set ik = r
set jk = r-1
loop
if(F.evaluate(ik,jk)) then
return true
endif
set jk = jk - 1
set i = i + 1
exitwhen (i > 2*r)
endloop
//Низ
set i = 1
set ik = r-1
set jk = -r
loop
if(F.evaluate(ik,jk)) then
return true
endif
set ik = ik - 1
set i = i + 1
exitwhen (i > 2*r)
endloop
//Лево
set i = 1
set ik = -r
set jk = -r+1
loop
if(F.evaluate(ik,jk)) then
return true
endif
set jk = jk + 1
set i = i + 1
exitwhen (i > 2*r)
endloop
return false
endfunction
endlibrary
library Dijkstra initializer onInit uses numjuss, MathLib, MatMapLib
//grid_L = 128
globals
private trigger udg_trg_check
private nj_I2D cmap
private matmap cmap_s
private nj_I2D bmap
private matmap bmap_s
private nj_I2D pmap
private matmap pmap_s
endglobals
function get_rar_0 takes integer i0, integer j0 returns nj_I2D
local nj_I2D rar = nj.empty_I2D(4,2)
set rar[0][0] = i0 - 1
set rar[1][0] = i0
set rar[2][0] = i0 + 1
set rar[3][0] = i0
set rar[0][1] = j0
set rar[1][1] = j0 + 1
set rar[2][1] = j0
set rar[3][1] = j0 - 1
return rar
endfunction
struct matmap extends MatMap
method gen_cmap takes nothing returns nothing
local integer i1
local integer j1
local unit un = CreateUnit(Player(0), 'hpea', 0, 0, 0)
set this.map = nj.zeros_I2D(this.shape_x, this.shape_y)
call ShowUnit(un, false)
set i1 = 0
set j1 = 0
loop
exitwhen(i1 == this.shape_x)
set j1 = 0
loop
exitwhen(j1 == this.shape_y)
if(not(IssueBuildOrderById(un, 'htow', mat_i2x(i1), mat_j2y(j1))))then
set this.map[i1][j1] = 1
endif
set j1 = j1 + 1
endloop
set i1 = i1 + 1
endloop
call RemoveUnit(un)
endmethod
method getpath takes integer ie, integer je returns nj_I2D
local integer j
local integer c
local nj_I2D rar_0
local nj_I2D rar
set c = this.map[ie][je]
if(c > 0)then
set rar = nj.empty_I2D(c+1,2)
else
call BJDebugMsg("Хуй")
return nj.empty_I2D(0,2)
endif
set rar[c][0] = ie
set rar[c][1] = je
loop
exitwhen(c == 0)
set j = 0
set rar_0 = get_rar_0(rar[c][0],rar[c][1])
set c = c - 1
loop
exitwhen(j == 4)
if(c == this.map[rar_0[j][0]][rar_0[j][1]])then
set rar[c][0] = rar_0[j][0]
set rar[c][1] = rar_0[j][1]
exitwhen(true)
endif
set j = j + 1
endloop
endloop
return rar
endmethod
endstruct
function get_rar takes nj_I2D rar returns nj_I2D
local nj_I2D loc_rar
local nj_I2D rar2 = nj.empty_I2D(0,2)
local integer i
local integer j
local integer k
set k = 0
set i = 0
loop
exitwhen(i == rar.shape_x)
if(pmap[rar[i][0]][rar[i][1]] != -1)then
set loc_rar = get_rar_0(rar[i][0],rar[i][1])
set j = 0
loop
exitwhen(j == 4)
if(loc_rar[j][0] >= 0 and loc_rar[j][0] < pmap.shape_x and /*
*/loc_rar[j][1] >= 0 and loc_rar[j][1] < pmap.shape_y)then
if(bmap[loc_rar[j][0]][loc_rar[j][1]] == 0)then
set rar2[k][0] = loc_rar[j][0]
set rar2[k][1] = loc_rar[j][1]
set bmap[loc_rar[j][0]][loc_rar[j][1]] = 1
set k = k + 1
endif
endif
set j = j + 1
endloop
endif
set i = i + 1
endloop
set rar2.shape_x = k
set rar2.len = k*2
return rar2
endfunction
private function get_pmap_edge takes nj_I2D rar, integer p returns nothing
local integer i = 0
set i = 0
loop
exitwhen(i == rar.shape_x)
if(cmap[rar[i][0]][rar[i][1]] == 0)then
set pmap[rar[i][0]][rar[i][1]] = p
else
set pmap[rar[i][0]][rar[i][1]] = -1
endif
set i = i + 1
endloop
endfunction
function Dijkstra takes integer i0, integer j0 returns nothing
local integer r_x
local integer r_y
local integer i
local nj_I2D rar = nj.empty_I2D(1,2)
set rar[0][0] = i0
set rar[0][1] = j0
//
set bmap[i0][j0] = 1
set pmap[i0][j0] = 0
set cmap[i0][j0] = 0
//
set i = 0
loop
call get_pmap_edge.execute(rar,i)
set rar = get_rar.evaluate(rar)
set i = i + 1
exitwhen(i == 40 or rar.shape_x == 0)
endloop
endfunction
function pathprint takes nj_I2D path returns nothing
local lightning light
local integer i
local real x1
local real x2
local real y1
local real y2
set i = 0
loop
exitwhen(i == path.shape_x-1)
set x1 = pmap_s.mat_i2x(path[i][0])
set y1 = pmap_s.mat_j2y(path[i][1])
set x2 = pmap_s.mat_i2x(path[i+1][0])
set y2 = pmap_s.mat_j2y(path[i+1][1])
set light = AddLightning("CLPB", false, x1, y1, x2, y2)
call addLightningTimer(light, 2)
set i = i + 1
endloop
endfunction
function map_path takes nothing returns nothing
local nj_I2D path
set cmap_s = matmap.create(16,16)
set bmap_s = matmap.create(16,16)
set pmap_s = matmap.create(16,16)
call cmap_s.gen_cmap.execute()
//
set cmap = cmap_s.map
//
set bmap = nj.zeros_I2D(cmap.shape_x,cmap.shape_y)
set pmap = nj.fill_I2D(cmap.shape_x,cmap.shape_y,-2)
call Dijkstra(5,5)
set pmap_s.map = pmap
call pmap.print()
endfunction
function addCounter takes real X, real Y returns nothing
local integer maxX = R2I(GetRectMaxX(GetWorldBounds()))
local integer minX = R2I(GetRectMinX(GetWorldBounds()))
local integer maxY = R2I(GetRectMaxY(GetWorldBounds()))
local integer minY = R2I(GetRectMinY(GetWorldBounds()))
local real dX = (maxX - minX)/10
local real dY = (maxY - minY)/10
local integer I = math.floor(X/dX) + 5
local integer J = math.floor(Y/dY) + 5
set cmap[I][J] = 1
call BJDebugMsg(I2S(I) + " " + I2S(J))
//call
endfunction
function TestFunc takes nothing returns nothing
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
//
local integer i = cmap_s.mat_x2i(x)
local integer j = cmap_s.mat_y2j(y)
//
call BJDebugMsg(I2S(i) + " " + I2S(j))
call pathprint(pmap_s.getpath.evaluate(i,j))
endfunction
function TestFuncInit takes nothing returns nothing
local trigger trig = CreateTrigger()
call TriggerRegisterPlayerEvent(trig, Player(0), EVENT_PLAYER_MOUSE_DOWN)
call TriggerAddAction( trig, function TestFunc)
endfunction
private function onInit takes nothing returns nothing
call map_path()
call TestFuncInit()
//call BJDebugMsg("Готово")
endfunction
endlibrary
library IsPathing initializer onInit// uses DCSTRA
globals
private trigger udg_trg_mouse
private trigger udg_trg_timer
private integer ung_i = 0
endglobals
private function COLLOF takes nothing returns nothing
call SetUnitPathing( GetEnumUnit(), false )
call ShowUnit(GetEnumUnit(), false)
endfunction
private function COLLON takes nothing returns nothing
call SetUnitPathing( GetEnumUnit(), true )
call ShowUnit(GetEnumUnit(), true)
endfunction
private function MouseAction1 takes nothing returns nothing
local location loc = BlzGetTriggerPlayerMousePosition()
local unit un = gg_unit_hpea_0050
local real X = GetLocationX(loc)
local real Y = GetLocationY(loc)
local group G = GetUnitsInRangeOfLocAll(512, loc)
call ForGroupBJ( G, function COLLOF )
if( IssueBuildOrderById(un, 'hhou', X , Y) )then
call BJDebugMsg("Проходимо")
else
call BJDebugMsg("Не проходимо")
endif
call ForGroupBJ( G, function COLLON )
endfunction
/*
private function MouseAction2 takes nothing returns nothing
local location loc = BlzGetTriggerPlayerMousePosition()
local real X = GetLocationX(loc)
local real Y = GetLocationY(loc)
call addCounter(X,Y)
endfunction
*/
private function MouseAction2 takes nothing returns nothing
local location loc = BlzGetTriggerPlayerMousePosition()
local real X = GetLocationX(loc)
local real Y = GetLocationY(loc)
//call addCounter(X,Y)
endfunction
function TestAction takes nothing returns integer
local integer i = 0
local integer j = ung_i
loop
exitwhen(i == 200000)
set i = i + 1
endloop
set ung_i = ung_i + 1
return ung_i + i
endfunction
private function interface FuncExe takes nothing returns integer
private function TimerAction takes nothing returns nothing
local trigger loc_trg
local integer i = 0
loop
exitwhen(i == 10)
//call BJDebugMsg(I2S(i))
call BJDebugMsg(I2S(TestAction.evaluate()))
//call ExecuteFunc("TestAction")
set i = i + 1
endloop
endfunction
private function onInit takes nothing returns nothing
set udg_trg_mouse = CreateTrigger( )
call TriggerRegisterPlayerEvent(udg_trg_mouse, Player(0), EVENT_PLAYER_MOUSE_DOWN)
call TriggerAddAction( udg_trg_mouse, function MouseAction1 )
//
set udg_trg_timer = CreateTrigger( )
call TriggerRegisterTimerEvent(udg_trg_timer, 2, false)
call TriggerAddAction(udg_trg_timer, function TimerAction)
endfunction
endlibrary
library BuildLib uses RectSearcher
native GetUnitGoldCost takes integer id returns integer
native GetUnitWoodCost takes integer id returns integer
native GetUpgradeGoldCost takes integer id returns integer
native GetUpgradeWoodCost takes integer id returns integer
globals
private integer udg_buildID
private unit udg_witchPeon
private real udg_X_0
private real udg_Y_0
endglobals
//
// ====
function isPlayerHaveRssReserch takes player pl, integer id returns boolean
local integer WoodCost = GetUpgradeWoodCost(id)
local integer GoldCost = GetUpgradeGoldCost(id)
local integer WoodHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_LUMBER)
local integer GoldHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_GOLD)
return (WoodCost <= WoodHave) and (GoldCost <= GoldHave)
endfunction
//
// ====
function isPlayerHaveRssUnit takes player pl, integer id returns boolean
local integer WoodCost = GetUnitWoodCost(id)
local integer GoldCost = GetUnitGoldCost(id)
local integer WoodHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_LUMBER)
local integer GoldHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_GOLD)
return (WoodCost <= WoodHave) and (GoldCost <= GoldHave)
endfunction
private function PointConstraction takes integer ik, integer jk returns boolean
local real X = ik*125. + udg_X_0
local real Y = jk*125. + udg_Y_0
return IssueBuildOrderById(udg_witchPeon, udg_buildID, X, Y)
endfunction
function SearchForBuild takes unit witchPeon, integer buildID, real X, real Y returns boolean
local boolean loc_bool
local integer i = 0
set udg_buildID = buildID
set udg_witchPeon = witchPeon
set udg_X_0 = X
set udg_Y_0 = Y
set loc_bool = IssueBuildOrderById(witchPeon, buildID, X, Y)
set i = i + 1
loop
exitwhen ( loc_bool == true ) or (i == 6)
set loc_bool = runrect(i, PointConstraction)
set i = i + 1
endloop
return loc_bool
endfunction
endlibrary
library AITownLib initializer onInit
globals
private hashtable udg_HashTable
//
private real udg_AttackedX
private real udg_AttackedY
private player udg_AttackedPl
//
private group udg_GroupDeffer
// Тригер отлова атакованных городских
private trigger gg_trg_TwnAtked
// Триггер отлова мертвых городских
private trigger gg_trg_TwnDead
//
private constant integer indexkey = 4
endglobals
private function interface UnitExeFunc takes unit un returns nothing
//
// ===== Получить ID-группы типа юнита =============
private function GetUnGroupID takes unit un returns integer
return LoadInteger(udg_HashTable, GetHandleId(un), 0)
endfunction
//! runtextmacro UnitHashHandler("Citizen", "1", "1")
//! runtextmacro UnitHashHandler("Builder", "1", "2")
//! runtextmacro UnitHashHandler("Deffenser", "1", "3")
//GetAttackedUnitBJ() GetTriggerUnit()
// ==== Добавление юнита в город в защиту ====================
function AddCitizen takes unit un, boolean d_build, boolean b_build returns nothing
call CitizenAdd(un)
// Юнит может принимать участие в защите
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey, d_build)
// Юнит может принимать участие в строительстве
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey+1, b_build)
// Юнит принимает участие в защите прямо сейчас
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey+2, false)
if(b_build) then
call BuilderAdd(un)
endif
endfunction
//
// ==== Удаление юнита отовсюду ==============================
function RemoveCitizen takes unit un returns nothing
local boolean array loc_boolen
local boolean isDefer = LoadBoolean(udg_HashTable, GetHandleId(un), 4)
local unit last_un = udg_Citizen[udg_Citizen_Count]
if(isDefer) then
call GroupRemoveUnit(udg_GroupDeffer, un)
endif
set loc_boolen[0] = LoadBoolean(udg_HashTable, GetHandleId(un), indexkey)
set loc_boolen[1] = LoadBoolean(udg_HashTable, GetHandleId(un), indexkey+1)
set loc_boolen[2] = LoadBoolean(udg_HashTable, GetHandleId(un), indexkey+2)
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey, loc_boolen[0])
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey+1, loc_boolen[1])
call SaveBoolean(udg_HashTable, GetHandleId(un), indexkey+2, loc_boolen[2])
if(loc_boolen[1])then
call BuilderIDRemove_HS(un)
endif
if(loc_boolen[2])then
call DeffenserIDRemove_HS(un)
endif
call CitizenIDRemove(un)
endfunction
//
//
function GetRandomBuilder takes nothing returns unit
local integer loc_int
local integer loc_isbuilder
local unit un
if(udg_Builder_Count > 0)then
set loc_int = GetRandomInt(0, udg_Builder_Count-1)
return udg_Builder[loc_int]
endif
return null
endfunction
//
// ==== Приказ группе атаковать переходя в точку атакованного ====
function ActionFunc takes nothing returns nothing
call IssuePointOrder( GetEnumUnit(), "attack", udg_AttackedX, udg_AttackedY)
call SaveBoolean( udg_HashTable, GetHandleId(GetEnumUnit()), indexkey+2, true)
call DeffenserAdd(GetEnumUnit())
endfunction
//
// ==== Проверка, что юнит может принимать участие в атаке =======
function ConditionFunc takes nothing returns boolean
local boolean loc_bool
set loc_bool = (udg_AttackedPl == GetOwningPlayer(GetFilterUnit()))
if(loc_bool) then
set loc_bool = LoadBoolean(udg_HashTable, GetHandleId(GetFilterUnit()), indexkey)
if(loc_bool)then
set loc_bool = not(LoadBoolean(udg_HashTable, GetHandleId(GetFilterUnit()), indexkey+2))
if(loc_bool)then
return true
endif
endif
endif
return false
endfunction
//
//
function TurnOnAttackTrg takes nothing returns nothing
local timer loc_timer = GetExpiredTimer()
call DestroyTimer(loc_timer)
call EnableTrigger( gg_trg_TwnAtked )
endfunction
//
// Условие для фильтрации живых пауков
function IsLivingSpider takes nothing returns boolean
local unit filterUnit = GetFilterUnit()
return GetUnitTypeId(filterUnit) == 'n001' and not IsUnitDeadBJ(filterUnit)
endfunction
// Условие для фильтрации живых пауков-ткачей
function IsLivingWeaver takes nothing returns boolean
local unit filterUnit = GetFilterUnit()
return GetUnitTypeId(filterUnit) == 'n014' and not IsUnitDeadBJ(filterUnit)
endfunction
// Проверка, изучена ли технология power of treants 2-го уровня для 11 игрока
function IsTechLevelTwoOrAbove takes nothing returns boolean
return GetPlayerTechCount(Player(10), 'R003', true) >= 2
endfunction
// Основное событие при атаке юнита
function Trig_TownLib_Actions takes nothing returns nothing
local unit loc_atcked = GetTriggerUnit()
local unit loc_atckin = GetAttacker()
local real attackedX = GetUnitX(loc_atcked)
local real attackedY = GetUnitY(loc_atcked)
local real attackDamage = BlzGetUnitBaseDamage(loc_atcked, 0)
local timer loc_timer
local group loc_gr
local group spiders
local group weavers
local integer spiderCount = 0
local integer weaverCount = 0
// Проверка, может ли юнит атаковать и не является ли атакующий человек
if attackDamage > 1 and GetPlayerController(GetOwningPlayer(loc_atckin)) != MAP_CONTROL_USER then
set spiders = CreateGroup()
set weavers = CreateGroup()
call GroupEnumUnitsInRange(spiders, attackedX, attackedY, 512, Condition(function IsLivingSpider))
call GroupEnumUnitsInRange(weavers, attackedX, attackedY, 512, Condition(function IsLivingWeaver))
// Подсчет количества пауков и пауков-ткачей
set spiderCount = BlzGroupGetSize(spiders)
set weaverCount = BlzGroupGetSize(weavers)
// Логика отбивания атаки при определенных условиях
if ( (spiderCount <= 2 and weaverCount == 0) /*
*/ or (IsTechLevelTwoOrAbove() and weaverCount == 1 and spiderCount <= 3) /*
*/ or (IsTechLevelTwoOrAbove() and weaverCount == 0 and spiderCount <= 6) ) then
call SaveBoolean(udg_HashTable, GetHandleId(loc_atcked), indexkey+2, true)
call IssueTargetOrder(loc_atcked, "attack", loc_atckin)
call DeffenserAdd(loc_atcked)
set loc_timer = CreateTimer()
call TimerStart(loc_timer, 1, false, function TurnOnAttackTrg)
call DestroyGroup(spiders)
call DestroyGroup(weavers)
set spiders = null
set weavers = null
call DisableTrigger(gg_trg_TwnAtked)
return
endif
call DestroyGroup(spiders)
call DestroyGroup(weavers)
set spiders = null
set weavers = null
endif
// Обычная логика, если атакует больше двух пауков или любой другой юнит
set udg_AttackedX = attackedX
set udg_AttackedY = attackedY
set udg_AttackedPl = GetOwningPlayer(loc_atcked)
if udg_AttackedPl != GetOwningPlayer(loc_atckin) then
set loc_gr = CreateGroup()
call GroupEnumUnitsInRange(loc_gr, udg_AttackedX, udg_AttackedY, 1024, function ConditionFunc)
call ForGroup(loc_gr, function ActionFunc)
call DestroyGroup(loc_gr)
set loc_gr = null
endif
set loc_timer = CreateTimer()
call TimerStart(loc_timer, 1, false, function TurnOnAttackTrg)
call DisableTrigger(gg_trg_TwnAtked)
endfunction
//
// ===== Действие для группы всех городских юнитов =============
function SuperviseUnit takes unit un returns nothing
if (GetUnitCurrentOrder(un) != OrderId("Attack")) then
call SaveBoolean( udg_HashTable, GetHandleId(un), indexkey+2, false)
call DeffenserIDRemove_HS(un)
endif
endfunction
//
// ==== Супервизия всех городских юнитов =======================
function Supervise takes nothing returns nothing
call ForAll_Citizen(SuperviseUnit)
endfunction
//
// ==== Проверка атакован городской ===========================
function CitizenAttacked_Condition takes nothing returns boolean
return LoadInteger(udg_HashTable, GetHandleId(GetTriggerUnit()), 0) != 0
endfunction
//
// ==== Проверка умирел ли городских ===========================
function CitizenDead_Condition takes nothing returns boolean
return LoadInteger(udg_HashTable, GetHandleId(GetDyingUnit()), 0) != 0
endfunction
//
// ==== Действие при смерти городского =========================
function CitizenDead takes nothing returns nothing
call RemoveCitizen(GetDyingUnit())
endfunction
//
// ==== Обработка при прямом удалении юнита
private function HookRemove takes unit un returns nothing
if(GetUnGroupID(un) != 0)then
call RemoveCitizen(un)
endif
endfunction
hook RemoveUnit HookRemove
//
// ==== Триггер инициализации ==================================
private function onInit takes nothing returns nothing
local timer loc_timer
//
set udg_Citizen_Count = 0
set udg_Builder_Count = 0
set udg_Deffenser_Count = 0
set udg_GroupDeffer = CreateGroup()
set udg_HashTable = InitHashtable()
//
// Инициализаця тригера отлавливающего атакованных жителей
set gg_trg_TwnAtked = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_TwnAtked, EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddCondition( gg_trg_TwnAtked, Condition( function CitizenAttacked_Condition ) )
call TriggerAddAction( gg_trg_TwnAtked, function Trig_TownLib_Actions )
//Инициализация триггера отлова мертвых жителей
set gg_trg_TwnDead = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_TwnDead, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_TwnDead, Condition( function CitizenDead_Condition ) )
call TriggerAddAction( gg_trg_TwnDead, function CitizenDead )
set loc_timer = CreateTimer()
call TimerStart(loc_timer, 1.5 ,true, function Supervise )
endfunction
endlibrary
library AIAttackGroupLib initializer onInit
globals
private group array AttackSquad
private integer AttackSquad_Count
private hashtable udg_HashTable
//
private real udg_X
private real udg_Y
endglobals
function AttackSquadCreate takes nothing returns integer
set AttackSquad[AttackSquad_Count] = CreateGroup()
set AttackSquad_Count = AttackSquad_Count + 1
return AttackSquad_Count - 1
endfunction
function UnitAddSquad takes unit un, integer n_squad returns nothing
call GroupAddUnit(AttackSquad[n_squad],un)
call SaveInteger(udg_HashTable, GetHandleId(un),0,n_squad+1)
endfunction
private function ActionFunc takes nothing returns nothing
call IssuePointOrder( GetEnumUnit(), "attack", udg_X, udg_Y)
endfunction
function SquadAttackPoint takes integer n_squad, real X, real Y returns nothing
set udg_X = X
set udg_Y = Y
call ForGroup(AttackSquad[n_squad], function ActionFunc)
endfunction
private function onInit takes nothing returns nothing
set AttackSquad_Count = 0
set udg_HashTable = InitHashtable()
endfunction
endlibrary
library AIHarvestLib2 initializer onInit uses HandlerLib
/*
function AddHarvester unit un returns nothing
*/
globals
private hashtable udg_HashTable
private trigger udg_trg_dyinghrv
private trigger udg_trg_dyingtype
//
// 1 - обычныйе харвестеры
private HandlerUnit HrvsCom
// 2 - харвестеры без приказа
private HandlerUnit HrvsNotOrder
// 3 - харвестеры получившие приказ
private HandlerUnit HrvsGotOrder
// 4 - ожидающие харвестеры
private HandlerUnit HrvsWait
endglobals
//
// ===== Проверка умер ли юнит с типом ======
private function IsDiyngType_Conditions takes nothing returns boolean
return HandlerUnit.isUnitIn(GetDyingUnit())
endfunction
//
// Добавить харвестера
function AddHarvester takes unit un returns nothing
local UNIT UN = UNIT.create(un)
call HrvsCom.Add(UN)
endfunction
//
// Удалить харвестера
function RemoveHarvester takes unit un returns nothing
local UNIT UN = GetHandleId(un)
if (HandlerUnit.isUnitIn(un)) then
if (HrvsCom.isUnitInGroup(UN)) then
call HrvsCom.Remove(UN)
elseif (HrvsNotOrder.isUnitInGroup(UN)) then
call HrvsNotOrder.Remove(UN)
elseif (HrvsGotOrder.isUnitInGroup(UN)) then
call HrvsGotOrder.Remove(UN)
elseif (HrvsWait.isUnitInGroup(UN)) then
call HrvsWait.Remove(UN)
endif
call UN.flush()
endif
endfunction
//
// ===== Проверка на изменения приказа ======
private function OrderCheck_HrvsGotOrder takes unit un returns nothing
local integer loc_order = GetUnitCurrentOrder(un)
local UNIT UN = GetHandleId(un)
if( loc_order != 0 ) then
// Приказ изменился
call HrvsGotOrder.Remove(UN)
call HrvsCom.Add(UN)
//call BJDebugMsg("Приказ изменился")
else
// Приказ не изменился
call HrvsGotOrder.Remove(UN)
call HrvsWait.Add(UN)
debug call BJDebugMsg( "Приказ не изменился: " + GetUnitName(un) )
endif
endfunction
//
// ==== Обработка при прямом удалении юнита
private function HookRemove takes unit un returns nothing
if (HandlerUnit.isUnitIn(un)) then
call RemoveHarvester(un)
endif
endfunction
hook RemoveUnit HookRemove
//
// ===== Отдать приказ харвестеру
private function GiveOrder_HrvsNotOrder takes unit un returns nothing
local UNIT UN = GetHandleId(un)
if(un != null) then
call IssueImmediateOrder( un, "autoharvestlumber" )
debug else
debug call BJDebugMsg("Пытаюсь отдать приказ null")
endif
call HrvsNotOrder.Remove(UN)
call HrvsGotOrder.Add(UN)
endfunction
//
// ===== Проверка харвестера на наличие приказа
private function OrderCheck_HrvsCom takes unit un returns nothing
local UNIT UN = GetHandleId(un)
local integer loc_order = GetUnitCurrentOrder(un)
if(loc_order == 0) then
call HrvsCom.Remove(UN)
call HrvsNotOrder.Add(UN)
endif
endfunction
//
// ===== Проверка харвестера на наличие приказа
private function WaitersRefersh takes unit un returns nothing
local UNIT UN = GetHandleId(un)
local integer loc_order = GetUnitCurrentOrder(un)
if(loc_order == 0) then
call HrvsWait.Remove(UN)
call HrvsNotOrder.Add(UN)
endif
endfunction
//
//
private function DebugHrvs takes nothing returns nothing
local string SI1 = I2S(HrvsCom.Count)
local string SI2 = I2S(HrvsGotOrder.Count)
local string SI3 = I2S(HrvsNotOrder.Count)
debug call BJDebugMsg("C: " + SI1 + " G: " + SI2 + " N: " + SI3)
endfunction
//
// ===== Супервизия харвестеров =======================
private function Supervise takes nothing returns nothing
//call DebugHrvs()
call HrvsCom.forAll(OrderCheck_HrvsCom)
//call DebugHrvs()
call HrvsNotOrder.forPatch(GiveOrder_HrvsNotOrder)
//call DebugHrvs()
call HrvsGotOrder.forAll(OrderCheck_HrvsGotOrder)
//call DebugHrvs()
endfunction
//
// ===== Обновления массива ожидающих харвестеров =====
private function WaiterRefresh_Periodic takes nothing returns nothing
call HrvsWait.forPatch(WaitersRefersh)
endfunction
//
// ===== Начало супервизии харвестеров ======
private function SuperviseStart takes nothing returns nothing
local timer loc_timer_s
local timer loc_timer_wr
set loc_timer_s = CreateTimer()
set loc_timer_wr = CreateTimer()
call TimerStart(loc_timer_s, 5 ,true,function Supervise )
call TimerStart(loc_timer_wr, 20 ,true,function WaiterRefresh_Periodic )
endfunction
//
// ====== Что делать с мертвым харвестером
private function AIhrvstDead takes nothing returns nothing
call RemoveHarvester(GetDyingUnit())
endfunction
//
struct AI_HRVS
//
// ===== Инициализация переменных системы
static method Init_AIHarvestLib takes nothing returns nothing
set udg_HashTable = InitHashtable()
set HrvsCom = HandlerUnit.create(0)
set HrvsNotOrder = HandlerUnit.create(0)
set HrvsGotOrder = HandlerUnit.create(0)
set HrvsWait = HandlerUnit.create(0)
call SuperviseStart()
endmethod
private static method B2S takes boolean b returns string
if(b)then
return "true"
else
return "false"
endif
endmethod
static method TestSystem takes nothing returns nothing
if(HrvsCom.TestRepCount())then
call BJDebugMsg("При тестированни HrvsCom найдены повторы")
else
call BJDebugMsg("При тестированни HrvsCom повторы не найдены ")
endif
if(HrvsNotOrder.TestRepCount())then
call BJDebugMsg("При тестированни HrvsNotOrder найдены повторы")
else
call BJDebugMsg("При тестированни HrvsNotOrder повторы не найдены ")
endif
if(HrvsGotOrder.TestRepCount())then
call BJDebugMsg("При тестированни HrvsGotOrder найдены повторы")
else
call BJDebugMsg("При тестированни HrvsGotOrder повторы не найдены ")
endif
if(HrvsWait.TestRepCount())then
call BJDebugMsg("При тестированни HrvsWait найдены повторы")
else
call BJDebugMsg("При тестированни HrvsWait повторы не найдены ")
endif
call BJDebugMsg("При тестированни HrvsCom повторы не найдены ")
call DebugHrvs()
endmethod
static method TestUnit takes unit un returns nothing
local UNIT UN = GetHandleId(un)
if(UN.isin)then
call BJDebugMsg("Юнит " + I2S(UN) + " в системе UNIT")
call BJDebugMsg("Юнит в группе " + I2S(HrvsCom) + " HrvsCom " + B2S(HrvsCom.isUnitInGroup(UN)))
call BJDebugMsg("Юнит в группе " + I2S(HrvsNotOrder) + " HrvsNotOrder " + B2S(HrvsNotOrder.isUnitInGroup(UN)))
call BJDebugMsg("Юнит в группе " + I2S(HrvsGotOrder) + " HrvsGotOrder " + B2S(HrvsGotOrder.isUnitInGroup(UN)))
call BJDebugMsg("Юнит в группе " + I2S(HrvsWait) + " HrvsWait " + B2S(HrvsWait.isUnitInGroup(UN)))
endif
endmethod
static method TrgSelectUnit takes nothing returns nothing
call TestUnit(GetTriggerUnit())
endmethod
private static trigger test_chat
private static trigger test_select
private static boolean test_bool
private static method TestInit takes nothing returns nothing
if(not(test_bool))then
set test_chat = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( test_chat, Player(0), "hrvstest", true )
call TriggerAddAction( test_chat, function thistype.TestSystem )
//
set test_select = CreateTrigger( )
call TriggerRegisterPlayerSelectionEventBJ( test_select, Player(0), true )
call TriggerAddAction( test_select, function thistype.TrgSelectUnit )
call BJDebugMsg("Тестовые триггеры включены")
else
call DestroyTrigger(test_chat)
call DestroyTrigger(test_select)
call BJDebugMsg("Тестовые триггеры включены")
endif
endmethod
static method onInit takes nothing returns nothing
local trigger trg
//call TestInit()
set test_bool = false
set trg = CreateTrigger( )
call TriggerRegisterPlayerChatEvent( trg, Player(0), "testonoff", true )
call TriggerAddAction( trg, function thistype.TestInit )
endmethod
endstruct
//
// ====== Полная инициализация ==================
private function onInit takes nothing returns nothing
call AI_HRVS.Init_AIHarvestLib()
set udg_trg_dyinghrv = CreateTrigger()
// Инициализация триггера отслеживающая мертвых харвестеров
call TriggerRegisterAnyUnitEventBJ( udg_trg_dyinghrv, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( udg_trg_dyinghrv, Condition( function IsDiyngType_Conditions ) )
call TriggerAddAction( udg_trg_dyinghrv, function AIhrvstDead )
endfunction
endlibrary
library MainMapCore initializer onInit uses AICore, Demons
globals
trigger udg_trg_UnitDeath
trigger udg_trg_ElapsedINITrg_AI
trigger udg_trg_EventTraine
trigger udg_trg_EventBuildIni
trigger udg_trg_EventUnitAttacked
/*
Хэш таблица
uses in: SpidersLib
*/ hashtable udg_HashTable//
real udg_MapMinX
real udg_MapMaxX
real udg_MapMinY
real udg_MapMaxY
endglobals
function Initialization_ALL takes nothing returns nothing
set udg_MapMinX = GetRectMinX(GetEntireMapRect())
set udg_MapMaxX = GetRectMaxX(GetEntireMapRect())
set udg_MapMinY = GetRectMinY(GetEntireMapRect())
set udg_MapMaxY = GetRectMaxY(GetEntireMapRect())
//Инициализация основной хзш таблицы
set udg_HashTable = InitHashtable()
//Ini_AI
call Initialz_AI()
//Инициализация шуток лешего
call Leshi_Jokes_INI()
//Инициализация погоды
call WeatherINI()
//Инициализация демонов
call DemonInvasionINI()
// Инициализация перехода на 1 страницу при выборе складов
call InitTrig_OnUnitSelected()
endfunction
//
// ====
native GetUnitGoldCost takes integer id returns integer
native GetUnitWoodCost takes integer id returns integer
native GetUpgradeGoldCost takes integer id returns integer
native GetUpgradeWoodCost takes integer id returns integer
//
// ==== Функция обрабатывающая сметри юнитов
function UnitDeathAction takes nothing returns nothing
local unit Dying = GetDyingUnit()
local integer loc_DyingTypeID = GetUnitTypeId(Dying)
//Смерть юнитов AI
if(Trig_AIEntDeath_Actions(Dying, loc_DyingTypeID))then
return
endif
//Молния
if(LightingRemove(Dying, loc_DyingTypeID))then
return
endif
//Демоны
if(DemonsDeath(Dying, loc_DyingTypeID))then
return
endif
endfunction
//
//Событие того что юнит атакован
function Trig_UnitAttacked takes nothing returns nothing
local unit loc_Attaked = GetTriggerUnit() //Атакованный
local unit loc_Attaker = GetAttacker() //Атакующий
//Спасение виспа
if(WispMove(loc_Attaked))then
return
endif
endfunction
//===========================================================================
private function onInit takes nothing returns nothing
//ElapsedINICore//Инициализация через 0.05
set udg_trg_ElapsedINITrg_AI = CreateTrigger( )
call TriggerRegisterTimerEvent(udg_trg_ElapsedINITrg_AI, 0.1, false )
call TriggerAddAction(udg_trg_ElapsedINITrg_AI, function Initialization_ALL)
//Событие смерти юнита
set udg_trg_UnitDeath = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ(udg_trg_UnitDeath, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddAction( udg_trg_UnitDeath, function UnitDeathAction )
//Событие того ,что юнит атакован
set udg_trg_EventUnitAttacked = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( udg_trg_EventUnitAttacked,EVENT_PLAYER_UNIT_ATTACKED )
call TriggerAddAction( udg_trg_EventUnitAttacked, function Trig_UnitAttacked )
endfunction
endlibrary
library LandscapeLib
globals
trigger udg_trg_landscapegen
endglobals
// =====
private function LandscapeGen takes nothing returns nothing
local real loc_minX = GetRectMinX(GetEntireMapRect())
local real loc_minY = GetRectMinY(GetEntireMapRect())
local real loc_maxX = GetRectMaxX(GetEntireMapRect())
local real loc_maxY = GetRectMaxY(GetEntireMapRect())
local integer array loc_TerrianType
local integer array loc_TerrianType_W
local integer array loc_TerrianType_Size
local integer loc_TerrianType_WM = 0
local integer loc_TerrianTypeCount
local integer loc_rintx
local integer loc_rinty
local integer i
local real loc_X
local real loc_Y
//
set loc_TerrianType[0] = 'Lgrs'
set loc_TerrianType[1] = 'Lgrd'
set loc_TerrianType[2] = 'Ldro'
set loc_TerrianType[3] = 'Ldrt'
//
set loc_TerrianType_W[0] = 4
set loc_TerrianType_W[1] = 4
set loc_TerrianType_W[2] = 1
set loc_TerrianType_W[3] = 1
//
set loc_TerrianType_Size[0] = 2
set loc_TerrianType_Size[1] = 2
set loc_TerrianType_Size[2] = 1
set loc_TerrianType_Size[3] = 1
//
set loc_TerrianTypeCount = 4
//
set i = 0
loop
exitwhen (i == loc_TerrianTypeCount)
if(loc_TerrianType_WM < loc_TerrianType_W[i])then
set loc_TerrianType_WM = loc_TerrianType_W[i]
endif
set i = i + 1
endloop
//
set i = 0
loop
exitwhen(i == 8000)
loop
set loc_rintx = GetRandomInt(0,loc_TerrianTypeCount-1)
set loc_rinty = GetRandomInt(1,loc_TerrianType_WM)
exitwhen( loc_TerrianType_W[loc_rintx] <= loc_rinty)
endloop
set loc_X = GetRandomReal(loc_minX, loc_maxX)
set loc_Y = GetRandomReal(loc_minY, loc_maxY)
call SetTerrainType(loc_X, loc_Y, loc_TerrianType[loc_rintx], -1, loc_TerrianType_Size[loc_rintx], 0)
set i = i + 1
endloop
endfunction
private function TerrianDeformGen takes nothing returns nothing
local real loc_minX = GetRectMinX(GetEntireMapRect())
local real loc_minY = GetRectMinY(GetEntireMapRect())
local real loc_maxX = GetRectMaxX(GetEntireMapRect())
local real loc_maxY = GetRectMaxY(GetEntireMapRect())
local real loc_X
local real loc_Y
local integer i
set i = 0
loop
set loc_X = GetRandomReal(loc_minX, loc_maxX)
set loc_Y = GetRandomReal(loc_minY, loc_maxY)
call TerrainDeformCrater(loc_X, loc_Y, 512, GetRandomInt(-10, 10) * 1, 1, true)
set i = i + 1
exitwhen(i == 2000)
endloop
//call BJDebugMsg(I2S(i))
endfunction
private function CreateEnviroment takes nothing returns nothing
local real loc_minX = GetRectMinX(GetPlayableMapRect())
local real loc_minY = GetRectMinY(GetPlayableMapRect())
local real loc_maxX = GetRectMaxX(GetPlayableMapRect())
local real loc_maxY = GetRectMaxY(GetPlayableMapRect())
local integer i
local string array ModelPathArray
local integer ModelPathArrayCount
local effect loc_effect
local real loc_X
local real loc_Y
set ModelPathArray[0] = "Doodads\\Ruins\\Plants\\Ruins_Shrub\\Ruins_Shrub0.mdl"
set ModelPathArray[1] = "Doodads\\Ruins\\Plants\\Ruins_Shrub\\Ruins_Shrub1.mdl"
set ModelPathArray[2] = "Doodads\\Ruins\\Plants\\Ruins_Shrub\\Ruins_Shrub2.mdl"
set ModelPathArray[3] = "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower0.mdl"
set ModelPathArray[4] = "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower1.mdl"
set ModelPathArray[5] = "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower2.mdl"
set ModelPathArray[6] = "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower3.mdl"
set ModelPathArray[7] = "Doodads\\Ruins\\Plants\\Ruins_Flower\\Ruins_Flower4.mdl"
set ModelPathArrayCount = 8
set i = 0
loop
set loc_X = GetRandomReal(loc_minX, loc_maxX)
set loc_Y = GetRandomReal(loc_minY, loc_maxY)
set loc_effect = AddSpecialEffect(ModelPathArray[GetRandomInt(0,ModelPathArrayCount-1)], loc_X, loc_Y)
call BlzSetSpecialEffectYaw(loc_effect,GetRandomReal(0, 2*bj_PI))
call BlzSetSpecialEffectScale(loc_effect,GetRandomReal(0.8, 1.2))
set i = i + 1
exitwhen(i == 200)
endloop
endfunction
//===========================================================================
function InitTrig_LandscapeLib takes nothing returns nothing
local trigger loc_trg_LandscapeGen = CreateTrigger()
call TriggerRegisterTimerEventSingle( loc_trg_LandscapeGen, 0.50 )
call TriggerAddAction( loc_trg_LandscapeGen, function CreateEnviroment )
call LandscapeGen()
call TerrianDeformGen()
endfunction
endlibrary
globals
hashtable GoblinRepair = InitHashtable( )
endglobals
function Trig_Caster_Repair_Buff_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00A'
endfunction
function Trig_Caster_Repair_Buff_Actions takes nothing returns nothing
set bj_lastCreatedEffect = AddSpecialEffectTarget ( "war3mapImported\\repair.mdx", GetTriggerUnit ( ), "overhead" )
call SaveEffectHandle( GoblinRepair, GetHandleId ( GetTriggerUnit( ) ), 0, bj_lastCreatedEffect )
endfunction
//===========================================================================
function InitTrig_Caster_Repair_Buff takes nothing returns nothing
set gg_trg_Caster_Repair_Buff = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Caster_Repair_Buff, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Caster_Repair_Buff, Condition( function Trig_Caster_Repair_Buff_Conditions ) )
call TriggerAddAction( gg_trg_Caster_Repair_Buff, function Trig_Caster_Repair_Buff_Actions )
endfunction
function Trig_Caster_Stop_Repair_Buff_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A00A'
endfunction
function Trig_Caster_Stop_Repair_Buff_Actions takes nothing returns nothing
set bj_lastCreatedEffect = LoadEffectHandle( GoblinRepair, GetHandleId ( GetTriggerUnit ( ) ), 0 )
call DestroyEffect ( bj_lastCreatedEffect )
call RemoveSavedHandle ( GoblinRepair, GetHandleId ( GetTriggerUnit ( ) ), 0 )
endfunction
//===========================================================================
function InitTrig_Caster_Stop_Repair_Buff takes nothing returns nothing
set gg_trg_Caster_Stop_Repair_Buff = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Caster_Stop_Repair_Buff, EVENT_PLAYER_UNIT_SPELL_ENDCAST )
call TriggerAddCondition( gg_trg_Caster_Stop_Repair_Buff, Condition( function Trig_Caster_Stop_Repair_Buff_Conditions ) )
call TriggerAddAction( gg_trg_Caster_Stop_Repair_Buff, function Trig_Caster_Stop_Repair_Buff_Actions )
endfunction
library PillageGold uses DefaultTextTag
struct PillageGold
static method run takes unit src_un, unit tg_un, integer amount returns nothing
local integer curGold = GetPlayerState(GetOwningPlayer(tg_un), PLAYER_STATE_RESOURCE_GOLD)
local string loc_str
local texttag tt
local real x = GetUnitX(src_un)
local real y = GetUnitY(src_un)
local integer i = 0
local player p
// Проверка количества золота
if curGold > 0 then
if curGold < amount then
set amount = curGold
endif
else
return
endif
// Форматирование строки для текстовой метки
set loc_str = "+" + I2S(amount)
// Регулировка состояния игрока (добавление и вычитание золота)
call AdjustPlayerStateBJ(amount, GetOwningPlayer(src_un), PLAYER_STATE_RESOURCE_GOLD)
call AdjustPlayerStateBJ(-amount, GetOwningPlayer(tg_un), PLAYER_STATE_RESOURCE_GOLD)
// Создание текстовой метки
set tt = DefaultTextTag(TextTagGoldBounty, x, y, loc_str)
// Установка видимости текстовой метки для всех игроков, которым виден юнит
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set p = Player(i)
if IsUnitVisible(src_un, p) and GetLocalPlayer() == p then
call SetTextTagVisibility(tt, true)
endif
set i = i + 1
endloop
endmethod
endstruct
endlibrary
library PillageLumber uses DefaultTextTag
struct PillageLumber
static method run takes unit src_un, unit tg_un, integer amount returns nothing
local integer curLumber = GetPlayerState(GetOwningPlayer(tg_un), PLAYER_STATE_RESOURCE_LUMBER)
local string loc_str
local texttag tt
local real x = GetUnitX(src_un)
local real y = GetUnitY(src_un)
local integer i = 0
local player p
// Проверка количества древесины
if curLumber > 0 then
if curLumber < amount then
set amount = curLumber
endif
else
return
endif
// Форматирование строки для текстовой метки
set loc_str = "+" + I2S(amount)
// Регулировка состояния игрока (добавление и вычитание древесины)
call AdjustPlayerStateBJ(amount, GetOwningPlayer(src_un), PLAYER_STATE_RESOURCE_LUMBER)
call AdjustPlayerStateBJ(-amount, GetOwningPlayer(tg_un), PLAYER_STATE_RESOURCE_LUMBER)
// Создание текстовой метки
set tt = DefaultTextTag(TextTagLumberBounty, x, y, loc_str)
// Установка видимости текстовой метки для всех игроков, которым виден юнит
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set p = Player(i)
if IsUnitVisible(src_un, p) and GetLocalPlayer() == p then
call SetTextTagVisibility(tt, true)
endif
set i = i + 1
endloop
endmethod
endstruct
endlibrary
library Roots initializer onInit
globals
private player player_caster
endglobals
// Проверка способности "Гнев деревьев (область)"
private function Roots_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A001'
endfunction
// Проверка, что владелец юнита цели не является владельцем кастера
private function IsNotPlayerCaster takes nothing returns boolean
return GetOwningPlayer(GetEnumUnit()) != player_caster
endfunction
// Функция для создания фиктивного юнита и применения способности
private function CreateDummyAndCast takes unit target, real damage returns nothing
local ability abl
local real x = GetUnitX(target)
local real y = GetUnitY(target)
local unit un = CreateUnit(player_caster, 'h002', x, y, bj_UNIT_FACING)
call UnitAddAbility(un, 'A00O')
set abl = BlzGetUnitAbility(un, 'A00O')
call BlzSetAbilityRealLevelField( abl, ABILITY_RLF_DAMAGE_PER_SECOND_EER1, 0, damage )
call UnitApplyTimedLife(un, 'BTLF', 2.00)
call IssueTargetOrder(un, "entanglingroots", target)
endfunction
// Функция для обработки группы юнитов и применения способности в зависимости от уровня "Гнев деревьев"
private function ProcessGroup takes real damage, real radius returns nothing
local group g = CreateGroup()
local location sptl = GetSpellTargetLoc()
local unit u
local integer i = 0
local integer gsize
set player_caster = GetOwningPlayer(GetSpellAbilityUnit())
call GroupEnumUnitsInRangeOfLoc(g, sptl, radius, Condition(function IsNotPlayerCaster))
set gsize = BlzGroupGetSize(g)
//
loop
exitwhen (i == gsize)
set u = BlzGroupUnitAt(g, i)
if (i <= 5) then
call CreateDummyAndCast.evaluate(u, damage)
else
if (GetRandomInt(0,1) == 0) then
call CreateDummyAndCast.evaluate(u, damage)
else
call CreateDummyAndCast.evaluate(u, GetUnitState(u, UNIT_STATE_MAX_LIFE)*0.033)
endif
endif
set i = i + 1
endloop
//
call DestroyGroup(g) // Удаляем группу, чтобы избежать утечек
call RemoveLocation(sptl)
set g = null
set sptl = null
endfunction
// Основная функция триггера, которая вызывает ProcessGroup с нужной способностью
private function Roots_Actions takes nothing returns nothing
local unit un = GetSpellAbilityUnit()
local integer ablvl = GetUnitAbilityLevel(un, 'A001') - 1 // индексация начинается с единицы, поэтому -1
local real radius = BlzGetAbilityRealLevelField(/*
*/BlzGetUnitAbility(un, 'A001'), ABILITY_RLF_AREA_OF_EFFECT, ablvl)
if ablvl == 0 then
call ProcessGroup(40.0, radius)
elseif ablvl == 1 then
call ProcessGroup(180.0, radius)
elseif ablvl == 2 then
call ProcessGroup(650.0, radius)
endif
endfunction
// Инициализация триггера
private function onInit takes nothing returns nothing
local trigger trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(trg, Condition(function Roots_Conditions))
call TriggerAddAction(trg, function Roots_Actions)
endfunction
endlibrary
library Keeper initializer onInit
globals
private timer timer_treereviving = null
private timer timer_owl = null
private timer timer_treant = null
private timer timer_roots = null
private unit Keeper
endglobals
// Функция для приказа "Воскрешение деревьев"
function KeeperCastTreeReviving takes nothing returns nothing
local real xmin = GetRectMinX(GetPlayableMapRect())
local real xmax = GetRectMaxX(GetPlayableMapRect())
local real ymin = GetRectMinY(GetPlayableMapRect())
local real ymax = GetRectMaxY(GetPlayableMapRect())
local real x = GetRandomReal(xmin, xmax)
local real y = GetRandomReal(ymin, ymax)
call IssuePointOrder(Keeper, "rainoffire", x, y)
endfunction
// Функция для приказа "Сова"
function KeeperCastOwl takes nothing returns nothing
local destructable dstr = RandomDestructableInRectSimpleBJ(GetPlayableMapRect())
call IssueTargetDestructableOrder(Keeper, "sentinel", dstr)
endfunction
// Функция для приказа "Призыв энта"
function KeeperCastTreant takes nothing returns nothing
local real xmin = GetRectMinX(GetPlayableMapRect())
local real xmax = GetRectMaxX(GetPlayableMapRect())
local real ymin = GetRectMinY(GetPlayableMapRect())
local real ymax = GetRectMaxY(GetPlayableMapRect())
local real x = GetRandomReal(xmin, xmax)
local real y = GetRandomReal(ymin, ymax)
call IssuePointOrder(Keeper, "forceofnature", x, y)
endfunction
// Функция для приказа "Корни"
function KeeperCastRoots takes nothing returns nothing
local real xmin = GetRectMinX(GetPlayableMapRect())
local real xmax = GetRectMaxX(GetPlayableMapRect())
local real ymin = GetRectMinY(GetPlayableMapRect())
local real ymax = GetRectMaxY(GetPlayableMapRect())
local real x = GetRandomReal(xmin, xmax)
local real y = GetRandomReal(ymin, ymax)
call IssuePointOrder(Keeper, "cloudoffog", x, y)
endfunction
// Функция для запуска таймера "Воскрешение деревьев"
function KeeperTreeRevivingStart takes integer lvl returns nothing
if (timer_treereviving != null) then
call DestroyTimer(timer_treereviving)
endif
set timer_treereviving = CreateTimer()
if (lvl == 1) then
call TimerStart(timer_treereviving, 33.0, true, function KeeperCastTreeReviving)
elseif (lvl == 2) then
call TimerStart(timer_treereviving, 16.5, true, function KeeperCastTreeReviving)
endif
endfunction
// Функция для запуска таймера "Сова"
function KeeperOwlStart takes nothing returns nothing
if (timer_owl != null) then
call DestroyTimer(timer_owl)
endif
set timer_owl = CreateTimer()
call TimerStart(timer_owl, 20.0, true, function KeeperCastOwl)
endfunction
// Функция для запуска таймера "Призыв энта"
function KeeperTreantStart takes nothing returns nothing
if (timer_treant != null) then
call DestroyTimer(timer_treant)
endif
set timer_treant = CreateTimer()
call TimerStart(timer_treant, 20.0, true, function KeeperCastTreant)
endfunction
// Функция для запуска таймера "Корни"
function KeeperRootsStart takes nothing returns nothing
if (timer_roots != null) then
call DestroyTimer(timer_roots)
endif
set timer_roots = CreateTimer()
call TimerStart(timer_roots, 11.5, true, function KeeperCastRoots)
endfunction
// Функция для старта соответствующих таймеров в зависимости от уровня тира энтов
function KeeperCastStart takes integer tier returns nothing
if (tier == 0) then
call KeeperTreantStart()
elseif (tier == 1) then
call KeeperRootsStart()
call KeeperOwlStart()
elseif (tier == 2) then
call KeeperTreeRevivingStart(1)
elseif (tier == 5) then
call KeeperTreeRevivingStart(2)
endif
endfunction
private function onInit takes nothing returns nothing
set Keeper = gg_unit_E00D_0012
endfunction
endlibrary
globals
hashtable itemTable = InitHashtable()
endglobals
// Функция для проверки, используется ли определенная способность
function Trig_Unit_Upgrade_FuncC takes integer abilityId returns boolean
return GetSpellAbilityId() == abilityId
endfunction
// Сохранение предметов юнита в хэш-таблицу
function SaveUnitItems takes unit u, integer unitId returns nothing
local integer i = 0
loop
exitwhen i >= 6
call SaveItemHandle(itemTable, unitId, i, UnitItemInSlot(u, i))
set i = i + 1
endloop
endfunction
// Восстановление предметов юнита из хэш-таблицы
function RestoreUnitItems takes unit u, integer unitId returns nothing
local integer i = 0
local item itm
loop
exitwhen i >= 6
set itm = LoadItemHandle(itemTable, unitId, i)
if itm != null then
call UnitAddItem(u, itm)
endif
set i = i + 1
endloop
endfunction
// Очистка предметов юнита из хэш-таблицы
function ClearUnitItems takes integer unitId returns nothing
local integer i = 0
loop
exitwhen i >= 6
call RemoveSavedHandle(itemTable, unitId, i)
set i = i + 1
endloop
endfunction
// Замена юнита с переносом предметов и добавлением эффекта
function ReplaceUnitWithItems takes unit u, integer newUnitId, string effectPath, string attachPoint, real effectScale, real effectDuration returns unit
local integer unitId = GetHandleId(u)
local unit newUnit
local player owner = GetOwningPlayer(u)
call SaveUnitItems(u, unitId)
call ShowUnit(u, false)
set newUnit = ReplaceUnitBJ(u, newUnitId, bj_UNIT_STATE_METHOD_RELATIVE)
call RestoreUnitItems(newUnit, unitId)
call ClearUnitItems(unitId)
call AddSpecialEffectTargetUnitBJ(attachPoint, newUnit, effectPath)
call BlzSetSpecialEffectScale(GetLastCreatedEffectBJ(), effectScale)
call addEffectTimer(GetLastCreatedEffectBJ(), effectDuration)
// Выбор нового юнита для игрока
call SelectUnit(newUnit, true)
return newUnit
endfunction
// Основная функция для обработки улучшений юнита
function Trig_Unit_Upgrade_Actions takes nothing returns nothing
local unit u = GetSpellAbilityUnit()
if Trig_Unit_Upgrade_FuncC('A02Q') then
call ReplaceUnitWithItems(u, 'o00R', "war3mapImported\\Armor Stimulus Orange.mdx", "overhead", 1.0, 3.0)
elseif Trig_Unit_Upgrade_FuncC('A02V') then
call ReplaceUnitWithItems(u, 'o00S', "war3mapImported\\Armor Stimulus Orange.mdx", "overhead", 1.0, 3.0)
elseif Trig_Unit_Upgrade_FuncC('A02T') then
call ReplaceUnitWithItems(u, 'o00V', "war3mapImported\\Heal.mdx", "origin", 0.6, 5.0)
elseif Trig_Unit_Upgrade_FuncC('A02R') then
call ReplaceUnitWithItems(u, 'o00D', "war3mapImported\\Heal Gold.mdx", "origin", 0.6, 5.0)
elseif Trig_Unit_Upgrade_FuncC('A02U') then
call ReplaceUnitWithItems(u, 'o005', "war3mapImported\\Heal Orange.mdx", "origin", 0.6, 5.0)
elseif Trig_Unit_Upgrade_FuncC('A02S') then
call ReplaceUnitWithItems(u, 'o00T', "war3mapImported\\Armor Stimulus Red.mdx", "overhead", 1.0, 3.0)
elseif Trig_Unit_Upgrade_FuncC('A02W') then
call ReplaceUnitWithItems(u, 'o00U', "war3mapImported\\Armor Stimulus Red.mdx", "overhead", 1.0, 3.0)
endif
// Очистка локальной переменной
set u = null
endfunction
// Инициализация триггера для обработки улучшений юнита
function InitTrig_Unit_Upgrade takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddAction(t, function Trig_Unit_Upgrade_Actions)
set gg_trg_Unit_Upgrade = t
endfunction
library AbilityToggleSystem initializer onInit
globals
private constant integer RESEARCH_COUNT = 7
private boolean array researchCompleted
private integer array RESEARCH_IDS
private integer array UNIT_TYPES_OLD
private integer array ABILITIES_OLD
private integer array ABILITIES_NEW
endglobals
// Инициализация массивов для исследований, типов юнитов и их способностей
private function InitArrays takes nothing returns nothing
set RESEARCH_IDS[0] = 'R00T' // Black Armour
set UNIT_TYPES_OLD[0] = 'o002' // Lazy ass
set ABILITIES_OLD[0] = 'A02L' // Equip Black Armour (dummy)
set ABILITIES_NEW[0] = 'A02Q' // Equip Black Armour (upgrade ass)
set RESEARCH_IDS[1] = 'R00T' // Black Armour
set UNIT_TYPES_OLD[1] = 'o003' // Junky
set ABILITIES_OLD[1] = 'A02L' // Equip Black Armour (dummy)
set ABILITIES_NEW[1] = 'A02V' // Equip Black Armour (upgrade junky)
set RESEARCH_IDS[2] = 'R00S' // Specialists
set UNIT_TYPES_OLD[2] = 'o00A' // Navvy
set ABILITIES_OLD[2] = 'A02J' // Upgrade to Specialist (dummy)
set ABILITIES_NEW[2] = 'A02T' // Upgrade to Specialist (upgrade)
set RESEARCH_IDS[3] = 'R00R' // Elven Masters
set UNIT_TYPES_OLD[3] = 'o00C' // Pacifist
set ABILITIES_OLD[3] = 'A02N' // Upgrade to Atrisan (dummy)
set ABILITIES_NEW[3] = 'A02R' // Upgrade to Atrisan (upgrade)
set RESEARCH_IDS[4] = 'R00V' // Woodsmen
set UNIT_TYPES_OLD[4] = 'o004' // Lumberjack
set ABILITIES_OLD[4] = 'A02P' // Upgrade to Woodsman (dummy)
set ABILITIES_NEW[4] = 'A02U' // Upgrade to Woodsman (upgrade)
set RESEARCH_IDS[5] = 'R00U' // BlackRock Armour
set UNIT_TYPES_OLD[5] = 'o00J' // Ukr
set ABILITIES_OLD[5] = 'A02M' // Equip Black Armour (dummy)
set ABILITIES_NEW[5] = 'A02S' // Equip Black Armour (upgrade Ukr)
set RESEARCH_IDS[6] = 'R00U' // BlackRock Armour
set UNIT_TYPES_OLD[6] = 'o00K' // Incensed Urk
set ABILITIES_OLD[6] = 'A02M' // Equip Black Armour (dummy)
set ABILITIES_NEW[6] = 'A02W' // Equip Black Armour (upgrade Incensed Urk)
endfunction
// Замена старой способности на новую у юнита
private function ReplaceAbility takes unit u, integer oldAbil, integer newAbil returns nothing
if GetUnitAbilityLevel(u, oldAbil) > 0 then
call UnitRemoveAbility(u, oldAbil)
call UnitAddAbility(u, newAbil)
call SetUnitAbilityLevel(u, newAbil, 1)
endif
endfunction
// Функция, вызываемая при завершении исследования
private function OnResearchFinish takes nothing returns nothing
local player p = GetTriggerPlayer() // Получение игрока, завершившего исследование
local integer playerId = GetPlayerId(p) // Получение ID игрока
local integer researchId = GetResearched() // Получение ID завершенного исследования
local group g = CreateGroup() // Создание группы для хранения юнитов игрока
local unit u
local integer i
set researchCompleted[playerId] = true // Отметка, что исследование завершено для данного игрока
call GroupEnumUnitsOfPlayer(g, p, null) // Перечисление всех юнитов игрока
loop
set u = FirstOfGroup(g)
exitwhen u == null
set i = 0
loop
exitwhen i >= RESEARCH_COUNT
if researchId == RESEARCH_IDS[i] then
if GetUnitTypeId(u) == UNIT_TYPES_OLD[i] then
call ReplaceAbility(u, ABILITIES_OLD[i], ABILITIES_NEW[i])
endif
endif
set i = i + 1
endloop
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g) // Уничтожение группы для освобождения памяти
endfunction
// Функция, вызываемая при создании нового юнита
private function OnUnitCreated takes nothing returns nothing
local unit u = GetTriggerUnit() // Получение созданного юнита
local player p = GetOwningPlayer(u) // Получение владельца юнита
local integer playerId = GetPlayerId(p) // Получение ID игрока
local integer i = 0
loop
exitwhen i >= RESEARCH_COUNT
if GetUnitTypeId(u) == UNIT_TYPES_OLD[i] then
if researchCompleted[playerId] and GetPlayerTechCount(p, RESEARCH_IDS[i], true) > 0 then
call ReplaceAbility(u, ABILITIES_OLD[i], ABILITIES_NEW[i])
endif
endif
set i = i + 1
endloop
endfunction
// Инициализация способностей юнитов для всех игроков при старте игры
private function InitUnitAbilities takes nothing returns nothing
local group g
local unit u
local integer i = 0
local integer j
local player p
loop
exitwhen i >= bj_MAX_PLAYERS
set p = Player(i)
set g = CreateGroup()
call GroupEnumUnitsOfPlayer(g, p, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
set j = 0
loop
exitwhen j >= RESEARCH_COUNT
if GetUnitTypeId(u) == UNIT_TYPES_OLD[j] then
if researchCompleted[GetPlayerId(GetOwningPlayer(u))] and GetPlayerTechCount(GetOwningPlayer(u), RESEARCH_IDS[j], true) > 0 then
call ReplaceAbility(u, ABILITIES_OLD[j], ABILITIES_NEW[j])
endif
endif
set j = j + 1
endloop
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
set i = i + 1
endloop
endfunction
// Инициализация триггеров и массивов при старте карты
private function onInit takes nothing returns nothing
local trigger trg
local integer i = 0
call InitArrays() // Инициализация массивов
// Инициализация массива завершенных исследований
loop
exitwhen i >= bj_MAX_PLAYERS
set researchCompleted[i] = false
set i = i + 1
endloop
// Инициализация способностей юнитов для всех игроков при старте игры
call InitUnitAbilities()
// Регистрация события завершения исследования
set trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_RESEARCH_FINISH)
call TriggerAddAction(trg, function OnResearchFinish)
// Регистрация события создания юнита
set trg = CreateTrigger()
call TriggerRegisterEnterRectSimple(trg, GetPlayableMapRect())
call TriggerAddAction(trg, function OnUnitCreated)
endfunction
endlibrary
globals
hashtable H = InitHashtable( )
group TempGroup = CreateGroup( )
endglobals
native UnitAlive takes unit id returns boolean
function Trig_Spell_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction
function Move takes nothing returns nothing
local timer t = GetExpiredTimer( )
local unit c = LoadUnitHandle ( H, GetHandleId( t ), 0 )
local unit u = null
local real x = GetUnitX ( c ) + 20.00 * Cos ( GetUnitFacing( c ) * bj_DEGTORAD )
local real y = GetUnitY ( c ) + 20.00 * Sin ( GetUnitFacing( c ) * bj_DEGTORAD )
call SetUnitX ( c, x )
call SetUnitY ( c, y )
call GroupEnumUnitsInRange (TempGroup, x, y, 100, null)
loop
set u = FirstOfGroup ( TempGroup )
exitwhen u == null
call GroupRemoveUnit ( TempGroup, u )
if UnitAlive ( u ) and IsUnitEnemy ( u, GetOwningPlayer ( c ) ) then
call GroupClear ( TempGroup )
call GroupEnumUnitsInRange ( TempGroup, x, y, 300, null)
loop
set u = FirstOfGroup ( TempGroup )
exitwhen u == null
call GroupRemoveUnit ( TempGroup, u )
if UnitAlive ( u ) and IsUnitEnemy ( u, GetOwningPlayer ( c ) ) then
call UnitDamageTarget ( c , u, 500, false, false, null, null, null )
set bj_lastCreatedEffect = AddSpecialEffectTarget ( "Abilities\\Weapons\\RedDragonBreath\\RedDragonMissile.mdl", u, "chest" )
call DestroyEffect ( bj_lastCreatedEffect )
endif
call KillUnit ( c )
set bj_lastCreatedEffect = AddSpecialEffect ( "Abilities\\Spells\\Other\\Doom\\DoomDeath.mdl", x, y )
call BlzSetSpecialEffectScale ( bj_lastCreatedEffect, 1.5 )
call DestroyEffect ( bj_lastCreatedEffect )
endloop
endif
endloop
if not UnitAlive ( c ) then
call PauseTimer ( t )
call FlushChildHashtable( H, GetHandleId( t ) )
call DestroyTimer ( t )
endif
set t = null
set c = null
endfunction
function Trig_Spell_Actions takes nothing returns nothing
local timer t = CreateTimer( )
local unit c = GetTriggerUnit( )
local real x = GetUnitX( c )
local real y = GetUnitY( c )
set bj_lastCreatedUnit = CreateUnit( GetOwningPlayer( c ), 'h000', x, y, Atan2 ( GetSpellTargetY() - y, GetSpellTargetX() - x ) * bj_RADTODEG )
call UnitApplyTimedLife ( bj_lastCreatedUnit, 'BTLF', 2 )
call UnitAddAbility ( bj_lastCreatedUnit, 'Arav' )
call SetUnitFlyHeight ( bj_lastCreatedUnit, 50, 0 )
call SetUnitPathing ( bj_lastCreatedUnit, false )
call SetUnitX ( bj_lastCreatedUnit, x )
call SetUnitY ( bj_lastCreatedUnit, y )
call SaveUnitHandle( H, GetHandleId( t ), 0, bj_lastCreatedUnit )
call TimerStart( t, 0.03125, true, function Move )
set t = null
set c = null
endfunction
//===========================================================================
function InitTrig_Spell takes nothing returns nothing
set gg_trg_Spell = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Spell, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Spell, Condition( function Trig_Spell_Conditions ) )
call TriggerAddAction( gg_trg_Spell, function Trig_Spell_Actions )
endfunction
library PlayerLeave initializer onInit
private function PlayerLeave takes nothing returns nothing
local string Text
local player pl = GetTriggerPlayer()
if(BlzGetLocale() == "ruRU")then
set Text = " испугался количества деревьев и вышел из игры."
else
set Text = " afraid of the number of trees and left the game."
endif
call DisplayTextToForce( GetPlayersAll(), /*
*/GetPlayerName(GetTriggerPlayer()) + Text)
call ConditionalTriggerExecute( gg_trg_SawmillCheck )
if(IsPlayerInForce(pl, udg_PlayersInGame))then
call ForceRemovePlayer(udg_PlayersInGame, pl)
endif
endfunction
//===========================================================================
private function onInit takes nothing returns nothing
local trigger trig = CreateTrigger( )
local integer i = 0
loop
exitwhen(i == 24)
call TriggerRegisterPlayerEvent(trig, Player(i), EVENT_PLAYER_LEAVE)
set i = i + 1
endloop
call TriggerAddAction( trig, function PlayerLeave )
endfunction
endlibrary
function Trig_PlayerUnitTrainedAngryUrc_Conditions takes nothing returns boolean
return GetUnitTypeId(GetTrainedUnit()) == 'o00K'
endfunction
function PlayUnitSound takes location loc returns nothing
local sound loc_sound
set loc_sound = CreateSound("Units/Orc/Hellscream/GromWhat3.flac", false, false, false, 1, 1, "SpellsEAX")
if(GetLocalPlayer() == GetOwningPlayer(GetTrainedUnit()))then
call SetSoundVolume(loc_sound, 127)
else
call SetSoundVolume(loc_sound, 0)
endif
call StartSound(loc_sound)
call KillSoundWhenDone(loc_sound)
endfunction
function Trig_PlayerUnitTrainedAngryUrc_Actions takes nothing returns nothing
local location loc = GetUnitLoc(GetTrainedUnit())
call PlayUnitSound(loc)
call RemoveLocation(loc) // Удаление локации после использования
endfunction
//===========================================================================
function InitTrig_PlayerUnitTrainedAngryUrc takes nothing returns nothing
set gg_trg_PlayerUnitTrainedAngryUrc = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_PlayerUnitTrainedAngryUrc, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( gg_trg_PlayerUnitTrainedAngryUrc, Condition( function Trig_PlayerUnitTrainedAngryUrc_Conditions ) )
call TriggerAddAction( gg_trg_PlayerUnitTrainedAngryUrc, function Trig_PlayerUnitTrainedAngryUrc_Actions )
endfunction
library WoodGrowLocInit initializer onInit uses WoodGrowLib
private function onInit takes nothing returns nothing
/* ====== Функция добавления нового типа деревьев в систему ========================
function WGL.addTreeType takes integer objectid, integer shapex, integer shapey,
integer sw, real smin, real smax, rect r returns nothing
// objectid - id типа разрушаемого объекта - дерева
// shapex - размер по x формы карты путей дерева
// shapey - размер по y формы карты путей дерева
// sw - статистический вес дерева
// smin - минимальный масштаб дерева
// smax - максимальный масштаб дерева
// r - область возможног появления дерева
*/
call WGL.addTreeType( 'B002', 4, 4, 2, 0.8, 1.2, GetWorldBounds() )
call WGL.addTreeType( 'B001', 4, 4, 2, 0.6, 1.0, GetWorldBounds() )
call WGL.addTreeType( 'B000', 2, 2, 1, 0.38, 0.58, gg_rct_TinyWoodGrowArea )
set WGL.TreesMax = 15000 // Максимум деревьев
set WGL.StumpsMax = 5000 // Максимум пеньков
set WGL.GrowTreeNum = 1 // Число деревьев за итерацию
set WGL.GrowTime = 0.05 // Время между итерациями роста
call STML.SetMaxDens(4)
call WGL.GrowStart()
endfunction
endlibrary
library SpeedController initializer onInit uses WoodGrowMapLib, WoodGrowLocInit
globals
private integer MaxTrees
endglobals
function SpeedRefresh takes nothing returns nothing
local integer NumTrees = WGL.GetTreesCount()
local real SpeedTime = 0.01 + I2R(NumTrees)/I2R(MaxTrees)*0.07
set WGL.GrowTime = SpeedTime
endfunction
private function onInit takes nothing returns nothing
set MaxTrees = WGM.maxdens*WGM.TreesMap.shape_x*WGM.TreesMap.shape_y
endfunction
endlibrary
library GoldenItemAcquire uses DefaultTextTag
globals
private constant integer ITEM_BUNCH_COINS = 'I00A'
private constant integer ITEM_GOLD_COINS = 'I00N'
private constant integer ITEM_CHEST_GOLD = 'I00C'
private constant integer BASE_BUNCH_COINS = 100
private constant integer BASE_GOLD_COINS = 250
private constant integer BASE_CHEST_GOLD = 500
private constant integer TECH_ALCHEMY = 'R00W'
endglobals
// Функция для округления числа до ближайшего целого
function Round takes real value returns integer
if value >= 0 then
return R2I(value + 0.5)
else
return R2I(value - 0.5)
endif
endfunction
// Уровень алхимии и множитель получаемого золота
function GetAlchemyMultiplier takes integer level returns real
if level == 1 then
return 1.3
elseif level == 2 then
return 1.6
elseif level == 3 then
return 2.0
else
return 1.0
endif
endfunction
function AdjustGoldAndShowText takes unit manipulatingUnit, integer baseGold, real multiplier returns nothing
local integer goldAmount = Round(baseGold * multiplier)
local real x = GetUnitX(manipulatingUnit)
local real y = GetUnitY(manipulatingUnit)
local texttag tt
local string text = "+" + I2S(goldAmount)
call AdjustPlayerStateBJ(goldAmount, GetOwningPlayer(manipulatingUnit), PLAYER_STATE_RESOURCE_GOLD)
// Создание текстовой метки с помощью DefaultTextTag
set tt = DefaultTextTag(TextTagGoldBounty, x, y, text)
// Установка видимости текстовой метки только для игрока, который подобрал предмет
if GetLocalPlayer() == GetOwningPlayer(manipulatingUnit) then
call SetTextTagVisibility(tt, true)
endif
endfunction
function Trig_Golden_item_acquire_Actions takes nothing returns nothing
local unit manipulatingUnit = GetManipulatingUnit()
local integer itemType = GetItemTypeId(GetManipulatedItem())
local integer techLevel = GetPlayerTechCountSimple(TECH_ALCHEMY, GetOwningPlayer(manipulatingUnit))
local real multiplier = GetAlchemyMultiplier(techLevel)
if itemType == ITEM_BUNCH_COINS then
call AdjustGoldAndShowText(manipulatingUnit, BASE_BUNCH_COINS, multiplier)
elseif itemType == ITEM_GOLD_COINS then
call AdjustGoldAndShowText(manipulatingUnit, BASE_GOLD_COINS, multiplier)
elseif itemType == ITEM_CHEST_GOLD then
call AdjustGoldAndShowText(manipulatingUnit, BASE_CHEST_GOLD, multiplier)
endif
// Освобождение локальных переменных
set manipulatingUnit = null
endfunction
//===========================================================================
function InitTrig_Golden_item_acquire takes nothing returns nothing
local trigger gg_trg_Golden_item_acquire = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Golden_item_acquire, EVENT_PLAYER_UNIT_PICKUP_ITEM)
call TriggerAddAction(gg_trg_Golden_item_acquire, function Trig_Golden_item_acquire_Actions)
endfunction
endlibrary
// Функция, создающая золотую монетку в случайной точке на игровой карте
function Trig_CreateGoldCoin_Actions takes nothing returns nothing
local real x = GetRandomReal(GetRectMinX(GetPlayableMapRect()), GetRectMaxX(GetPlayableMapRect()))
local real y = GetRandomReal(GetRectMinY(GetPlayableMapRect()), GetRectMaxY(GetPlayableMapRect()))
call CreateItem('I00N', x, y)
endfunction
// Инициализация триггера для создания золотой монеты каждые 5 секунд
function InitTrig_CreateGoldCoin takes nothing returns nothing
set gg_trg_CreateGoldCoin = CreateTrigger()
call TriggerRegisterTimerEventPeriodic(gg_trg_CreateGoldCoin, 5.00)
call TriggerAddAction(gg_trg_CreateGoldCoin, function Trig_CreateGoldCoin_Actions)
endfunction
library ClearItems requires optional WorldBounds
/*
This library fixes the leak and the lag caused by unremoved items,
including powerups and manually-destroyed items.
The dead items are periodically removed. You can adjust the period by changing
the constant CLEANING_PERIOD. Note that items' death animations need some time
to play so adjust the DEATH_TIME delay accordingly.
If you don't know exactly what you are doing, you shouldn't change the life
of a dead item; the items are no longer usable after their death but
you can still change their life. If you set their life to more than 0.405,
they won't be properly cleaned. You should also remove items manually
if you kill them when they are carried by a unit.
*/
globals
// Interval between item-cleanups.
private constant real CLEANING_PERIOD = 15
// Time for the item's death animation, optimized for tomes and runes.
private constant real DEATH_TIME = 1.5
endglobals
globals
private keyword S
private integer N = 0
private code s_code
private boolexpr s_bool
private timer s_timer = CreateTimer()
private item array I
endglobals
private function DeleteItems takes nothing returns nothing
loop
set N = N - 1
call SetWidgetLife(I[N], 1)
call RemoveItem(I[N])
set I[N] = null
exitwhen (N == 0)
endloop
call TimerStart(s_timer, CLEANING_PERIOD - DEATH_TIME, true, s_code)
endfunction
private function CleanItems takes nothing returns boolean
if (GetWidgetLife(GetFilterItem()) < 0.405) then
set I[N] = GetFilterItem()
set N = N + 1
endif
return false
endfunction
private function SweepItems takes nothing returns nothing
static if (LIBRARY_WorldBounds) then
call EnumItemsInRect(WorldBounds.world, s_bool, null)
else
call EnumItemsInRect(S.world, s_bool, null)
endif
if (N > 0) then
call TimerStart(s_timer, DEATH_TIME, false, function DeleteItems)
endif
endfunction
private struct S extends array
static if (not LIBRARY_WorldBounds) then
static rect world
endif
static method onInit takes nothing returns nothing
static if (not LIBRARY_WorldBounds) then
set world = GetWorldBounds()
endif
set s_code = function SweepItems
set s_bool = Filter(function CleanItems)
call TimerStart(s_timer, CLEANING_PERIOD, true, s_code)
endmethod
endstruct
endlibrary
library GolemSpawnInit initializer onInit uses GolemSpawn
private function onInit takes nothing returns nothing
call GCL.AddGolemType('n013', 0.04, 3) // Шанс спавна глинняного голема, 1-3 штуки
call GCL.AddGolemType('n012', 0.01, 1) // Шанс спавна каменного голема
call GCL.AddGolemType('n011', 0.0025, 1) // Шанс спавна гранитового голема
endfunction
endlibrary
library Spiders initializer onInit uses QuasiRandom
globals
private integer CaveMaxSpiders = 5 //Максимальное количество пауков их 1 шахты при инициализации
real CaveSpawnTime = 200 // Время спавна первых шахт, в самом начале их появляется 2, потом 1 каждые 200 секунд
SpawnType ST
QR CaveLocs
endglobals
function SetMaxSpiders takes integer value returns nothing
set CaveMaxSpiders = value
call SPL.SetMaxGuardForAll(value)
endfunction
private function CaveSpawn takes nothing returns unit
local location loc
local real x
local real y
local unit NewCave
if (CaveLocs.xar.shape_x > 0) then
set loc = CaveLocs.TakeLocation()
set x = GetLocationX(loc)
set y = GetLocationY(loc)
set NewCave = CreateUnit(Player(PLAYER_NEUTRAL_AGGRESSIVE), 'o00I', x, y, bj_UNIT_FACING)
call SPL.addSpawner(NewCave, CaveMaxSpiders, 5.0, ST)
call RemoveLocation(loc)
return NewCave
else
return null
endif
endfunction
function StartCavePeriodic takes nothing returns nothing
call DestroyTimer(GetExpiredTimer())
call CaveSpawn()
call CaveSpawn()
call TimerStart(CreateTimer(), CaveSpawnTime, true, function CaveSpawn)
endfunction
function CaveDeath takes nothing returns nothing
local unit un = GetTriggerUnit()
if(GetUnitTypeId(un) == 'o00I')then
call CaveLocs.AddLocation(R2I(GetUnitX(un)), R2I(GetUnitY(un)))
endif
endfunction
private function onInit takes nothing returns nothing
set ST = SpawnType.create()
set CaveLocs = QR.create(1280.0, 10, GetPlayableMapRect())
call TriggerAddAction( SPL.Trg_SpawnerDeath, function CaveDeath )
endfunction
endlibrary
library SpidersTir uses Spiders
globals
private timer t41
endglobals
// Уровень 4_1
private function Spiders_T4_1 takes nothing returns nothing
call DestroyTimer(t41)
call SetMaxSpiders(20) // Максимальное количество пауков из 1 шахты
set ST.max[1] = 5 // Максимальное количество Ткачей
set ST.sw[1] = 5 // Вес для Ткачей
set ST.max[0] = 15 // Максимальное количество обычных лесных пауков
set ST.sw[0] = 15 // Вес для Обычных лесных пауков
set ST.wsum = 20 // Общий вес всех типов пауков
call SPL.SetSpawnTimeForAll(4.0) // Время спавна 1 паука после 600 секунд
endfunction
// Уровень 4
function Spiders_T4 takes nothing returns nothing
call SetMaxSpiders(20) // Максимальное количество пауков из 1 шахты
set ST.max[1] = 2 // Максимальное количество Ткачей
set ST.sw[1] = 2 // Вес для Ткачей
set ST.max[0] = 18 // Максимальное количество обычных лесных пауков
set ST.sw[0] = 18 // Вес для Обычных лесных пауков
set ST.wsum = 20 // Общий вес всех типов пауков
set t41 = CreateTimer()
call TimerStart(t41, 600.0, false, function Spiders_T4_1)
call SPL.SetSpawnTimeForAll(4.5) // Время спавна 1 паука
endfunction
// Уровень 3
function Spiders_T3 takes nothing returns nothing
call SetMaxSpiders(16) // Максимальное количество пауков из 1 шахты
call ST.addType('n014', 1, 1) // Добавляем тип пауков 'n014 - ткач' с весом 1 и максимумом 1
call SPL.SetSpawnTimeForAll(5.0) // Время спавна 1 паука
endfunction
// Уровень 2
function Spiders_T2 takes nothing returns nothing
call SetMaxSpiders(15) // Максимальное количество пауков из 1 шахты
set ST.max[0] = 15 // Максимальное количество обычных лесных пауков
set ST.sw[0] = 15 // Вес для Обычных лесных пауков
set ST.wsum = 15 // Общий вес всех типов пауков
call SPL.SetSpawnTimeForAll(6.0) // Время спавна 1 паука
endfunction
// Уровень 1
function Spiders_T1 takes nothing returns nothing
call SetMaxSpiders(10) // Максимальное количество пауков из 1 шахты
call ST.addType('n001', 10, 10) // Добавляем тип пауков 'n001 - лесной паук' с весом 10 и максимумом 10
call SPL.SetSpawnTimeForAll(7.5) // Время спавна 1 паука
call TimerStart(CreateTimer(), CaveSpawnTime, false, function StartCavePeriodic) // Запуск периодического спавна пауков
endfunction
private function onInit takes nothing returns nothing
// Здесь вызываем Spiders_T1 через стартовый триггер
endfunction
endlibrary
library Pathing
globals
unit udg_un_1
unit udg_un_2
location udg_loc_1
location udg_loc_2
timer timerok
timer MaxPath_timer
boolean Pathing
endglobals
function PathingConclusion takes nothing returns nothing
if(Pathing)then
call DisplayTextToForce( GetPlayersAll(), "Проходимо")
else
call DisplayTextToForce( GetPlayersAll(), "Непроходимо")
endif
endfunction
function PeriodicUnits takes nothing returns nothing
local unit un_1 = udg_un_1
local unit un_2 = udg_un_2
local real Dist_un
//DisplayTextToForce( GetPlayersAll(), OrderId2StringBJ(GetUnitCurrentOrder(un)) )
if(GetUnitCurrentOrder(un_1) == null)then
call ShowUnit(un_1, true)
set Dist_un = SquareRoot((GetUnitX(un_1)- GetLocationX(udg_loc_2))*(GetUnitX(un_1)- GetLocationX(udg_loc_2)) + (GetUnitY(un_1)- GetLocationY(udg_loc_2))*(GetUnitY(un_1)- GetLocationY(udg_loc_2)))
if(Dist_un > 200)then
call DisplayTextToForce( GetPlayersAll(), "Юнит_1 недошел: " + R2S( Dist_un) )
set Pathing = false
else
call DisplayTextToForce( GetPlayersAll(), "Юнит_1 дошел: " + R2S( Dist_un) )
set Pathing = true
endif
endif
if(GetUnitCurrentOrder(un_2) == null)then
call ShowUnit(un_2, true)
set Dist_un = SquareRoot((GetUnitX(un_2)- GetLocationX(udg_loc_1))*(GetUnitX(un_2)- GetLocationX(udg_loc_1)) + (GetUnitY(un_2)- GetLocationY(udg_loc_1))*(GetUnitY(un_2)- GetLocationY(udg_loc_1)))
if(Dist_un > 200)then
call DisplayTextToForce( GetPlayersAll(), "Юнит_2 недошел: " + R2S( Dist_un) )
set Pathing = false
else
call DisplayTextToForce( GetPlayersAll(), "Юнит_2 дошел: " + R2S( Dist_un) )
set Pathing = true
endif
endif
endfunction
function Cheak takes location loc_1, location loc_2 returns nothing
local unit un_1 = CreateUnitAtLoc(Player(0),'h00N', loc_1, 0)
local unit un_2 = CreateUnitAtLoc(Player(0),'h00N', loc_2, 0)
local unit un_free = CreateUnitAtLoc(Player(0),'h00N', loc_1, 0)
//
call IssuePointOrderLoc( un_1, "move", loc_2 )
call IssuePointOrderLoc( un_2, "move", loc_1 )
//
call ShowUnit(un_1, false)
//call SetUnitMoveSpeed(un_1, 60000);
call ShowUnit(un_2, false)
//call SetUnitMoveSpeed(un_2, 60000);
//
set timerok = CreateTimer()
call TimerStart(timerok ,0.1 ,true ,function PeriodicUnits)
//
set MaxPath_timer = CreateTimer()
call TimerStart(MaxPath_timer ,10.0 ,false ,function PathingConclusion)
set Pathing = false
//
set udg_un_1 = un_1
set udg_un_2 = un_2
set udg_loc_1 = loc_1
set udg_loc_2 = loc_2
endfunction
endlibrary
library DemonsV2
struct PORTAL extends UNIT
static integer maxdemons
//!novjass
integer currdemons
//!endnovjass
//
method DemonSpawn takes integer UnitID returns DEMON
local real x_c = GetUnitX(this.unit)
local real y_c = GetUnitY(this.unit)
local real x = GetRandomReal(x_c - 500, x_c + 500)
local real y = GetRandomReal(y_c - 500, y_c + 500)
local DEMON DE = DEMON.Spawn(this, UnitID, x, y)
/*//call PlaySoundAtPointBJ( gg_snd_LightningBolt3, 50.00, loc, 1250.00 )
//
call SaveInteger(udg_HashTable, GetHandleId(un), 0, Demons_Counter)
set udg_Demons[Demons_Counter] = un
set AtakerNumber[Demons_Counter] = -1
set PortalOfDemon[Demons_Counter] = N_Portal
set Demons_Counter = Demons_Counter + 1
call RemoveRect(Rectic)
call RemoveLocation(loc)*/
return DE
endmethod
endstruct
struct DEMON extends UNIT
//!novjass
//integer numport //номер портала
//!endnovjass
method operator numport takes nothing returns integer
return this.LoadInteger(this.thishandler.p)
endmethod
method operator numport= takes integer value returns nothing
call this.SaveInteger(this.thishandler.p, value)
endmethod
//
static method Spawn takes PORTAL PO, integer UnitID, real x, real y returns thistype
local thistype this = DEMON.create(CreateUnit(GetOwningPlayer(PO.unit), UnitID, x, y, bj_UNIT_FACING))
set this.numport = PO
return this
endmethod
endstruct
struct DEMONLIDER extends UNIT
//!novjass
location target
trigger gettrg //получение цели
//!endnovjass
endstruct
endlibrary
library ClassLider uses ClassMainBuilding
globals
//define{
//ID_Lider = 'Hpal';
//}
//class Lider
unit array udg_Lider
integer Liers_Counter
location array udg_LiderTarg
trigger array LiderDetect
boolean array bool_AttackMill
timer array IdleTimer
//
unit array udg_DemonMinion
integer Minion_Counter
integer array udg_DemonLider
endglobals
//
function IdleElapsed takes nothing returns nothing
local integer N_li = LoadInteger(udg_HashTable, GetHandleId(GetExpiredTimer()), 0)
//BJDebugMsg(I2S(N_li) + " ничего не делал уже " + I2S(IdleTime) + " сек")
local location loc = GetUnitLoc(FindNearestMillAtLoc(GetUnitLoc(udg_Lider[N_li])))
call RemoveLocation(udg_LiderTarg[N_li])
set udg_LiderTarg[N_li] = loc
set bool_AttackMill[N_li] = true
call SetUnitPathing(udg_Lider[N_li], false )
endfunction
function LiderDetectAction takes nothing returns nothing
local integer N_li = LoadInteger(udg_HashTable, GetHandleId(GetTriggeringTrigger()), 0)
if(bool_AttackMill[N_li])then
call SetUnitPathing(udg_Lider[N_li], true )
endif
set bool_AttackMill[N_li] = false
//BJDebugMsg("пизда " + I2S(N_li))
call TimerStart(IdleTimer[N_li], IdleTime, false, function IdleElapsed)
endfunction
function LiderDetectingPeriodic takes nothing returns nothing
local integer i = 0
local location loc
loop
exitwhen(i == Liers_Counter)
set loc = GetUnitLoc(udg_Lider[i])
call SetUnitPositionLoc( udg_Lider[i], loc)
if(bool_AttackMill[i])then
call IssuePointOrderLoc( udg_Lider[i], "attack", udg_LiderTarg[i])
endif
call RemoveLocation(loc)
set i = i + 1
endloop
set i = 0
loop
exitwhen(i == Minion_Counter)
set loc = GetUnitLoc(udg_DemonMinion[i])
call SetUnitPositionLoc( udg_DemonMinion[i], loc)
if(bool_AttackMill[udg_DemonLider[i]])then
call IssueTargetOrder( udg_DemonMinion[i], "move", udg_Lider[udg_DemonLider[i]] )
endif
set i = i + 1
endloop
endfunction
//Destructor
function LiderDemonTrase takes integer N_un returns nothing
//
local unit Dying = udg_Lider[N_un]
//
set Liers_Counter = Liers_Counter - 1
//
call SaveInteger(udg_HashTable, GetHandleId(LiderDetect[Liers_Counter]), 0, N_un)
call FlushChildHashtable(udg_HashTable, GetHandleId(LiderDetect[N_un]))
call DestroyTrigger( LiderDetect[N_un] )
set LiderDetect[N_un] = LiderDetect[Liers_Counter]
//
call SaveInteger(udg_HashTable, GetHandleId(IdleTimer[Liers_Counter]), 0, N_un)
call FlushChildHashtable(udg_HashTable, GetHandleId(IdleTimer[N_un]))
call DestroyTimer( IdleTimer[N_un] )
set IdleTimer[N_un] = IdleTimer[Liers_Counter]
//
set udg_Lider[N_un] = udg_Lider[Liers_Counter]
call RemoveLocation(udg_LiderTarg[N_un])
set udg_LiderTarg[N_un] = udg_LiderTarg[Liers_Counter]
set bool_AttackMill[N_un] = bool_AttackMill[Liers_Counter]
//
//Обновленние данных последнего
call SaveInteger(udg_HashTable, GetHandleId(udg_Lider[Liers_Counter]), 0, N_un)
//Удаление данных об умершем юните из хэштаблицы
call FlushChildHashtable(udg_HashTable, GetHandleId(Dying))
endfunction
//Constructor
function DemonLiderCreate takes integer N_Portal, integer Unit_ID, location LocTarg returns unit
local unit New_Lider = CreateUnitAtLoc(GetOwningPlayer(udg_Portals[N_Portal]),Unit_ID, GetUnitLoc(udg_Portals[N_Portal]), 0)
local trigger New_trg = CreateTrigger( )
call SaveInteger(udg_HashTable, GetHandleId(New_Lider), 0, Liers_Counter)
set udg_Lider[Liers_Counter] = New_Lider
set udg_LiderTarg[Liers_Counter] = LocTarg
set bool_AttackMill[Liers_Counter] = true
//
call TriggerRegisterUnitEvent( New_trg, New_Lider, EVENT_UNIT_ACQUIRED_TARGET )
call TriggerAddAction( New_trg, function LiderDetectAction )
call SaveInteger(udg_HashTable, GetHandleId(New_trg), 0, Liers_Counter)
set LiderDetect[Liers_Counter] = New_trg
//
set IdleTimer[Liers_Counter] = CreateTimer()
call SaveInteger(udg_HashTable, GetHandleId(IdleTimer[Liers_Counter]), 0, Liers_Counter)
//
set Liers_Counter = Liers_Counter + 1
return New_Lider
endfunction
//ClassInitialization
function DemonLiderInI takes nothing returns nothing
local timer loc_timer = CreateTimer()
set Liers_Counter = 0
set Minion_Counter = 0
call TimerStart(loc_timer, 4.5, true, function LiderDetectingPeriodic)
//set PeriodicDemonsSpawn = loc_timer
endfunction
//для миньена
function AddMinion takes unit de, integer N_Lider returns nothing
local integer N_un = LoadInteger(udg_HashTable, GetHandleId(de), 0)
set AtakerNumber[N_un] = Minion_Counter
set udg_DemonLider[Minion_Counter] = N_Lider
set udg_DemonMinion[Minion_Counter] = de
set Minion_Counter = Minion_Counter + 1
endfunction
function MinionDemonTrase takes integer N_un returns nothing
local integer N_min = AtakerNumber[N_un]
set Minion_Counter = Minion_Counter - 1
set udg_DemonMinion[N_min] = udg_DemonMinion[Minion_Counter]
set udg_DemonLider[N_min] = udg_DemonLider[Minion_Counter]
endfunction
endlibrary
library ClassDestructor
globals
private real d = 300
//
timer TreeDestr_timer
private unit array Destruktors
integer Destruktors_Counter
private effect array DestruktorEffect
integer DestruktorEffect_Counter
private timer array DestruktorEffect_timer
private integer DestruktorEffectTimerCounter
endglobals
//Функция для взаимодействия с разр. объектами
private function DestSpellTarg takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
private function EffectDestr_time takes nothing returns nothing
local timer loc_time = GetExpiredTimer()
local integer N_ti = LoadInteger(udg_HashTable, GetHandleId(loc_time), 0)
local integer j = 0
set DestruktorEffect_Counter = DestruktorEffect_Counter - 20
set DestruktorEffectTimerCounter = DestruktorEffectTimerCounter - 1
loop
exitwhen(j == 20)
call DestroyEffect(DestruktorEffect[N_ti*20 + j])
set DestruktorEffect[N_ti*20 + j] = DestruktorEffect[DestruktorEffectTimerCounter*20+j]
set j = j + 1
endloop
call SaveInteger(udg_HashTable, GetHandleId(DestruktorEffect_timer[DestruktorEffectTimerCounter]), 0, N_ti)
call FlushChildHashtable(udg_HashTable, GetHandleId(loc_time))
set DestruktorEffect_timer[N_ti] = DestruktorEffect_timer[DestruktorEffectTimerCounter]
call DestroyTimer(loc_time)
endfunction
//Функция обработки периодического действия
private function SpellTreeDestr_Periodic takes nothing returns nothing
local real x_c
local real y_c
local rect Rectic
local integer i = 0
local integer j = 0
local effect loc_ef
local timer loc_time
loop
exitwhen(i == Destruktors_Counter)
set x_c = GetUnitX(Destruktors[i])
set y_c = GetUnitY(Destruktors[i])
set Rectic = Rect(x_c - d, y_c - d, x_c + d, y_c + d)
call EnumDestructablesInRect(Rectic, null, function DestSpellTarg)
set j = 0
loop
exitwhen(j == 20)
set loc_ef = AddSpecialEffectLoc("Abilities\\Spells\\Human\\FlameStrike\\FlameStrikeEmbers.mdl",GetRandomLocInRect(Rectic))
set DestruktorEffect[DestruktorEffect_Counter + j] = loc_ef
set j = j + 1
endloop
set DestruktorEffect_Counter = DestruktorEffect_Counter + j
set loc_time = CreateTimer()
call TimerStart(loc_time, 3, false, function EffectDestr_time )
call SaveInteger(udg_HashTable, GetHandleId(loc_time), 0, DestruktorEffectTimerCounter)
set DestruktorEffect_timer[DestruktorEffectTimerCounter] = loc_time
set DestruktorEffectTimerCounter = DestruktorEffectTimerCounter + 1
call RemoveRect(Rectic)
set i = i + 1
endloop
endfunction
//Инициализация таймера
//private function SpellTreeDestrINI takes nothing returns nothing
//endfunction
//Destructor
function DestructorDeath takes unit DeathUnit returns boolean
local integer i = 0
loop
exitwhen(Destruktors[i] == DeathUnit)
set i = i + 1
if(i == Destruktors_Counter)then
call BJDebugMsg("Ошибка: деструктор не найден")
return false
endif
endloop
//
set Destruktors_Counter = Destruktors_Counter - 1
set Destruktors[i] = Destruktors[Destruktors_Counter]
return true
endfunction
//Constructor
function SpellTreeDestrStart takes unit un returns nothing
set Destruktors[Destruktors_Counter] = un
set Destruktors_Counter = Destruktors_Counter + 1
endfunction
function DestructorInI takes nothing returns nothing
set Destruktors_Counter = 0
set DestruktorEffect_Counter = 0
set DestruktorEffectTimerCounter = 0
//
set TreeDestr_timer = CreateTimer()
call TimerStart(TreeDestr_timer, 1.00,true, function SpellTreeDestr_Periodic)
endfunction
endlibrary
library ClassDemon uses ClassLider//class demon
globals
private boolean DispProc = true
//
unit array udg_Demons
integer array PortalOfDemon//Номер шахты принадлежащего паучку
integer array AtakerNumber
integer Demons_Counter
//
integer array UnitType_ID
integer array UnitStatWeight
integer StatSum
integer UnitType_Counter
//
//trigger DemonsTypsInitialization;//для удобной инициализации
endglobals
//Methods
function IsItDemon takes integer Unit_ID returns boolean
local integer i = 0
loop
exitwhen( i == UnitType_Counter )
if(Unit_ID == UnitType_ID[i])then
return true
endif
set i = i + 1
endloop
return false
endfunction
function GetRandomDemon takes nothing returns integer
local integer Rand = GetRandomInt(1,StatSum)
local integer i = 0
loop
exitwhen(Rand <= UnitStatWeight[i])
set Rand = Rand - UnitStatWeight[i]
set i = i + 1
endloop
return UnitType_ID[i]
endfunction
//Destructor
function DemonTrase takes integer N_unit returns nothing
set Demons_Counter = Demons_Counter - 1
//
set PortalOfDemon[N_unit] = PortalOfDemon[Demons_Counter]
set udg_Demons[N_unit] = udg_Demons[Demons_Counter]
set AtakerNumber[N_unit] = AtakerNumber[Demons_Counter]
if(Destruktors_Counter > 0)then
call MinionDemonTrase(N_unit)
endif
//
//Обновленние данных последнего
call SaveInteger(udg_HashTable, GetHandleId(udg_Demons[Demons_Counter]), 0, N_unit)
//Удаление данных об умершем юните из хэштаблицы
call FlushChildHashtable(udg_HashTable, GetHandleId(udg_Demons[N_unit]))
endfunction
//Constructor
function UnitCreate takes integer N_Portal, integer Unit_ID returns unit
local real x_c = GetUnitX(udg_Portals[N_Portal])
local real y_c = GetUnitY(udg_Portals[N_Portal])
local rect Rectic = Rect(x_c - 500, y_c - 500, x_c + 500, y_c + 500)
local location loc = GetRandomLocInRect (Rectic)
local unit un = CreateUnit(GetOwningPlayer(udg_Portals[N_Portal]), Unit_ID,GetLocationX(loc),GetLocationY(loc), bj_UNIT_FACING)
local string soundpath = "Abilities/Spells/Orc/LightningBolt/LightningBolt.flac"
local sound loc_sound = CreateSound(soundpath, false, true, true, 1, 1, "SpellsEAX")
call SetSoundPosition(loc_sound, GetLocationX(loc), GetLocationY(loc), 0)
call SetSoundVolume(loc_sound, 172)
call SetSoundDistanceCutoff(loc_sound, 1250)
call StartSound(loc_sound)
call KillSoundWhenDone(loc_sound)
//
call SaveInteger(udg_HashTable, GetHandleId(un), 0, Demons_Counter)
set udg_Demons[Demons_Counter] = un
set AtakerNumber[Demons_Counter] = -1
set PortalOfDemon[Demons_Counter] = N_Portal
set Demons_Counter = Demons_Counter + 1
call RemoveRect(Rectic)
call RemoveLocation(loc)
return un
endfunction
//ClassInitialization
function ClassDemonINI takes nothing returns nothing
local integer i = 0
set Demons_Counter = 0
//Вычисление статистической суммы
set StatSum = 0
loop
exitwhen( i == UnitType_Counter)
set StatSum = StatSum + UnitStatWeight[i]
set i = i + 1
endloop
if(DispProc)then
set i = 0
loop
exitwhen( i == UnitType_Counter )
//debug BJDebugMsg(I2S(i) + ": " + I2S(R2I((I2R(UnitStatWeight[i])/I2R(StatSum))*100)))
set i = i + 1
endloop
endif//GetUnitName(UnitType_ID[i])
endfunction
endlibrary//endclass
library ClassPortal uses ClassDemon, QuasiRandom, ClassMainBuilding
globals
unit array udg_Portals
integer Portals_Counter
integer array DemonsPortalCounter
timer PeriodicDemonsSpawn
QR PortalLocs
endglobals
//scope MethodsClassPortal{
function LightStomp takes nothing returns nothing
local timer loc_time = GetExpiredTimer()
local lightning loc_Lighting = LoadLightningHandle(udg_HashTable, GetHandleId(loc_time), 0)
call DestroyLightning(loc_Lighting)
call DestroyEffect(LoadEffectHandle(udg_HashTable, GetHandleId(loc_time), 1))
call FlushChildHashtable(udg_HashTable, GetHandleId(loc_time))
call DestroyTimer(loc_time)
endfunction
private function DestractFun takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
function Raizer takes integer N_Portal, unit New_de returns nothing
local unit Portal = udg_Portals[N_Portal]
local lightning loc_Lighting = AddLightningEx(ID_Lightning_Create, false,GetUnitX(Portal), GetUnitY(Portal), 150,GetUnitX(New_de), GetUnitY(New_de), 0)
local timer loc_timer = CreateTimer()
local effect loc_ef = AddSpecialEffect(ID_TargEf, GetUnitX(New_de), GetUnitY(New_de))
//
call TimerStart(loc_timer, 1.0, false, function LightStomp)
call SaveLightningHandle(udg_HashTable, GetHandleId(loc_timer), 0, loc_Lighting)
call SaveEffectHandle(udg_HashTable, GetHandleId(loc_timer), 1, loc_ef)
endfunction
function DemonsSpawnPeridic takes nothing returns nothing
local integer i = 0
local unit un
local real x_c
local real y_c
local rect Rectic
local integer Unit_ID
local location MillLoc
local unit New_Lider
local integer j
local integer k
loop
exitwhen(Portals_Counter == i)
if(DemonsPortalCounter[i] < MaxDemons)then //Учет максимального кол-ва демонов
set Unit_ID = GetRandomDemon()
set un = UnitCreate(i,Unit_ID)
set x_c = GetUnitX(un)
set y_c = GetUnitY(un)
set Rectic = Rect(x_c - 128, y_c - 128, x_c + 128, y_c + 128)
call EnumDestructablesInRect(Rectic, null, function DestractFun)
call RemoveRect(Rectic)
call Raizer( i, un)
//
set DemonsPortalCounter[i] = DemonsPortalCounter[i] + 1
else
if(DemonsPortalCounter[i] == MaxDemons)then
//local unit Lider = DestructorsINI();
set MillLoc = GetUnitLoc( FindNearestMillAtLoc( GetUnitLoc(udg_Portals[i]) ) )
set New_Lider = DemonLiderCreate(i, ID_Lider, MillLoc)
call SpellTreeDestrStart(New_Lider)
call SetUnitPathing(New_Lider, false )
call IssuePointOrderLoc( New_Lider, "attack", MillLoc)
//Цикл - освобождение
set j = 0//все демоны
set k = 0//освобожденные
loop
exitwhen( DemonsPortalCounter[i] == k)
if(j > Demons_Counter)then
call BJDebugMsg("Ошибка освобождения демонов2")
endif
if(PortalOfDemon[j] == i) then
set PortalOfDemon[j] = -1
//LiderOfUnit[j] = Liers_Counter
call IssueTargetOrder( udg_Demons[j], "move", New_Lider )
call AddMinion( udg_Demons[j], Liers_Counter - 1 )
set k = k + 1
endif
set j = j + 1
endloop
set DemonsPortalCounter[i] = 0
endif
endif
set i = i + 1
endloop
endfunction
//c N_cave в пустоту а с N_TOcave на ее номер
function DemonSwitch takes integer N_portal, integer N_TOportal returns nothing
local integer i = 0//SwitchTo 101 для пустоты
local integer j = 0
local integer m = 0
local integer N_unlish_portals = DemonsPortalCounter[N_portal]
local integer N_To_portals = DemonsPortalCounter[N_TOportal]
local integer cos_0
loop
exitwhen( (N_unlish_portals == j) and (N_To_portals == m))
if(i > Demons_Counter)then
call BJDebugMsg("Ошибка освобождения демонов")
endif
//
set cos_0 = PortalOfDemon[i]
if(cos_0 == N_TOportal) then
set PortalOfDemon[i] = N_portal
set m = m + 1
endif
//
if(cos_0 == N_portal) then
set PortalOfDemon[i] = -1
set j = j + 1
endif
set i = i + 1
endloop
endfunction
//}
//Constructor
function CreateDemonPortal takes nothing returns nothing//готов
local location loc
local unit New_Portal
//
if(PortalLocs.xar.shape_x > 0)then
set loc = PortalLocs.TakeLocation()
set New_Portal = CreateUnitAtLoc(Player(PLAYER_NEUTRAL_AGGRESSIVE), ID_Portal, loc, 0)
call RemoveLocation(loc)
//
set udg_Portals[Portals_Counter] = New_Portal
set DemonsPortalCounter[Portals_Counter] = 0
call SaveInteger(udg_HashTable, GetHandleId(New_Portal), 0, Portals_Counter)
set Portals_Counter = Portals_Counter + 1
endif
endfunction
//Destructor
function PortalTrase takes integer N_Portal returns nothing
local unit Dying = udg_Portals[N_Portal]
set Portals_Counter = Portals_Counter - 1
call PortalLocs.AddLocation(R2I(GetUnitX(Dying)), R2I(GetUnitY(Dying)))
call DemonSwitch(N_Portal, Portals_Counter)
set DemonsPortalCounter[N_Portal] = DemonsPortalCounter[Portals_Counter]
set udg_Portals[N_Portal] = udg_Portals[Portals_Counter]
call SaveInteger(udg_HashTable, GetHandleId(udg_Portals[Portals_Counter]), 0, N_Portal)
call FlushChildHashtable(udg_HashTable, GetHandleId(Dying))
endfunction
function DemonPortalInI takes nothing returns nothing
local timer loc_timer = CreateTimer()
set Portals_Counter = 0
set Liers_Counter = 0
call TimerStart(loc_timer, DemonSpawn_time, true, function DemonsSpawnPeridic)
set PeriodicDemonsSpawn = loc_timer
set PortalLocs = QR.create(1280.0, 10, gg_rct_DemonPortalSpawn)
endfunction
endlibrary
library Demons uses ClassDestructor, ClassDemon, ClassLider, ClassPortal, ClassMainBuilding
globals
integer MaxDemons = 8//Максимум демонов
real DemonSpawn_time = 40//Время спавна демонов
real IdleTime = 5//Время которое лидер бездествует
real PortalRadius = 200
integer ID_Portal = 'o00M'
integer ID_Lider = 'n00J'
string ID_Lightning_Create = "AFOD"//Код молнии
string ID_TargEf = "Abilities\\Spells\\Demon\\DarkPortal\\DarkPortalTarget.mdl"//Код таргетного эффекта
endglobals
function DemonsTypsINI takes nothing returns nothing
set UnitType_ID[0] = 'n007'
set UnitStatWeight[0] = 90
set UnitType_ID[1] = 'n00O'
set UnitStatWeight[1] = 35
set UnitType_ID[2] = 'n008'
set UnitStatWeight[2] = 20
set UnitType_ID[3] = 'n00N'
set UnitStatWeight[3] = 2
set UnitType_Counter = 4
endfunction
//*понед новые чер 4 часа, математи*//
function DemonsDeath takes unit Dying, integer loc_DyingTypeID returns boolean
local integer N_de
local integer N_un
local integer N_Portal
if(IsItDemon(loc_DyingTypeID))then //Если Демон
//Запрос с хэш табицы номера умершего беса
set N_de = LoadInteger(udg_HashTable, GetHandleId(Dying), 0)
//
//Изменение данных шахты
set N_Portal = PortalOfDemon[N_de]
if(N_Portal != -1)then
set DemonsPortalCounter[N_Portal] = DemonsPortalCounter[N_Portal] - 1
else
//debug BJDebugMsg("Это был беспортальный бес")
endif
//
//Тасовка данных массива бесов
call DemonTrase(N_de)
return true
endif
//
if(loc_DyingTypeID == ID_Portal)then//Если портал
set N_Portal = LoadInteger(udg_HashTable, GetHandleId(Dying), 0)
call PortalTrase(N_Portal)
endif
if(loc_DyingTypeID == ID_Lider)then
set N_un = LoadInteger(udg_HashTable, GetHandleId(Dying), 0)
if(DestructorDeath(Dying))then
call LiderDemonTrase(N_un)
endif
endif
return false
endfunction
function PortalSpawnPeriodic takes nothing returns nothing
call TimerStart(CreateTimer(), 300.0,true, function CreateDemonPortal)
endfunction
function DemonInvasionINI takes nothing returns nothing
//call DestroyTimer(udg_FirstCaveTimer )
//DemonsTypsInitialization = function DemonsTypsINI
call DemonPortalInI()
call DemonsTypsINI()
call ClassDemonINI()
call DemonLiderInI()
call DestructorInI()
endfunction
endlibrary
library RandomItemWoodenBox
// Условие: если умирающая единица - деревянный ящик ('n004')
function Trig_Random_item_Wooden_box_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'n004'
endfunction
// Функция для создания предмета
function CreateRandomItemWoodenBox takes integer itemId, location loc, integer chance returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateItemLoc(itemId, loc)
endif
endfunction
// Основная функция для создания предметов с определенной вероятностью
function Trig_Random_item_Wooden_box_Actions takes nothing returns nothing
local location dyingUnitLoc = GetUnitLoc(GetDyingUnit())
call CreateRandomItemWoodenBox('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemWoodenBox('I009', dyingUnitLoc, 20) // Создание предмета "Ham" с вероятностью 20%
call CreateRandomItemWoodenBox('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of coins" с вероятностью 19%
call CreateRandomItemWoodenBox('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of coins" с вероятностью 19%
call CreateRandomItemWoodenBox('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemWoodenBox('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemWoodenBox('I00N', dyingUnitLoc, 15) // Создание предмета "Gold Coins" с вероятностью 15%
call CreateRandomItemWoodenBox('I00D', dyingUnitLoc, 15) // Создание предмета "Periapt of Vitality" с вероятностью 15%
call CreateRandomItemWoodenBox('I003', dyingUnitLoc, 12) // Создание предмета "Gloves of Haste" с вероятностью 12%
call CreateRandomItemWoodenBox('I002', dyingUnitLoc, 12) // Создание предмета "Boots of Speed" с вероятностью 12%
// Создание юнита "Sludge" с вероятностью 33%
if GetRandomInt(0, 100) <= 33 then
call CreateNUnitsAtLocFacingLocBJ(1, 'n006', Player(PLAYER_NEUTRAL_AGGRESSIVE), dyingUnitLoc, GetRandomLocInRect(GetPlayableMapRect()))
endif
// Удаление локации после использования
call RemoveLocation(dyingUnitLoc)
endfunction
// Инициализация триггера
function InitTrig_Random_item_Wooden_box takes nothing returns nothing
set gg_trg_Random_item_Wooden_box = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Random_item_Wooden_box, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_Random_item_Wooden_box, Condition(function Trig_Random_item_Wooden_box_Conditions))
call TriggerAddAction(gg_trg_Random_item_Wooden_box, function Trig_Random_item_Wooden_box_Actions)
endfunction
endlibrary
library RandomItemScrolls
// Условие: если умирающая единица - Картограф ('h00P')
function Trig_Random_item_Scrolls_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'h00P'
endfunction
// Функция для создания предмета с определенным шансом
function CreateRandomScroll takes integer itemId, location loc, integer chance returns nothing
if GetRandomInt(1, 7) == chance then
call CreateItemLoc(itemId, loc)
endif
endfunction
// Основная функция для создания предметов с определенными шансами
function Trig_Random_item_Scrolls_Actions takes nothing returns nothing
local location dyingUnitLoc = GetUnitLoc(GetDyingUnit())
call CreateRandomScroll('I00I', dyingUnitLoc, 1) // Создание предмета "Scroll of Protection" с шансом 1/7
call CreateRandomScroll('I00G', dyingUnitLoc, 2) // Создание предмета "Scroll of the Beast" с шансом 1/7
call CreateRandomScroll('I00J', dyingUnitLoc, 3) // Создание предмета "Scroll of Healing" с шансом 1/7
call CreateRandomScroll('I00H', dyingUnitLoc, 4) // Создание предмета "Scroll of Resurrection" с шансом 1/7
call CreateRandomScroll('I00L', dyingUnitLoc, 5) // Создание предмета "Greater Scroll of Replenishment" с шансом 1/7
call CreateRandomScroll('I00F', dyingUnitLoc, 6) // Создание предмета "Scroll of the Unholy Legion" с шансом 1/7
call CreateRandomScroll('I00K', dyingUnitLoc, 7) // Создание предмета "Scroll of Speed" с шансом 1/7
// Удаление локации после использования
call RemoveLocation(dyingUnitLoc)
endfunction
//===========================================================================
function InitTrig_Random_item_Scrolls takes nothing returns nothing
set gg_trg_Random_item_Scrolls = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Random_item_Scrolls, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_Random_item_Scrolls, Condition(function Trig_Random_item_Scrolls_Conditions))
call TriggerAddAction(gg_trg_Random_item_Scrolls, function Trig_Random_item_Scrolls_Actions)
endfunction
endlibrary
library RandomItemMetalBox
// Условие: если умирающая единица - металлический ящик ('n005')
function Trig_Random_item_Metal_box_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'n005'
endfunction
// Функция для создания предмета
function CreateRandomItemMetalBox takes integer itemId, location loc, integer chance returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateItemLoc(itemId, loc)
endif
endfunction
// Функция для создания юнита
function CreateRandomUnitMetalBox takes integer unitId, location loc, integer chance, player whichPlayer returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateNUnitsAtLocFacingLocBJ(1, unitId, whichPlayer, loc, GetRandomLocInRect(GetPlayableMapRect()))
endif
endfunction
// Основная функция для создания предметов и юнитов с определенной вероятностью
function Trig_Random_item_Metal_box_Actions takes nothing returns nothing
local location dyingUnitLoc = GetUnitLoc(GetDyingUnit())
call CreateRandomItemMetalBox('I005', dyingUnitLoc, 18) // Создание предмета "Bundle of Lumber" с вероятностью 18%
call CreateRandomItemMetalBox('I005', dyingUnitLoc, 18) // Создание предмета "Bundle of Lumber" с вероятностью 18%
call CreateRandomItemMetalBox('I009', dyingUnitLoc, 20) // Создание предмета "Ham" с вероятностью 20%
call CreateRandomItemMetalBox('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of coins" с вероятностью 19%
call CreateRandomItemMetalBox('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of coins" с вероятностью 19%
call CreateRandomItemMetalBox('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of coins" с вероятностью 19%
call CreateRandomItemMetalBox('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemMetalBox('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemMetalBox('I006', dyingUnitLoc, 9) // Создание предмета "Ring of Protection +10" с вероятностью 9%
call CreateRandomItemMetalBox('I004', dyingUnitLoc, 15) // Создание предмета "Scroll of Healing" с вероятностью 15%
call CreateRandomItemMetalBox('I00N', dyingUnitLoc, 15) // Создание предмета "Gold Coins" с вероятностью 15%
call CreateRandomUnitMetalBox('e006', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Mimic" с вероятностью 12%
call CreateRandomUnitMetalBox('e006', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Mimic" с вероятностью 12%
call CreateRandomItemMetalBox('I00B', dyingUnitLoc, 12) // Создание предмета "Khadgar's Gem of Health" с вероятностью 12%
call CreateRandomItemMetalBox('I003', dyingUnitLoc, 12) // Создание предмета "Gloves of Haste" с вероятностью 12%
call CreateRandomItemMetalBox('I002', dyingUnitLoc, 12) // Создание предмета "Boots of Speed" с вероятностью 12%
call CreateRandomItemMetalBox('I007', dyingUnitLoc, 9) // Создание предмета "Claws of Attack +500" с вероятностью 9%
call CreateRandomUnitMetalBox('o00L', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_PASSIVE)) // Создание юнита "Clock warrior" с вероятностью 12%
call CreateRandomUnitMetalBox('n006', dyingUnitLoc, 6, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Sludge" с вероятностью 6%
// Удаление локации после использования
call RemoveLocation(dyingUnitLoc)
endfunction
// Инициализация триггера
function InitTrig_Random_item_Metal_box takes nothing returns nothing
set gg_trg_Random_item_Metal_box = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Random_item_Metal_box, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_Random_item_Metal_box, Condition(function Trig_Random_item_Metal_box_Conditions))
call TriggerAddAction(gg_trg_Random_item_Metal_box, function Trig_Random_item_Metal_box_Actions)
endfunction
endlibrary
library RandomItemMagicVault
// Условие: если умирающая единица - магическое хранилище ('n003')
function Trig_Random_item_Magic_treasure_Conditions takes nothing returns boolean
return GetUnitTypeId(GetDyingUnit()) == 'n003'
endfunction
// Функция для создания предмета
function CreateRandomItemMagicVault takes integer itemId, location loc, integer chance returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateItemLoc(itemId, loc)
endif
endfunction
// Функция для создания юнита
function CreateRandomUnitMagicVault takes integer unitId, location loc, integer chance, player whichPlayer returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateNUnitsAtLocFacingLocBJ(1, unitId, whichPlayer, loc, GetRandomLocInRect(GetPlayableMapRect()))
endif
endfunction
// Основная функция для создания предметов и юнитов с определенной вероятностью
function Trig_Random_item_Magic_treasure_Actions takes nothing returns nothing
local location dyingUnitLoc = GetUnitLoc(GetDyingUnit())
call CreateRandomItemMagicVault('I005', dyingUnitLoc, 18) // Создание предмета "Bundle of Lumber" с вероятностью 18%
call CreateRandomItemMagicVault('I005', dyingUnitLoc, 18) // Создание предмета "Bundle of Lumber" с вероятностью 18%
call CreateRandomItemMagicVault('I005', dyingUnitLoc, 18) // Создание предмета "Bundle of Lumber" с вероятностью 18%
call CreateRandomItemMagicVault('I009', dyingUnitLoc, 20) // Создание предмета "Ham" с вероятностью 20%
call CreateRandomItemMagicVault('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of Coins" с вероятностью 19%
call CreateRandomItemMagicVault('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of Coins" с вероятностью 19%
call CreateRandomItemMagicVault('I00A', dyingUnitLoc, 19) // Создание предмета "Bunch of Coins" с вероятностью 19%
call CreateRandomItemMagicVault('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemMagicVault('I00E', dyingUnitLoc, 20) // Создание предмета "Bundle of Lumber" с вероятностью 20%
call CreateRandomItemMagicVault('I006', dyingUnitLoc, 9) // Создание предмета "Ring of Protection +10" с вероятностью 9%
call CreateRandomItemMagicVault('I004', dyingUnitLoc, 15) // Создание предмета "Scroll of Healing" с вероятностью 15%
call CreateRandomItemMagicVault('I00N', dyingUnitLoc, 15) // Создание предмета "Gold Coins" с вероятностью 15%
call CreateRandomUnitMagicVault('e006', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Mimic" с вероятностью 12%
call CreateRandomUnitMagicVault('e006', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Mimic" с вероятностью 12%
call CreateRandomUnitMagicVault('e006', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Mimic" с вероятностью 12%
call CreateRandomItemMagicVault('I00B', dyingUnitLoc, 12) // Создание предмета "Khadgar's Gem of Health" с вероятностью 12%
call CreateRandomItemMagicVault('I003', dyingUnitLoc, 12) // Создание предмета "Gloves of Haste" с вероятностью 12%
call CreateRandomItemMagicVault('I002', dyingUnitLoc, 12) // Создание предмета "Boots of Speed" с вероятностью 12%
call CreateRandomItemMagicVault('I007', dyingUnitLoc, 9) // Создание предмета "Claws of Attack +500" с вероятностью 9%
call CreateRandomItemMagicVault('I00C', dyingUnitLoc, 9) // Создание предмета "Chest of Gold" с вероятностью 9%
call CreateRandomUnitMagicVault('o00L', dyingUnitLoc, 12, Player(PLAYER_NEUTRAL_PASSIVE)) // Создание юнита "Clock warrior" с вероятностью 12%
call CreateRandomItemMagicVault('I001', dyingUnitLoc, 8) // Создание предмета "Ankh of Reincarnation" с вероятностью 8%
call CreateRandomItemMagicVault('I008', dyingUnitLoc, 8) // Создание предмета "Runed Bracers" с вероятностью 8%
call CreateRandomUnitMagicVault('e007', dyingUnitLoc, 8, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Possessed tome" с вероятностью 8%
call CreateRandomUnitMagicVault('n006', dyingUnitLoc, 6, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Sludge" с вероятностью 6%
// Удаление локации после использования
call RemoveLocation(dyingUnitLoc)
endfunction
// Инициализация триггера
function InitTrig_Random_item_Magic_treasure takes nothing returns nothing
set gg_trg_Random_item_Magic_treasure = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Random_item_Magic_treasure, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_Random_item_Magic_treasure, Condition(function Trig_Random_item_Magic_treasure_Conditions))
call TriggerAddAction(gg_trg_Random_item_Magic_treasure, function Trig_Random_item_Magic_treasure_Actions)
endfunction
endlibrary
library RandomItemGoblins
// Условие: если умирающая единица - деревянный ящик ('n004'), металлический ящик ('n005') или магическое хранилище ('n003')
function Trig_Random_item_Goblins_Conditions takes nothing returns boolean
local integer unitTypeId = GetUnitTypeId(GetDyingUnit())
return unitTypeId == 'n003' or unitTypeId == 'n005' or unitTypeId == 'n004'
endfunction
// Функция для создания юнита
function CreateRandomGoblin takes integer unitId, location loc, integer chance, player whichPlayer returns nothing
if GetRandomInt(0, 100) <= chance then
call CreateNUnitsAtLocFacingLocBJ(1, unitId, whichPlayer, loc, GetRandomLocInRect(GetPlayableMapRect()))
endif
endfunction
// Основная функция для создания юнитов с определенной вероятностью
function Trig_Random_item_Goblins_Actions takes nothing returns nothing
local location dyingUnitLoc = GetUnitLoc(GetDyingUnit())
call CreateRandomGoblin('h00K', dyingUnitLoc, 3, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Former captain" с вероятностью 3%
call CreateRandomGoblin('n00A', dyingUnitLoc, 4, Player(PLAYER_NEUTRAL_AGGRESSIVE)) // Создание юнита "Sapper" с вероятностью 4%
call CreateRandomGoblin('h00P', dyingUnitLoc, 8, Player(bj_PLAYER_NEUTRAL_EXTRA)) // Создание юнита "Cartographer" с вероятностью 8%
// Удаление локации после использования
call RemoveLocation(dyingUnitLoc)
endfunction
// Инициализация триггера
function InitTrig_Random_item_Goblins takes nothing returns nothing
set gg_trg_Random_item_Goblins = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Random_item_Goblins, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(gg_trg_Random_item_Goblins, Condition(function Trig_Random_item_Goblins_Conditions))
call TriggerAddAction(gg_trg_Random_item_Goblins, function Trig_Random_item_Goblins_Actions)
endfunction
endlibrary
library GoblinZeppelin initializer onInit uses TimerHandlerLib
globals
private timer WoodenBoxTimer = null
private timer MetalBoxTimer = null
private timer MagicBoxTimer = null
endglobals
private function WoodenBoxCreate takes nothing returns nothing
local effect ef
local real x = GetUnitX(udg_Zeppelin)
local real y = GetUnitY(udg_Zeppelin)
call CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'n004', x, y, GetRandomDirectionDeg())
set ef = AddSpecialEffect("Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl", x, y)
call addEffectTimer(ef, 10)
endfunction
private function MetalBoxCreate takes nothing returns nothing
local effect ef
local real x = GetUnitX(udg_Zeppelin)
local real y = GetUnitY(udg_Zeppelin)
call CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'n005', x, y, GetRandomDirectionDeg())
set ef = AddSpecialEffect("Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl", x, y)
call addEffectTimer(ef, 10)
endfunction
private function MagicBoxCreate takes nothing returns nothing
local effect ef
local real x = GetUnitX(udg_Zeppelin)
local real y = GetUnitY(udg_Zeppelin)
call CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE), 'n003', x, y, GetRandomDirectionDeg())
set ef = AddSpecialEffect("Abilities\\Spells\\Human\\Resurrect\\ResurrectTarget.mdl", x, y)
call addEffectTimer(ef, 10)
endfunction
function WoodenBoxTimerStart takes nothing returns nothing
if(WoodenBoxTimer == null)then
set WoodenBoxTimer = CreateTimer()
call TimerStart(WoodenBoxTimer, 30.0, true, function WoodenBoxCreate)
endif
endfunction
function WoodenBoxTimerDestroy takes nothing returns nothing
call DestroyTimer(WoodenBoxTimer)
endfunction
function MetalBoxTimerStart takes nothing returns nothing
if(MetalBoxTimer == null)then
set MetalBoxTimer = CreateTimer()
call TimerStart(MetalBoxTimer, 30.0, true, function MetalBoxCreate)
endif
endfunction
function MetalBoxTimerDestroy takes nothing returns nothing
call DestroyTimer(MetalBoxTimer)
endfunction
function MagicBoxTimerStart takes nothing returns nothing
if(MagicBoxTimer == null)then
set MagicBoxTimer = CreateTimer()
call TimerStart(MagicBoxTimer, 30.0, true, function MagicBoxCreate)
endif
endfunction
function MagicBoxTimerDestroy takes nothing returns nothing
call DestroyTimer(MagicBoxTimer)
endfunction
endlibrary
library weatherRain
/*
В будущем: Убрать экспл. таймеры для юнитов-эффектов
заменить их одим таймером и масивами
*/
globals
real Radius = 256.0 //Радиус урона от молний
real DemForBuild = 0.20 //Урон строениям
real DemForUnits = 0.50 //Урон юнитам
real NewRainTime = 350 //Среднее время до нового дождя
real ItsRainingTime = 75 //Среднее время дождя
real LightningStrikeTime = 8 //Среднее время между ударами молнии
/*
Время до начала дождя Tr = NewRainTime +- NewRainTime/4
Генерируется время дождя как: T0 = ItsRainingTime +- ItsRainingTime/3.
N_bolts = T0/LightningStrikeTime - кол-во молний за дождь.
Генерируется N_bolts таймеров, случайно разбросанных на время дождя,
до каждого из ударов молний.
*/
timer NewRain_timer
//Для дождя
weathereffect Rain_effect
timer ItsRaining_timer
boolean ItsRaining
sound Rain_sound
code RainStart_Func
//Для молнии
timer LightningStrike_timer
sound array Lighting_sounds //integer Lighting_SoundCounter;
unit LightingBolt
endglobals
//Функция для взаимодействия с разр. объектами
function DestLightTarg takes nothing returns nothing
call KillDestructable(GetEnumDestructable())
endfunction
//Функция для взаимодействия с юнитами
function UnitLightTarg takes nothing returns boolean
local unit un = GetFilterUnit()
local real NewLife
//Если юнит
if(IsUnitType(un, UNIT_TYPE_STRUCTURE) == false and not ( GetUnitAbilityLevel(un, 'Avul') == 1 ) ) then
set NewLife = GetUnitState(un, UNIT_STATE_LIFE) - GetUnitState(un, UNIT_STATE_MAX_LIFE)*GetRandomReal(0.25,1.375) //Урон юнитам от 25 до 137.5%, 33% убить юнита с 100% хп
call SetUnitState(un, UNIT_STATE_LIFE, NewLife)
return true
endif
//Если здание
if(IsUnitType(un, UNIT_TYPE_STRUCTURE) == true) then
set NewLife = GetUnitState(un, UNIT_STATE_LIFE) - GetUnitState(un, UNIT_STATE_MAX_LIFE)*GetRandomReal(0.05,0.3)//Урон зданиям от 5 до 30%
call SetUnitState(un, UNIT_STATE_LIFE, NewLife)
return true
endif
return false
endfunction
//Функция генерирующая удар молнии
function LightningStrike takes nothing returns nothing
local real x_c
local real y_c
local real d
local rect Rectic
local unit loc_LightingBolt
local group gr
local timer This_timer = GetExpiredTimer()
local location Point
call DestroyTimer(This_timer)
if(ItsRaining == false)then
return
endif
set Point = GetRandomLocInRect(bj_mapInitialPlayableArea)
set x_c = GetLocationX( Point )
set y_c = GetLocationY( Point )
set d = Radius
//
set Rectic = Rect(x_c - d, y_c - d, x_c + d, y_c + d)
//Поиск деревьев в области
call EnumDestructablesInRect(Rectic, null, function DestLightTarg)
//поиск юнитов в области
set gr = CreateGroup()
call GroupEnumUnitsInRect(gr, Rectic, function UnitLightTarg)
call DestroyGroup(gr)
//Создание спецэффектов
//Юниты
set loc_LightingBolt = CreateUnitAtLoc(Player(PLAYER_NEUTRAL_PASSIVE), 'h00A', Point, 100.0)
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', loc_LightingBolt )
set loc_LightingBolt = CreateUnitAtLoc(Player(PLAYER_NEUTRAL_PASSIVE), 'h00C', Point, 100.0)
call UnitApplyTimedLifeBJ( 1.50, 'BTLF', loc_LightingBolt )
//Остальное...
call CinematicFadeBJ( bj_CINEFADETYPE_FADEOUTIN, 0.70,"ReplaceableTextures\\CameraMasks\\White_mask.blp",100.00, 100.00, 100.00, 10.00 )
call StartSound(Lighting_sounds[0])
call StartSound(Lighting_sounds[GetRandomInt(1,2)])
//
//Деструкция
set LightingBolt = loc_LightingBolt
call RemoveRect(Rectic)
call RemoveLocation(Point)
endfunction
//Функция вызывающая окончание дождя
function RainFinish takes nothing returns nothing
local real loc_NewRainTime
call StopSound(Rain_sound, false, true)
call EnableWeatherEffect( Rain_effect, false )
call DestroyTimer(ItsRaining_timer)
//
set ItsRaining = false
//
//Таймер до дождя.
set loc_NewRainTime = NewRainTime + GetRandomReal( - NewRainTime/3,NewRainTime/3)
set NewRain_timer = CreateTimer()
call TimerStart(NewRain_timer, loc_NewRainTime, false, RainStart_Func)
endfunction
//LightningStrike_timer;
//Функция вызывающая начало дождя
function RainStart takes nothing returns nothing
local integer N_bolts
local timer Bolts_timer
local real Bolt_time
local integer i = 0
local real loc_ItsRainingTime
call DestroyTimer(NewRain_timer)
//
call StartSound(Rain_sound)
//Запуск спецэффекта
call EnableWeatherEffect( Rain_effect, true )
//Вычисление времени длительности дождя
set loc_ItsRainingTime = ItsRainingTime + GetRandomReal( - ItsRainingTime/4, ItsRainingTime/4)
//
//Запуск таймера до окончания дождя
set ItsRaining_timer = CreateTimer()
call TimerStart(ItsRaining_timer, loc_ItsRainingTime ,false,function RainFinish)
//
//Вычисление кол-ва молний
set N_bolts = R2I(loc_ItsRainingTime/LightningStrikeTime) - 1
//Запуск таймера генераций молний
loop
set i = i + 1
set Bolts_timer = CreateTimer()
set Bolt_time = GetRandomReal(2, loc_ItsRainingTime - 2)
call TimerStart(Bolts_timer, Bolt_time, true, function LightningStrike)
exitwhen(i == N_bolts)
endloop
//
set ItsRaining = true
endfunction
//Инициализация дождя
function WeatherINI takes nothing returns nothing
local real loc_NewRainTime
set Lighting_sounds[0] = gg_snd_LightningBolt1
set Lighting_sounds[1] = gg_snd_LightningBolt2
set Lighting_sounds[2] = gg_snd_LightningBolt3
set Rain_sound = gg_snd_Rain3 //Звук дождя
set RainStart_Func = function RainStart
set Rain_effect = AddWeatherEffect(bj_mapInitialPlayableArea, 'RAhr')
set ItsRaining = false
//
//Таймер до дождя.
set loc_NewRainTime = NewRainTime + GetRandomReal( - NewRainTime/4, NewRainTime/4)
set NewRain_timer = CreateTimer()
call TimerStart(NewRain_timer, loc_NewRainTime, false, RainStart_Func)
endfunction
function LightingRemove takes unit loc_Dying, integer unit_TypeID returns boolean
if( unit_TypeID == 'h009' or unit_TypeID == 'h00H' or unit_TypeID == 'h00A' or unit_TypeID == 'h00B' or unit_TypeID == 'h00C' ) then
call RemoveUnit( loc_Dying )
return true
endif
return false
endfunction
endlibrary
library FogSystem initializer onInit
/*
Эта система добавляет туман в игру в определенные ночные часы.
Туман может быть легким или тяжелым и уменьшает видимость всех юнитов, за исключением нейтральных юнитов, 11 и 12 игроков.
Система работает следующим образом:
1. Внутри игры проверяется текущее время каждые 20 секунд.
2. Если время с 21:00 до 7:00, есть 5% шанс активации тумана.
3. Если туман активируется, он может быть либо легким (60%), либо тяжелым (40%):
- Легкий туман уменьшает видимость юнитов на -300
- Тяжелый туман уменьшает видимость юнитов на -450.
4. Когда время выходит за пределы указанного диапазона (21:00 - 8:00), туман удаляется.
5. При деактивации тумана видимость юнитов восстанавливается до исходного уровня.
*/
globals
private timer fogCheckTimer
private trigger enterRegionTrigger
private boolean fogActive = false
private boolean fogCheckedTonight = false
private integer currentHour
private integer fogAbilityId = 0 // ID способности тумана (0 = нет тумана, 'A036' = легкий туман, 'A035' = тяжелый туман)
endglobals
// Функция для применения способности тумана к юниту
private function ApplyFogAbility takes unit u, integer abilityId returns nothing
if GetUnitState(u, UNIT_STATE_LIFE) > 0 then
// Проверяем, является ли юнит нейтральным враждебным, пассивным, экстра или жертвой, 11, 12 и исключаем их
if IsUnitOwnedByPlayer(u, Player(PLAYER_NEUTRAL_AGGRESSIVE)) then
return
elseif IsUnitOwnedByPlayer(u, Player(PLAYER_NEUTRAL_PASSIVE)) then
return
elseif IsUnitOwnedByPlayer(u, Player(bj_PLAYER_NEUTRAL_EXTRA)) then
return
elseif IsUnitOwnedByPlayer(u, Player(bj_PLAYER_NEUTRAL_VICTIM)) then
return
elseif IsUnitOwnedByPlayer(u, Player(10)) or IsUnitOwnedByPlayer(u, Player(11)) then
return
endif
if GetUnitAbilityLevel(u, abilityId) == 0 then
call UnitAddAbility(u, abilityId)
endif
endif
endfunction
// Функция для удаления способности тумана у юнита
private function RemoveFogAbility takes unit u, integer abilityId returns nothing
if GetUnitAbilityLevel(u, abilityId) > 0 then
call UnitRemoveAbility(u, abilityId)
endif
endfunction
// Функция для применения способности тумана ко всем юнитам на карте
private function ApplyFogAbilityToAllUnits takes integer abilityId returns nothing
local group g = CreateGroup()
local unit u
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call ApplyFogAbility(u, abilityId)
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
set g = null
endfunction
// Функция для удаления способности тумана у всех юнитов на карте
private function RemoveFogAbilityFromAllUnits takes nothing returns nothing
local group g = CreateGroup()
local unit u
call GroupEnumUnitsInRect(g, bj_mapInitialPlayableArea, null)
loop
set u = FirstOfGroup(g)
exitwhen u == null
call RemoveFogAbility(u, 'A036') // Легкий туман
call RemoveFogAbility(u, 'A035') // Тяжелый туман
call GroupRemoveUnit(g, u)
endloop
call DestroyGroup(g)
set g = null
endfunction
// Функция для активации тумана
private function ApplyFog takes nothing returns nothing
local real chance = GetRandomReal(0, 100)
if chance <= 60 then
// Активируем легкий туман
call SetTerrainFogExBJ(0, 1000, 4500, 0.25, 100, 100, 100)
set fogAbilityId = 'A036'
call ApplyFogAbilityToAllUnits(fogAbilityId)
//call BJDebugMsg("Легкий туман активирован")
else
// Активируем тяжелый туман
call SetTerrainFogExBJ(0, 0, 2500, 1.00, 100, 100, 100)
set fogAbilityId = 'A035'
call ApplyFogAbilityToAllUnits(fogAbilityId)
//call BJDebugMsg("Тяжелый туман активирован")
endif
set fogActive = true
set fogCheckedTonight = true
endfunction
// Функция для деактивации тумана
private function RemoveFog takes nothing returns nothing
if fogActive then
call ResetTerrainFogBJ()
//call BJDebugMsg("Туман деактивирован")
// Восстанавливаем видимость всех юнитов
call RemoveFogAbilityFromAllUnits()
set fogAbilityId = 0
set fogActive = false
endif
endfunction
// Функция проверки времени и активации тумана
private function CheckForFogActivation takes nothing returns nothing
local real chance = GetRandomReal(0, 100)
set currentHour = R2I(GetFloatGameState(GAME_STATE_TIME_OF_DAY))
//call BJDebugMsg("Текущее время: " + I2S(currentHour))
if currentHour >= 21 or currentHour < 7 then // Начало проверки с 21:00 до 7:00
//call BJDebugMsg("Проверка на туман. Время в диапазоне 21:00 - 7:00.")
if not fogCheckedTonight then
//call BJDebugMsg("Туман еще не был активирован этой ночью.")
//call BJDebugMsg("Проверка активации системы тумана. Шанс: " + R2S(chance))
if chance <= 5 then // Вероятность активации тумана 5%
call ApplyFog()
endif
endif
elseif currentHour >= 8 and currentHour < 21 then // Деактивация тумана с 8:00 до 21:00
//call BJDebugMsg("Время не в диапазоне 21:00 - 8:00. Деактивация тумана.")
call RemoveFog()
set fogCheckedTonight = false
endif
endfunction
// Функция обработки входа юнита в регион
private function OnUnitEnterRegion takes nothing returns nothing
local unit u = GetEnteringUnit()
if fogActive and fogAbilityId != 0 then
call ApplyFogAbility(u, fogAbilityId)
endif
set u = null
endfunction
// Функция инициализации системы тумана
private function StartFogCheckTimer takes nothing returns nothing
call TimerStart(fogCheckTimer, 20.0, true, function CheckForFogActivation) // Проверка установлена на 20 секунд, один кружок циферблата WC3
endfunction
private function InitFogSystem takes nothing returns nothing
set fogCheckTimer = CreateTimer()
call TimerStart(fogCheckTimer, 0.1, false, function StartFogCheckTimer) // Инициализация таймера с задержкой 0.1 секунд
set enterRegionTrigger = CreateTrigger()
call TriggerRegisterEnterRectSimple(enterRegionTrigger, bj_mapInitialPlayableArea)
call TriggerAddAction(enterRegionTrigger, function OnUnitEnterRegion)
endfunction
// Инициализация системы
private function onInit takes nothing returns nothing
call InitFogSystem()
endfunction
endlibrary
library LumberBounty uses DefaultTextTag
function GetBounty takes integer Base, integer DiceNum, integer DiceSide returns integer
local integer Bounty = Base
local integer Dice = 0
loop
exitwhen Dice == DiceNum
set Bounty = Bounty + GetRandomInt(1, DiceSide)
set Dice = Dice + 1
endloop
return Bounty
endfunction
struct LumberBounty
static method run takes unit src_un, unit tg_un, integer amount returns nothing
local string loc_str
local texttag tt
local real x = GetUnitX(tg_un)
local real y = GetUnitY(tg_un)
// Регулировка состояния игрока (добавление древесины)
call AdjustPlayerStateBJ(amount, GetOwningPlayer(src_un), PLAYER_STATE_RESOURCE_LUMBER)
// Форматирование строки для текстовой метки
set loc_str = "+" + I2S(amount)
// Создание текстовой метки
set tt = DefaultTextTag(TextTagLumberBounty, x, y, loc_str)
// Установка видимости текстовой метки только для игрока, который убил энта
if GetLocalPlayer() == GetOwningPlayer(src_un) then
call SetTextTagVisibility(tt, true)
endif
endmethod
endstruct
endlibrary
function Trig_Wisp_remove_lv0_Conditions takes nothing returns boolean
if ( not ( GetUnitTypeId(GetDyingUnit()) == 'e00B' ) ) then
return false
endif
return true
endfunction
function Trig_Wisp_remove_lv0_Actions takes nothing returns nothing
local integer a = 0
loop
exitwhen ((udg_WispHarvestLV0[a] == GetDyingUnit()) or (a == udg_WispCountLV0 ))
set a = a + 1
endloop
set udg_WispCountLV0 = ( udg_WispCountLV0 - 1 )
set udg_WispHarvestLV0[a] = udg_WispHarvestLV0[udg_WispCountLV0]
endfunction
//===========================================================================
function InitTrig_Wisp_remove_lv0 takes nothing returns nothing
set gg_trg_Wisp_remove_lv0 = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Wisp_remove_lv0, EVENT_PLAYER_UNIT_DEATH )
call TriggerAddCondition( gg_trg_Wisp_remove_lv0, Condition( function Trig_Wisp_remove_lv0_Conditions ) )
call TriggerAddAction( gg_trg_Wisp_remove_lv0, function Trig_Wisp_remove_lv0_Actions )
endfunction
library Leshi
function PuckCond_Flugs takes unit un returns boolean
local integer tpid = GetUnitTypeId(un)
local boolean bool = /*
*/ not(IsUnitType(un, UNIT_TYPE_STRUCTURE) ) and /*
*/ not(IsUnitType(un, UNIT_TYPE_MAGIC_IMMUNE)) and /*
*/ not(IsUnitType(un, UNIT_TYPE_MECHANICAL)) and /*
*/ not(IsUnitType(un, UNIT_TYPE_HERO)) and /*
*/ not(BlzIsUnitInvulnerable(un)) and /*
*/ GetUnitState(un, UNIT_STATE_LIFE) > 0 and /*
*/ GetOwningPlayer(un) != Player(10) and /*
*/ IsUnitVisible(un, Player(10)) and /*
*/ ( tpid != 'n001' and tpid != 'n014' ) // лесной паук и ткач
return bool
endfunction
function PuckCond takes nothing returns boolean
local unit un = GetFilterUnit()
return PuckCond_Flugs(un)
endfunction
function LeshiMove takes nothing returns nothing
local group gr = GetUnitsInRectMatching(GetPlayableMapRect(), Condition(function PuckCond))
local unit un = GroupPickRandomUnit(gr)
call BlzEndUnitAbilityCooldown(udg_Leshi, 'A01E')
// call BJDebugMsg("Пытаюсь одеревянить")
if (un != null) then
call IssueTargetOrderBJ(udg_Leshi, "thunderbolt", un)
// call BJDebugMsg("Бегу со всех ног")
else
// call BJDebugMsg("Попытка неудачная")
endif
// Очистка группы после использования
call DestroyGroup(gr)
set gr = null // Обнуление переменной группы
endfunction
function LeshiMoveStart takes nothing returns nothing
// call BJDebugMsg("начинаю деревянить")
call TimerStart(CreateTimer(), 20.0, true, function LeshiMove)
endfunction
endlibrary
function Trig_Leshi_move_out_Actions takes nothing returns nothing
local location moveLoc = GetRandomLocInRect(GetPlayableMapRect())
// Действие - леший побежал в случайную игровую точку на карте
call IssuePointOrderLocBJ(udg_Leshi, "move", moveLoc)
// Уничтожение локации
call RemoveLocation(moveLoc)
endfunction
//===========================================================================
function InitTrig_Leshi_move_out takes nothing returns nothing
set gg_trg_Leshi_move_out = CreateTrigger()
call TriggerRegisterTimerExpireEventBJ(gg_trg_Leshi_move_out, udg_LeshiMoveOutTimer)
call TriggerAddAction(gg_trg_Leshi_move_out, function Trig_Leshi_move_out_Actions)
endfunction
library Jokes uses DefaultTextTag
globals
private string array Leshi_Jokes
private integer Leshi_Jokes_Counter
private texttag Timed_Text
endglobals
function Leshi_Jokes_INI takes nothing returns nothing
if (BlzGetLocale() == "ruRU") then
set Leshi_Jokes[0] = "Пинокио"
set Leshi_Jokes[1] = "Одеревянивание"
set Leshi_Jokes[2] = "Опа, дуб!"
set Leshi_Jokes[3] = "сАсАть"
set Leshi_Jokes[4] = "Расти большой..."
set Leshi_Jokes[5] = "Береги дупло"
set Leshi_Jokes[6] = "Зеленка"
set Leshi_Jokes[7] = "Пустил корни"
set Leshi_Jokes[8] = "Теперь срубят тебя!"
set Leshi_Jokes[9] = "Приветствую в партии Зеленых"
set Leshi_Jokes[10] = "Похож на мою бывшую"
set Leshi_Jokes[11] = "Мммбереза"
else
set Leshi_Jokes[0] = "Pinocchio"
set Leshi_Jokes[1] = "Wooding"
set Leshi_Jokes[2] = "Whoa oak!"
set Leshi_Jokes[3] = "Suck it"
set Leshi_Jokes[4] = "Grow big..."
set Leshi_Jokes[5] = "Take care of the hollow"
set Leshi_Jokes[6] = "Zelyonka"
set Leshi_Jokes[7] = "Put down roots"
set Leshi_Jokes[8] = "Now they'll cut you down!"
set Leshi_Jokes[9] = "Welcome to the Green Party"
set Leshi_Jokes[10] = "Looks like my ex"
set Leshi_Jokes[11] = "Mmmbirch"
endif
set Leshi_Jokes_Counter = 12
endfunction
function Create_Joke takes location Joke_Point, unit triggerUnit returns nothing
local integer JokeNumber = GetRandomInt(0, Leshi_Jokes_Counter - 1)
local real x = GetLocationX(Joke_Point)
local real y = GetLocationY(Joke_Point)
local texttag tt
local player p
local integer i = 0
// Создание текстовой метки с помощью DefaultTextTag
set tt = DefaultTextTag(TextTagLumberBounty, x, y, Leshi_Jokes[JokeNumber])
set Timed_Text = tt
// Установка видимости текстовой метки для всех игроков, которым виден юнит
loop
exitwhen i >= bj_MAX_PLAYER_SLOTS
set p = Player(i)
if IsUnitVisible(triggerUnit, p) and GetLocalPlayer() == p then
call SetTextTagVisibility(tt, true)
endif
set i = i + 1
endloop
call RemoveLocation(Joke_Point)
endfunction
endlibrary
library AICore initializer onInit requires AICoreBehavior, AITownLib, AICitizenBehavior,
//
globals
unit udg_AICoreTree
private trigger udg_trg_TrainFinishEvent
integer AI_Ent_Counter
integer AI_Wisp_Counter
integer AI_Tower_Count
//
private hashtable udg_HashTable
integer udg_CoreStage
integer udg_CoreStageMax = 3
trigger udg_trg_BuildStart
trigger udg_trg_BuildFinish
trigger udg_trg_Dying
endglobals
//
//
//! runtextmacro UnitHashHandler("Ent" , "1", "1")
//! runtextmacro UnitHashHandler("Wisp", "2", "1")
//
//
function CoreTryStageUpgrade takes nothing returns nothing
if (udg_CoreStage == 0 and udg_CoreStageMax > 0)then
//call BJDebugMsg("Пытаюсь сделать исследование 0")
call CoreReserchStart()
elseif(udg_CoreStage == 1 and udg_CoreStageMax > 1)then
//call BJDebugMsg("Пытаюсь сделать исследование 1")
call CoreUpgradeStart()
elseif(udg_CoreStage == 2 and udg_CoreStageMax > 2)then
//call BJDebugMsg("Пытаюсь сделать исследование 2")
call CoreReserchStart()
elseif(udg_CoreStage == 3 and udg_CoreStageMax > 3)then
//call BJDebugMsg("Пытаюсь сделать исследование 3")
call CoreReserchStart()
elseif(udg_CoreStage == 4 and udg_CoreStageMax > 4)then
//call BJDebugMsg("Пытаюсь сделать исследование 4")
call CoreUpgradeStart()
debug else
debug call BJDebugMsg("Исследования закончены")
endif
endfunction
//
// ====
function BuildTowerPereodic takes nothing returns nothing
local real DX = 3000.
local real DY = 3000.
local real X_T = GetRandomReal(0, DX) - DX/2 + GetUnitX(udg_AICoreTree)
local real Y_T = GetRandomReal(0, DY) - DY/2 + GetUnitY(udg_AICoreTree)
if(udg_CoreStage >= 2)then
if ((AI_Tower_Count < 3) and (udg_CoreStage == 3)) then
call BuildTower(X_T, Y_T, 'e004')
elseif((AI_Tower_Count < 5) and (udg_CoreStage == 4)) then
call BuildTower(X_T, Y_T, 'e004')
elseif((AI_Tower_Count < 10) and (udg_CoreStage >= 5)) then
call BuildTower(X_T, Y_T, 'e004')
endif
endif
endfunction
//
// ====
function BuildTowerPereodic_Init takes nothing returns nothing
local timer loc_timer
set loc_timer = CreateTimer()
call TimerStart(loc_timer ,10 ,true ,function BuildTowerPereodic)
endfunction
//
// ====
function ReserchCheckPereodic_Init takes nothing returns nothing
local timer loc_timer
set loc_timer = CreateTimer()
call TimerStart(loc_timer ,10 ,true ,function CoreTryStageUpgrade)
endfunction
//
// ==== Создание Начального Дерева =============================
function AI_Start takes nothing returns nothing
local location TreeLoc = MB.MainLocs.TakeLocation()
set udg_AICoreTree = CreateUnitAtLoc( Player(10), 'e003', TreeLoc, bj_UNIT_FACING)
call RemoveLocation( TreeLoc )
set udg_AICoreBuilding = udg_AICoreTree
set udg_CoreStage = 0
//
call CoreBehavior_Start(udg_AICoreTree)
call BuildTowerPereodic_Init()
call ReserchCheckPereodic_Init()
endfunction
//
// ==== Функция обрабатывающая инициализацию AI ================
function Initialz_AI takes nothing returns nothing
local timer loc_timer
set loc_timer = CreateTimer()
call TimerStart(loc_timer ,1 ,false ,function AI_Start)
endfunction
//
// ==== Событие найма AI юнита =================================
function Trig_AIUnitTrain takes unit loc_Traine, integer loc_UnitTypeID returns boolean
//
if(loc_UnitTypeID == 'e001')then// Энт Развитие
call AddHarvester(loc_Traine)
call AddCitizen(loc_Traine, true, false)
call EntAdd(loc_Traine)
call IssueImmediateOrder( loc_Traine, "autoharvestlumber" )
set AI_Ent_Counter = udg_Ent_Count
set AI_Wisp_Counter = udg_Wisp_Count
return true
endif
//
if(loc_UnitTypeID == 'e000')then
call AddHarvester(loc_Traine)
call AddCitizen(loc_Traine, false, true)
call WispAdd(loc_Traine)
call IssueImmediateOrder( loc_Traine, "autoharvestlumber" )
set AI_Ent_Counter = udg_Ent_Count
set AI_Wisp_Counter = udg_Wisp_Count
return true
endif
return false
endfunction
//
// ==== Событие смерти AI юнита ==================================
function Trig_AIEntDeath_Actions takes unit Dying, integer Dying_ID returns boolean
local integer i = 0
if (Dying_ID == 'e001') then
call EntIDRemove(Dying)
return true
endif
//
if (Dying_ID == 'e000') then
call WispIDRemove(Dying)
endif
return false
endfunction
//
// ==== Обработка уничтожения юнита из масива при постройке башни ====
function Trig_Wisp_remove_Actions takes unit loc_build returns boolean
local integer i
local boolean array loc_bool
if(GetUnitTypeId(loc_build) == 'e004')then
set i = 0
loop
set loc_bool[0] = IsUnitHidden(udg_Wisp[i]) == true
set loc_bool[1] = GetUnitCurrentOrder(udg_Wisp[i]) == String2OrderIdBJ("custom_e004")
set loc_bool[2] = (i == udg_Wisp_Count)
exitwhen ((loc_bool[0]) and (loc_bool[1])) or (loc_bool[2])
set i = i + 1
endloop
if(i != udg_Wisp_Count)then
call RemoveCitizen(udg_Wisp[i])
call RemoveHarvester(udg_Wisp[i])
call WispIDRemove(udg_Wisp[i])
//debug call BJDebugMsg("Строящий висп успешно удален отовсюду")
//else
//debug call BJDebugMsg("Висп ненайден")
endif
return true
endif
return false
endfunction
//
// ==== Проверка принадлежит юнит AI ====
private function IsUnitAIType_Conditions takes unit un returns boolean
if (GetUnitTypeId(un) == 'e001')then
return true
elseif(GetUnitTypeId(un) == 'e000')then
return true
endif
return false
endfunction
//
// ==== Что делать с тренированныым ====
function Trig_UnitHarvest takes nothing returns nothing
local unit loc_Traine = GetTrainedUnit()
local integer loc_UnitTypeID = GetUnitTypeId(loc_Traine )
//Найм Юнитов AI
call Trig_AIUnitTrain( loc_Traine, loc_UnitTypeID )
endfunction
//
// ==== Принадлежит ли тренированный юнит AI ========
private function IsTrainedAI_Conditions takes nothing returns boolean
return IsUnitAIType_Conditions(GetTrainedUnit())
endfunction
//
// ==== Функция начала строительства
private function Trig_UnitBuilded takes nothing returns nothing
local unit un = GetTriggerUnit()
if(GetUnitTypeId(un) == 'e004') then
set AI_Tower_Count = AI_Tower_Count + 1
call Trig_Wisp_remove_Actions(un)
endif
endfunction
//
//
private function Trig_TowerDead takes nothing returns nothing
if(GetUnitTypeId(GetDyingUnit()) == 'e004') then
set AI_Tower_Count = AI_Tower_Count - 1
endif
endfunction
//
// ==== Инициализция ================================
private function onInit takes nothing returns nothing
// Инициализация переменных
set AI_Ent_Counter = 0
set AI_Wisp_Counter = 0
set udg_Ent_Count = 0
set udg_Wisp_Count = 0
set AI_Tower_Count = 0
set udg_HashTable = InitHashtable()
// Событие найма юнитов
//
set udg_trg_TrainFinishEvent = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( udg_trg_TrainFinishEvent, EVENT_PLAYER_UNIT_TRAIN_FINISH )
call TriggerAddCondition( udg_trg_TrainFinishEvent, Condition( function IsTrainedAI_Conditions ) )
call TriggerAddAction( udg_trg_TrainFinishEvent, function Trig_UnitHarvest )
//
//Событие начала строительства
set udg_trg_BuildFinish = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( udg_trg_BuildFinish, EVENT_PLAYER_UNIT_CONSTRUCT_START )
call TriggerAddAction( udg_trg_BuildFinish, function Trig_UnitBuilded )
//
// Инициализация триггера отслеживающая мертвых башень
set udg_trg_Dying = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ( udg_trg_Dying, EVENT_PLAYER_UNIT_DEATH )
//call TriggerAddCondition( udg_trg_Dying, Condition( function IsDiyngType_Conditions ) )
call TriggerAddAction( udg_trg_Dying, function Trig_TowerDead )
endfunction
endlibrary
library AICoreBehavior initializer onInit
globals
timer udg_HrvsBuild_timer
unit udg_AICore
integer CoreTier
boolean udg_interrupted
endglobals
//
// ====
private function isPlayerHaveRssReserch takes player pl, integer id returns boolean
local integer WoodCost = GetUpgradeWoodCost(id)
local integer GoldCost = GetUpgradeGoldCost(id)
local integer WoodHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_LUMBER)
local integer GoldHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_GOLD)
return (WoodCost <= WoodHave) and (GoldCost <= GoldHave)
endfunction
//
// ====
private function isPlayerHaveRssUnit takes player pl, integer id returns boolean
local integer WoodCost = GetUnitWoodCost(id)
local integer GoldCost = GetUnitGoldCost(id)
local integer WoodHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_LUMBER)
local integer GoldHave = GetPlayerState(pl, PLAYER_STATE_RESOURCE_GOLD)
return (WoodCost <= WoodHave) and (GoldCost <= GoldHave)
endfunction
//
// ==== Функция Инициализирующая строительство юнита
function CoreBuildHrvsStart takes nothing returns nothing
if( AI_Ent_Counter*2 <= AI_Wisp_Counter ) then
call IssueImmediateOrderById( udg_AICore, 'e001' )//Энт (развитие)
else
call IssueImmediateOrderById( udg_AICore, 'e000' )//Светлячек
endif
endfunction
function StopAllTrain takes unit un returns nothing
local integer i = 0
loop
call IssueImmediateOrderById(udg_AICore, 851976)
set i = i + 1
exitwhen(i == 9)
endloop
endfunction
//
// ===
function CoreReserchStart takes nothing returns boolean
if( GetUnitTypeId(udg_AICore) == 'e003' ) then
if(isPlayerHaveRssReserch(GetOwningPlayer(udg_AICore),'R002')) then
if(udg_interrupted == true)then
call StopAllTrain(udg_AICore)
if(IssueImmediateOrderById( udg_AICoreBuilding, 'R002' ))then
set udg_interrupted = false
return true
debug else
debug call BJDebugMsg("Ошибка")
endif
endif
endif
elseif( GetUnitTypeId(udg_AICore) == 'e002' ) then
if(isPlayerHaveRssReserch(GetOwningPlayer(udg_AICore),'R006')) then
if(udg_interrupted == true)then
call StopAllTrain(udg_AICore)
if(IssueImmediateOrderById( udg_AICoreBuilding, 'R006' ))then
set udg_interrupted = false
return true
debug else
debug call BJDebugMsg("Ошибка")
endif
endif
endif
elseif( GetUnitTypeId(udg_AICore) == 'e002' ) then
//call null
endif
return false
endfunction
// ====
function CoreUpgradeStart takes nothing returns boolean
if( GetUnitTypeId(udg_AICore) == 'e003' )then
if(isPlayerHaveRssUnit(GetOwningPlayer(udg_AICore),'e002'))then
if(udg_interrupted == true)then
call StopAllTrain(udg_AICore)
if(IssueImmediateOrderById(udg_AICore, 'e002'))then
set udg_interrupted = false
return true
debug else
debug call BJDebugMsg("Ошибка")
endif
endif
endif
elseif(GetUnitTypeId(udg_AICore) == 'e002')then
if(isPlayerHaveRssUnit(GetOwningPlayer(udg_AICore),'e005'))then
if(udg_interrupted == true)then
call StopAllTrain(udg_AICore)
if(IssueImmediateOrderById(udg_AICore, 'e005'))then
set udg_interrupted = false
return true
debug else
debug call BJDebugMsg("Ошибка")
endif
endif
endif
endif
return false
endfunction
//
// ====
function BuildHrvs_Start takes nothing returns nothing
set udg_HrvsBuild_timer = CreateTimer()
call TimerStart(udg_HrvsBuild_timer, 10,true, function CoreBuildHrvsStart)
endfunction
function CoreBehavior_Start takes unit AICore returns nothing
call BuildHrvs_Start()
set udg_AICore = AICore
set CoreTier = 1
endfunction
private function onInit takes nothing returns nothing
set udg_interrupted = true
endfunction
endlibrary
library AICitizenBehavior initializer onInit uses BuildLib, AITownLib
function BuildTower takes real X, real Y, integer TowerID returns nothing
local unit loc_un = GetRandomBuilder()
local boolean loc_bool
if(loc_un != null) then
if(isPlayerHaveRssUnit(GetOwningPlayer(loc_un) ,TowerID)) then
set loc_bool = SearchForBuild( loc_un, TowerID, X, Y)
debug else
//debug call BJDebugMsg("Недостаточно ресурсов")
endif
debug else
//debug call BJDebugMsg("Нет свободных рабочих")
endif
endfunction
private function onInit takes nothing returns nothing
endfunction
endlibrary
library AIFunctions
//Функция спасения виспа
function WispMove takes unit loc_Attaked returns boolean
local location coreLocation = null
if(GetUnitTypeId(loc_Attaked) == 'e000')then
set coreLocation = GetUnitLoc(udg_AICoreBuilding)
call IssuePointOrderLoc(loc_Attaked, "move", coreLocation)
call RemoveLocation(coreLocation) // Удаление созданной локации
set coreLocation = null
return true
endif
// Если coreLocation была создана, но условие не выполнено, всё равно удаляем
if coreLocation != null then
call RemoveLocation(coreLocation)
set coreLocation = null
endif
return false
endfunction
endlibrary
library MachinerySystem initializer onInit uses TimerHandlerLib
struct MACH extends array
static unit array Machinery
static method SelectForTriggeringPlayer takes nothing returns nothing
local player pl = GetTriggerPlayer()
if(GetLocalPlayer() == pl)then
call ClearSelection()
call SelectUnit(MACH.Machinery[GetPlayerId(pl)], true)
endif
endmethod
static method MachineryCreateForUnit takes unit un returns nothing
set MACH.Machinery[GetPlayerId(GetOwningPlayer(un))] = /*
*/CreateUnit(GetOwningPlayer(un), 'h001', GetUnitX(un), GetUnitY(un), bj_UNIT_FACING)
endmethod
endstruct
endlibrary
library MarketSystem initializer onInit uses TimerHandlerLib
struct MRTS extends array
static unit array Market
static method SelectForTriggeringPlayer takes nothing returns nothing
local player pl = GetTriggerPlayer()
if(GetLocalPlayer() == pl)then
call ClearSelection()
call SelectUnit(MRTS.Market[GetPlayerId(pl)], true)
endif
endmethod
static method MarketCreateForUnit takes unit un returns nothing
set MRTS.Market[GetPlayerId(GetOwningPlayer(un))] = /*
*/CreateUnit(GetOwningPlayer(un), 'h003', GetUnitX(un), GetUnitY(un), bj_UNIT_FACING)
endmethod
endstruct
private function PlaySnd takes real x, real y, string soundpath returns nothing
local sound loc_sound = CreateSound(soundpath, false, true, true, 1, 1, "SpellsEAX")
call SetSoundChannel(loc_sound, 0)
call SetSoundPitch(loc_sound, 1)
call SetSoundPosition(loc_sound, x, y, 120)
call SetSoundVolume(loc_sound, 172)
call SetSoundDistanceCutoff(loc_sound, 1024)
call StartSound(loc_sound)
call KillSoundWhenDone(loc_sound)
endfunction
private function GoldBuy takes unit un returns nothing
local real x = GetUnitX(un)
local real y = GetUnitY(un)
local real z = BlzGetUnitZ(un) + 175 // Высота над крышей здания
local effect ef = AddSpecialEffect("UI\\Feedback\\GoldCredit\\GoldCredit.mdl", x, y)
local string soundpath = "Abilities\\Spells\\Items\\ResourceItems\\ReceiveGold.flac"
call PlaySnd(x, y, soundpath)
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(un), PLAYER_STATE_RESOURCE_GOLD, 200)
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(un), PLAYER_STATE_RESOURCE_LUMBER, -100000)
call BlzSetSpecialEffectZ(ef, z) // Устанавливаем высоту эффекта
call addEffectTimer(ef, 2)
endfunction
private function WoodBuy takes unit un returns nothing
local real x = GetUnitX(un)
local real y = GetUnitY(un)
local real z = BlzGetUnitZ(un) + 275 // Высота над крышей здания
local effect ef = AddSpecialEffect("war3mapImported\\NatureBlessing.mdx", x, y)
local string soundpath = "Abilities\\Spells\\Items\\ResourceItems\\BundleOfLumber.flac"
call PlaySnd(x, y, soundpath)
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(un), PLAYER_STATE_RESOURCE_GOLD, -250)
call AdjustPlayerStateSimpleBJ(GetOwningPlayer(un), PLAYER_STATE_RESOURCE_LUMBER, 50000)
call BlzSetSpecialEffectZ(ef, z) // Устанавливаем высоту эффекта
call BlzSetSpecialEffectScale(ef, 1.25)
call addEffectTimer(ef, 0.5)
endfunction
private function GoldBuyTry takes nothing returns nothing
local unit un = GetSpellAbilityUnit()
local player pl = GetOwningPlayer(un)
call IssueImmediateOrder(un, "stop")
if (GetPlayerState(pl, PLAYER_STATE_RESOURCE_LUMBER) >= 100000) then
call GoldBuy(un)
else
if(BlzGetLocale() == "ruRU") then
call DisplayTimedTextToPlayer(pl, 0, 0, 3.0, "Вам не хватает ресурсов, чтобы выполнить обмен.")
else
call DisplayTimedTextToPlayer(pl, 0, 0, 3.0, "Insufficient resources to complete the exchange.")
endif
endif
endfunction
private function WoodBuyTry takes nothing returns nothing
local unit un = GetSpellAbilityUnit()
local player pl = GetOwningPlayer(un)
call IssueImmediateOrder(un, "stop")
if (GetPlayerState(pl, PLAYER_STATE_RESOURCE_GOLD) >= 250) then
call WoodBuy(un)
else
if(BlzGetLocale() == "ruRU") then
call DisplayTimedTextToPlayer(pl, 0, 0, 3.0, "Вам не хватает ресурсов, чтобы выполнить обмен.")
else
call DisplayTimedTextToPlayer(pl, 0, 0, 3.0, "Insufficient resources to complete the exchange.")
endif
endif
endfunction
private function GoldBuyAbilityCond takes nothing returns boolean
return GetSpellAbilityId() == 'A00B'
endfunction
private function WoodBuyAbilityCond takes nothing returns boolean
return GetSpellAbilityId() == 'A02B'
endfunction
private function onInit takes nothing returns nothing
local trigger trg1 = CreateTrigger()
local trigger trg2 = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg1, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(trg1, Condition(function GoldBuyAbilityCond))
call TriggerAddAction(trg1, function GoldBuyTry)
//
call TriggerRegisterAnyUnitEventBJ(trg2, EVENT_PLAYER_UNIT_SPELL_CAST)
call TriggerAddCondition(trg2, Condition(function WoodBuyAbilityCond))
call TriggerAddAction(trg2, function WoodBuyTry)
endfunction
endlibrary
function IsAbilityLevelSwapped takes nothing returns boolean
return GetUnitAbilityLevelSwapped('A02Y', GetTriggerUnit()) == 1
endfunction
function CheckUnitType takes integer unitId returns boolean
return GetUnitTypeId(GetTriggerUnit()) == unitId
endfunction
function ChangeUnitAbilities takes integer removeAbility, integer addAbility returns nothing
call UnitRemoveAbilityBJ(removeAbility, GetTriggerUnit())
call UnitAddAbilityBJ(addAbility, GetTriggerUnit())
endfunction
function Trig_PageSystem_Change_Page_VJASS_Actions takes nothing returns nothing
local unit trgUnit = GetTriggerUnit()
local integer unitTypeId = GetUnitTypeId(trgUnit)
local boolean abilitySwapped = IsAbilityLevelSwapped()
local player udg_PS_Player
local integer udg_PS_PN
// Переключение способностей в зависимости от типа юнита
if unitTypeId == 'o000' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A02Z')
else
call ChangeUnitAbilities('A02Z', 'A02Y')
endif
elseif unitTypeId == 'o001' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A034')
else
call ChangeUnitAbilities('A034', 'A02Y')
endif
elseif unitTypeId == 'o00G' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A030')
else
call ChangeUnitAbilities('A030', 'A02Y')
endif
elseif unitTypeId == 'o007' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A033')
else
call ChangeUnitAbilities('A033', 'A02Y')
endif
elseif unitTypeId == 'o00E' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A031')
else
call ChangeUnitAbilities('A031', 'A02Y')
endif
elseif unitTypeId == 'o00F' then
if abilitySwapped then
call ChangeUnitAbilities('A02Y', 'A032')
else
call ChangeUnitAbilities('A032', 'A02Y')
endif
endif
set udg_PS_Player = GetOwningPlayer(trgUnit)
set udg_PS_PN = GetConvertedPlayerId(udg_PS_Player)
// Отключение юнитов текущей страницы
set udg_PS_Loop = udg_PS_Page_Min_Range[udg_PS_Current_Page[udg_PS_PN]]
loop
exitwhen udg_PS_Loop > udg_PS_Page_Max_Range[udg_PS_Current_Page[udg_PS_PN]]
call SetPlayerTechMaxAllowedSwap(udg_PS_Tech_Type[udg_PS_Loop], 0, udg_PS_Player)
call SetPlayerUnitAvailableBJ(udg_PS_Unit_Type[udg_PS_Loop], false, udg_PS_Player)
set udg_PS_Loop = udg_PS_Loop + 1
endloop
// Регулировка текущей страницы
if udg_PS_Current_Page[udg_PS_PN] + 1 > udg_PS_Page_Count then
set udg_PS_Current_Page[udg_PS_PN] = 1
else
set udg_PS_Current_Page[udg_PS_PN] = udg_PS_Current_Page[udg_PS_PN] + 1
endif
// Включение юнитов новой текущей страницы
set udg_PS_Loop = udg_PS_Page_Min_Range[udg_PS_Current_Page[udg_PS_PN]]
loop
exitwhen udg_PS_Loop > udg_PS_Page_Max_Range[udg_PS_Current_Page[udg_PS_PN]]
call SetPlayerTechMaxAllowedSwap(udg_PS_Tech_Type[udg_PS_Loop], 9, udg_PS_Player)
call SetPlayerUnitAvailableBJ(udg_PS_Unit_Type[udg_PS_Loop], true, udg_PS_Player)
set udg_PS_Loop = udg_PS_Loop + 1
endloop
// Обновление PlayerCurrentPage при смене страницы
set PlayerCurrentPage[udg_PS_PN] = udg_PS_Current_Page[udg_PS_PN]
// Освобождение локальных переменных
set trgUnit = null
set udg_PS_Player = null
endfunction
//===========================================================================
function InitTrig_PageSystem_Change_Page_VJASS takes nothing returns nothing
set gg_trg_PageSystem_Change_Page_VJASS = CreateTrigger()
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A02Y', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A02Z', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A034', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A031', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A032', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A030', "channel")
call TriggerRegisterCommandEvent(gg_trg_PageSystem_Change_Page_VJASS, 'A033', "channel")
call TriggerAddAction(gg_trg_PageSystem_Change_Page_VJASS, function Trig_PageSystem_Change_Page_VJASS_Actions)
endfunction
library pagesystem
globals
integer array PlayerCurrentPage
boolean array SkipPageRestore
endglobals
// Смена способностей в зависимости от типа юнита и текущей страницы
function ChangeUnitAbilitiesForPage takes unit triggerUnit, integer page returns nothing
local integer unitTypeId = GetUnitTypeId(triggerUnit)
if page == 1 then
if unitTypeId == 'o000' then
call UnitRemoveAbilityBJ('A02Z', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
elseif unitTypeId == 'o001' then
call UnitRemoveAbilityBJ('A034', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
elseif unitTypeId == 'o00G' then
call UnitRemoveAbilityBJ('A030', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
elseif unitTypeId == 'o007' then
call UnitRemoveAbilityBJ('A033', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
elseif unitTypeId == 'o00E' then
call UnitRemoveAbilityBJ('A031', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
elseif unitTypeId == 'o00F' then
call UnitRemoveAbilityBJ('A032', triggerUnit)
call UnitAddAbilityBJ('A02Y', triggerUnit)
endif
elseif page == 2 then
if unitTypeId == 'o000' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A02Z', triggerUnit)
elseif unitTypeId == 'o001' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A034', triggerUnit)
elseif unitTypeId == 'o00G' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A030', triggerUnit)
elseif unitTypeId == 'o007' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A033', triggerUnit)
elseif unitTypeId == 'o00E' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A031', triggerUnit)
elseif unitTypeId == 'o00F' then
call UnitRemoveAbilityBJ('A02Y', triggerUnit)
call UnitAddAbilityBJ('A032', triggerUnit)
endif
endif
endfunction
// Функция для отключения текущей страницы для игрока
function DisablePageForPlayer takes player PS_Player, integer currentPage returns nothing
local integer PS_PN = GetConvertedPlayerId(PS_Player)
local integer PS_Loop = udg_PS_Page_Min_Range[currentPage]
loop
exitwhen PS_Loop > udg_PS_Page_Max_Range[currentPage]
call SetPlayerTechMaxAllowedSwap(udg_PS_Tech_Type[PS_Loop], 0, PS_Player)
call SetPlayerUnitAvailableBJ(udg_PS_Unit_Type[PS_Loop], false, PS_Player)
set PS_Loop = PS_Loop + 1
endloop
endfunction
// Функция для включения новой текущей страницы для игрока
function EnablePageForPlayer takes player PS_Player, integer currentPage returns nothing
local integer PS_PN = GetConvertedPlayerId(PS_Player)
local integer PS_Loop = udg_PS_Page_Min_Range[currentPage]
loop
exitwhen PS_Loop > udg_PS_Page_Max_Range[currentPage]
call SetPlayerTechMaxAllowedSwap(udg_PS_Tech_Type[PS_Loop], 9, PS_Player)
call SetPlayerUnitAvailableBJ(udg_PS_Unit_Type[PS_Loop], true, PS_Player)
set PS_Loop = PS_Loop + 1
endloop
endfunction
function PageActionCondition takes nothing returns boolean
return GetUnitState(MainBuildings[GetPlayerId(GetTriggerPlayer())], UNIT_STATE_LIFE) > 0
endfunction
// Функция для перехода на страницу 1
function PageNum1 takes nothing returns nothing
local player pl = GetTriggerPlayer()
local integer playerId = GetConvertedPlayerId(pl)
local unit trgUnit = MainBuildings[playerId-1]
set SkipPageRestore[playerId] = true
call DisablePageForPlayer(pl, udg_PS_Current_Page[playerId])
set udg_PS_Current_Page[playerId] = 1
call EnablePageForPlayer(pl, 1)
call ChangeUnitAbilitiesForPage(trgUnit, 1)
set trgUnit = null
endfunction
// Функция для перехода на страницу 2
function PageNum2 takes nothing returns nothing
local player pl = GetTriggerPlayer()
local integer playerId = GetConvertedPlayerId(pl)
local unit trgUnit = MainBuildings[playerId-1]
set SkipPageRestore[playerId] = true
call DisablePageForPlayer(pl, udg_PS_Current_Page[playerId])
set udg_PS_Current_Page[playerId] = 2
call EnablePageForPlayer(pl, 2)
call ChangeUnitAbilitiesForPage(trgUnit, 2)
set trgUnit = null
endfunction
// Проверка, является ли выбранный юнит основным зданием
function IsMainBuilding takes unit selectedUnit returns boolean
local integer i = 0
local player owningPlayer = GetOwningPlayer(selectedUnit)
loop
exitwhen i >= GetBJMaxPlayers()
if selectedUnit == MainBuildings[i] then
return true
endif
set i = i + 1
endloop
return false
endfunction
// Триггер для обработки выбора юнита и перехода на соответствующую страницу
function OnUnitSelected takes nothing returns nothing
local unit selectedUnit = GetTriggerUnit()
local player selectingPlayer = GetOwningPlayer(selectedUnit)
local integer unitTypeId = GetUnitTypeId(selectedUnit)
local integer playerId = GetConvertedPlayerId(selectingPlayer)
// Проверяем, является ли выбранный юнит o009 или o00H
if unitTypeId == 'o009' or unitTypeId == 'o00H' then
// Если текущая страница 2, переходим на страницу 1
if udg_PS_Current_Page[playerId] == 2 then
// Запоминаем текущую страницу для игрока перед переходом
set PlayerCurrentPage[playerId] = 2
call DisablePageForPlayer(selectingPlayer, udg_PS_Current_Page[playerId])
set udg_PS_Current_Page[playerId] = 1
call EnablePageForPlayer(selectingPlayer, 1)
call ChangeUnitAbilitiesForPage(selectedUnit, 1)
endif
// Проверяем, является ли выбранный юнит основным зданием
elseif IsMainBuilding(selectedUnit) then
// Восстанавливаем страницу для основного здания
if PlayerCurrentPage[playerId] == 2 and not SkipPageRestore[playerId] then
call DisablePageForPlayer(selectingPlayer, udg_PS_Current_Page[playerId])
set udg_PS_Current_Page[playerId] = 2
call EnablePageForPlayer(selectingPlayer, 2)
call ChangeUnitAbilitiesForPage(selectedUnit, 2)
else
// Если игрок ранее находился на другой странице, сохраняем текущую страницу
set PlayerCurrentPage[playerId] = udg_PS_Current_Page[playerId]
endif
endif
// Освобождаем локальные переменные
set selectedUnit = null
set selectingPlayer = null
set SkipPageRestore[playerId] = false
endfunction
// Инициализация триггера для выбора юнита
function InitTrig_OnUnitSelected takes nothing returns nothing
local trigger trg = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(trg, EVENT_PLAYER_UNIT_SELECTED)
call TriggerAddAction(trg, function OnUnitSelected)
set trg = null
endfunction
endlibrary
library HeroButtonSystem initializer onInit uses HeroButtonLib, pagesystem
function ButtonPush3 takes nothing returns nothing
local player pl = GetTriggerPlayer()
call BJDebugMsg("Button 3 Pushed")
endfunction
struct HBS extends array
static HeroButton array Button
static method onInit takes nothing returns nothing
local string IconPath1 = "ReplaceableTextures\\CommandButtons\\BTNHumanLumberMill.blp"
local string IconPath2 = "ReplaceableTextures\\CommandButtons\\BTNEngineeringUpgrade.blp"
local string IconPath3 = "ReplaceableTextures\\CommandButtons\\BTNArcher.blp"
local string Tooltip_basic1
local string Tooltip_basic2
local string Tooltip_basic3
//
if (BlzGetLocale() == "ruRU") then
set Tooltip_basic1 = "Главное здание"
set Tooltip_basic2 = "Центр исследований"
set Tooltip_basic3 = "Стать чем-то"
else
set Tooltip_basic1 = "Main building"
set Tooltip_basic2 = "Research Center"
set Tooltip_basic3 = "Become smth"
endif
//
set HBS.Button[0] = HeroButton.Create(Tooltip_basic1, IconPath1)
set HBS.Button[1] = HeroButton.Create(Tooltip_basic2, IconPath2)
set HBS.Button[2] = HeroButton.Create(Tooltip_basic3, IconPath3)
//
call HBS.Button[0].AddAction(function PageNum1)
call HBS.Button[1].AddAction(function PageNum2)
//
call HBS.Button[0].AddCondition(Condition(function PageActionCondition))
call HBS.Button[1].AddCondition(Condition(function PageActionCondition))
call HBS.Button[2].AddCondition(Condition(function PageActionCondition))
//
//call HBS.Button[2].AddAction(function ButtonPush3)
call HBS.Button[0].hide()
call HBS.Button[1].hide()
call HBS.Button[2].hide()
endmethod
endstruct
endlibrary
library ClassMainBuilding uses HeroButtonSystem, MarketSystem, MachinerySystem, numjass
globals
// Глобальные переменные для хранения основных зданий, их счетчика и триггера смерти основного здания
unit array MainBuildings
integer MainBuildings_Counter
trigger MainBuilding_death
endglobals
// Функция для нахождения ближайшей лесопилки к заданной точке
function FindNearestMillAtLoc takes location Point returns unit
local integer i = 0
local real min_dist = 999999.0
local integer min_i = -1
local real x0 = GetLocationX(Point)
local real y0 = GetLocationY(Point)
local real x
local real y
local real dist
// Ищем все расстояния
loop
exitwhen i == bj_MAX_PLAYERS
if MainBuildings[i] != null then
set x = GetUnitX(MainBuildings[i])
set y = GetUnitY(MainBuildings[i])
set dist = math.rhoL2(x, y, x0, y0)
if dist < min_dist then
set min_dist = dist
set min_i = i
endif
endif
set i = i + 1
endloop
// Возвращаем ближайшую лесопилку
if min_i != -1 then
return MainBuildings[min_i]
else
return null
endif
endfunction
struct MB
static QR MainLocs
static method RemoveFrameButtonsPlayer takes player pl returns nothing
if (GetLocalPlayer() == pl) then
call BlzFrameSetVisible(HBS.Button[0].button, false)
call BlzFrameSetVisible(HBS.Button[1].button, false)
call BlzFrameSetVisible(HBS.Button[2].button, false)
endif
endmethod
// Метод для обработки смерти основного здания
static method MainBuildingDeath takes nothing returns nothing
local unit un = GetTriggerUnit()
local player pl = GetOwningPlayer(un)
local integer plnum = GetPlayerId(pl)
local string Text
set MainBuildings[plnum] = null
if (BlzGetLocale() == "ruRU") then
set Text = " не выдержал конкуренции среди лесорубов."
else
set Text = " couldn't compete among the lumberjacks."
endif
// Удаляем игрока из игры, если он был в списке игроков
if(IsPlayerInForce(pl, udg_PlayersInGame)) then
call ForceRemovePlayer(udg_PlayersInGame, pl)
endif
// Отображаем сообщение и создаем эффект тумана войны
call DisplayTextToForce(GetPlayersAll(), (GetPlayerName(pl) + Text))
call CreateFogModifierRectBJ(true, pl, FOG_OF_WAR_VISIBLE, GetEntireMapRect())
call FogModifierStart(GetLastCreatedFogModifier())
//
call RemoveFrameButtonsPlayer(pl)
// Удаление рынка и техники при смерти основного здания
call RemoveUnit(MRTS.Market[plnum])
set MRTS.Market[plnum] = null
call RemoveUnit(MACH.Machinery[plnum])
set MACH.Machinery[plnum] = null
endmethod
// Метод для добавления основного здания в массив
static method AddMainBuilding takes unit un returns nothing
local integer plnum = GetPlayerId(GetOwningPlayer(un))
set MainBuildings[plnum] = un
call TriggerRegisterUnitEvent(MainBuilding_death, un, EVENT_UNIT_DEATH)
endmethod
// Метод для выбора основного здания для игрока
static method SelectForTriggeringPlayer takes nothing returns nothing
local player pl = GetTriggerPlayer()
if(GetLocalPlayer() == pl)then
call ClearSelection()
call SelectUnit(MainBuildings[GetPlayerId(pl)], true)
endif
endmethod
// Метод для обработки улучшения основного здания
private static method UpgradeAction takes nothing returns nothing
local unit un = GetTriggerUnit()
local player pl = GetOwningPlayer(un)
// Обновляем иконку и подсказку для кнопки
call HBS.Button[0].SetIconForPlayer(pl, BlzGetAbilityIcon(GetUnitTypeId(un)))
call HBS.Button[0].SetTTTForPlayer(pl, GetUnitName(un))
// Если юнит улучшен до 'o00E', создается рынок
if(GetUnitTypeId(un) == 'o00E')then
call MRTS.MarketCreateForUnit(un)
call HBS.Button[2].ShowForPlayer(pl)
call HBS.Button[2].SetTTTForPlayer(pl, GetUnitName(MRTS.Market[GetPlayerId(pl)]))
call HBS.Button[2].SetIconForPlayer(pl, BlzGetAbilityIcon(GetUnitTypeId(MRTS.Market[GetPlayerId(pl)])))
call HBS.Button[2].AddAction(function MRTS.SelectForTriggeringPlayer)
// Если юнит улучшен до 'o007', создается техника
elseif GetUnitTypeId(un) == 'o007' then
call MACH.MachineryCreateForUnit(un)
call HBS.Button[2].ShowForPlayer(pl)
call HBS.Button[2].SetTTTForPlayer(pl, GetUnitName(MACH.Machinery[GetPlayerId(pl)]))
call HBS.Button[2].SetIconForPlayer(pl, BlzGetAbilityIcon(GetUnitTypeId(MACH.Machinery[GetPlayerId(pl)])))
call HBS.Button[2].AddAction(function MACH.SelectForTriggeringPlayer)
endif
endmethod
// Метод для создания начального здания для игрока
static method CreateStartingBuilding takes player pl returns nothing
local location loc = MB.MainLocs.TakeLocation()
local trigger upg_trg = CreateTrigger()
local unit un = CreateUnitAtLoc(pl, 'o000', loc, bj_UNIT_FACING)
call PanCameraToTimedLocForPlayer(pl, loc, 0)
call MB.AddMainBuilding(un)
call HBS.Button[0].AddAction(function MB.SelectForTriggeringPlayer)
call HBS.Button[1].AddAction(function MB.SelectForTriggeringPlayer)
call HBS.Button[0].SetTTTForPlayer(pl, GetUnitName(un))
call HBS.Button[0].SetIconForPlayer(pl, BlzGetAbilityIcon(GetUnitTypeId(un)))
call HBS.Button[0].ShowForPlayer(pl)
call HBS.Button[1].ShowForPlayer(pl)
// Отключение интерфейса способности аура восстановления при создании начальной лесопилки
call BlzUnitDisableAbility(un, 'A037', false, true)
// Регистрируем событие улучшения юнита
call TriggerRegisterUnitEvent(upg_trg, un, EVENT_UNIT_UPGRADE_FINISH)
call TriggerAddAction(upg_trg, function MB.UpgradeAction)
// Деструкция
call RemoveLocation(loc)
endmethod
// Метод для создания начальных зданий для всех игроков
static method CreateStartingBuildings takes nothing returns nothing
local nj_I1D nums_pl = nj.arrange(1,1,GetBJMaxPlayers())
local integer mpl = GetBJMaxPlayers()
local integer i = 0
call nums_pl.shuffle()
loop
exitwhen( i == mpl )
if(BlzForceHasPlayer(udg_PlayersInGame, Player(i)))then
call CreateStartingBuilding(Player(i))
endif
set i = i + 1
endloop
call nums_pl.destroy()
endmethod
// Метод для инициализации структуры и минимального расстояния между объектами
private static method onInit takes nothing returns nothing
local integer mpl = GetBJMaxPlayers()
local integer i = 0
loop
exitwhen(i == mpl)
set MainBuildings[i] = null
set i = i + 1
endloop
set MainLocs = QR.create(1536.0, 10, gg_rct_DemonPortalSpawn)
// Создаем триггер для смерти основного здания
set MainBuilding_death = CreateTrigger()
call TriggerAddAction(MainBuilding_death, function thistype.MainBuildingDeath)
endmethod
endstruct
endlibrary